diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/Configure.help linux-2.4.20-wolk4.7-fullkernel/Documentation/Configure.help --- linux-2.4.20-wolk4.6-fullkernel/Documentation/Configure.help 2003-08-05 22:23:15.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/Configure.help 2003-08-17 21:31:47.000000000 +0200 @@ -198,6 +198,29 @@ CONFIG_RSBAC_SECOFF_UID boot the defaults are set and saved, and changes to this option will not have any effect. +Delayed init for initial ramdisk +CONFIG_RSBAC_INIT_DELAY + This option allows to delay RSBAC initialization until the first mount + of a real disk partition (major number > 1). It is intended to be used + with initial ramdisks, which mount the final root partition during + boot. + + You can trigger initialization at a specific partition mount with the + kernel parameter rsbac_delayed_root=major:minor. If the given partition + is not mounted and thus RSBAC not initialized, you can also call the + rsbac_init() system call at any time, e.g. with the rsbac_init admin + tool. + + To disable delayed init, you have to use the kernel parameter + rsbac_no_delay_init. This will force the standard initialization after + the first root mount. If this is your initrd, the RSBAC setup in there + will be used instead of the configuration on your real root device. + + Warning: The delayed init option requires the RSBAC init code to be + kept in memory all the time, which increases your kernel + memory usage by a few 10s of KB. It should only be used in + combination with an initial ramdisk. + RSBAC Maintenance Kernel (Use with care!) CONFIG_RSBAC_MAINT A maintenance kernel is useful, if the system got unaccessible, @@ -325,6 +348,9 @@ CONFIG_RSBAC_MAC To write to a resource, it must be at least as confidential as the user, and its category set must be a superset of the user's. + Please read the extended MAC model documentation in + Documentation/rsbac/html/models.htm. + MAC inherit as default CONFIG_RSBAC_MAC_DEF_INHERIT If enabled, the inheritable attributes security_level and @@ -380,6 +406,37 @@ CONFIG_RSBAC_MAC_LIGHT 2. Allow R_MOUNT and R_UMOUNT to ANY user (only Administrator in base MAC version). +Give trusted processes full read access +CONFIG_RSBAC_MAC_TRUSTED_READ + Normally, a mac_trusted process may only violate *-property, i.e., it + may write to any level within its owner's level range from + min_security_level to security_level, regardless of its current level + and the max_read boundary. This makes a user's trusted flag equivalent + to the combination of write_up and write_down flag. + + With this option turned on, a trusted process may also read from any + such level despite its current level and the min_write boundary. This + adds the meaning of the read_up flag to the trusted flag. + + Please note that the mac_auto privilege with automatic current level + and read/write boundary adjustment as well as the object mac_shared + flag are always tried before trusted, write_up, write_down and read_up. + +Reset current level on each execute +RSBAC_MAC_RESET_CURR + If enabled, the current process level is reset to the user's initial + level on every execute. + +Log all automatic changes to current level +CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + If both the effective mac_auto flag at an executable and the + mac_allow_auto flag at the user executing it are set, current levels + may be automatically adjusted to allow access, where it would otherwise + be denied. + + This option logs each such automatic change to the process current + level, because it means a change to the current access rights. + MAC network device protection CONFIG_RSBAC_MAC_NET_DEV_PROT If on, protect network devices: Only System Administrators may configure @@ -393,6 +450,20 @@ CONFIG_RSBAC_MAC_NET_OBJ_PROT The default attribute values are derived from those of the matching network template. +MAC number of process lists +CONFIG_RSBAC_MAC_NR_P_LISTS + When using MAC model, every process in the system will get individual + attributes set. This means that with many active processes, the list + lookups will become slower. + + To speed them up, RSBAC uses a hash table to split the MAC process + attribute lists into several shorter ones. This option sets the number + of these lists. + + In most cases, the default of 4 will be sufficient. However, if you + plan to have very many processes, a higher value will reduce lookup + time at the cost of additional list headers. + RSBAC support for FC policy CONFIG_RSBAC_FC The Functional Control classifies users as general, system @@ -437,7 +508,7 @@ CONFIG_RSBAC_SIM SIM protection for AUTH module CONFIG_RSBAC_SIM_AUTH_PROT - This option makes FC care for AUTH module settings, e.g. attributes + This option makes SIM care for AUTH module settings, e.g. attributes auth_may_setuid, auth_may_set_cap and the kernel-only pseudo attributes auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. Those settings are treated like SIM settings. @@ -529,37 +600,64 @@ CONFIG_RSBAC_MS_PERSIST Using this option can reduce the amount of scanning, but it cannot protect against file modifications while another kernel is booted. -Export do_scan for external scanner modules -CONFIG_RSBAC_MS_EXTERNAL - With this option, the rsbac_ms_do_scan variable, which points to the - file scanning engine function, is exported to kernel modules. It can - thus be changed to point to another function, e.g. a scanner module - provided by an antivirus vendor. - -Disable internal do_scan -CONFIG_RSBAC_MS_NO_INTERNAL - Use this to disable the file scanning engine prototype provided by - RSBAC. You need to point the rsbac_ms_do_scan variable to another - scanning funtion to get any scanning functionality then. - - Even without a scanning engine, previous scanning results are always - respected during their lifetime. - -Also check read-open and read-write-open -CONFIG_RSBAC_MS_READ - Also check on read-open and read-write-open, e.g. for macro viruses - or fileservers. - -Also do socket scan -CONFIG_RSBAC_MS_SOCK - Also check read on TCP and UDP connections. Returns error code -1023 - (-RSBAC_EMALWAREDETECTED) for all reads as soon as a detection is - triggered, unless process/program is ms_sock_trusted == MS_full for - this protocol. The original return value can still be recovered by - rsbac_ms_get_copied() system call, if ms_sock_trusted is MS_active. - If not, the buffer has been cleared anyway. :) - - This option is independent from RSBAC net support. +Propagate ms-trusted +CONFIG_RSBAC_MS_PROP_TRUSTED + If enabled, ms_trusted is propagated to all subprocesses and other + programs. + +External scanner module +CONFIG_RSBAC_MS_EXT + This switch disables the internal scanner prototype, enables the + plugin interface for scanner modules and lets you choose direct + support for some professional scanning engines. + +Support for F-Protd +CONFIG_RSBAC_MS_EXT_FPROTD + Use this switch to get direct support for the F-Prot daemon as + scanning engine. The daemon must have full read access to all files + and directories and it must be marked as ms_trusted for reading to + avoid scanning loops. + + When the daemon is up and running, you must enable the scanning + mechanism as root or secoff with + echo level inc > /proc/rsbac-info/ms_level + + Repeat this after each signature update. + + Warning: If the scanner fails, there will be no access to any file for + which there is no cached positive scanning result! + +F-Protd command line switches +CONFIG_RSBAC_MS_EXT_FPROTD_SW + Specify the command line switches passed to the daemon with the scan + request. Default is "-ai%20-old". + +Support for clamd +CONFIG_RSBAC_MS_EXT_CLAMD + Use this switch to get direct support for the Clam daemon as + scanning engine. The daemon must have full read access to all files + and directories, it must be marked as ms_trusted for reading to + avoid scanning loops and it must provide its network interface on + the localhost port specified below. + + When the daemon is up and running, you must enable the scanning + mechanism as root or secoff with + echo level inc > /proc/rsbac-info/ms_level + + Repeat this after each signature update. + + Warning: If the scanner fails, there will be no access to any file for + which there is no cached positive scanning result! + +Clamd port +CONFIG_RSBAC_MS_EXT_CLAMD_PORT + Specify the localhost port clamd is listening at. Default is 3310. + +Clamd scan action +CONFIG_RSBAC_MS_EXT_CLAMD_ACTION + Set the scanning action requested from clamd. Default is SCAN, other + values are RAWSCAN and CONTSCAN. Please read the clamd man page for + details. MS protection for AUTH module CONFIG_RSBAC_MS_AUTH_PROT @@ -650,7 +748,7 @@ CONFIG_RSBAC_RC_GEN_PROT RC network device protection CONFIG_RSBAC_RC_NET_DEV_PROT - If on, protect network devices based in RC NETDEV type compatibilities. + If on, protect network devices based on RC NETDEV type compatibilities. RC network object protection CONFIG_RSBAC_RC_NET_OBJ_PROT @@ -663,6 +761,20 @@ CONFIG_RSBAC_RC_NET_OBJ_PROT Templates themselves are protected through their own template type in attribute rc_type_nt and the nettemp type compatibility settings. +RC number of process lists +CONFIG_RSBAC_RC_NR_P_LISTS + When using RC model, every process in the system will get individual + attributes set. This means that with many active processes, the list + lookups will become slower. + + To speed them up, RSBAC uses a hash table to split the RC process + attribute lists into several shorter ones. This option sets the number + of these lists. + + In most cases, the default of 4 will be sufficient. However, if you + plan to have very many processes, a higher value will reduce lookup + time at the cost of additional list headers. + RSBAC support for AUTH policy CONFIG_RSBAC_AUTH This module can be seen as a support module for all others. It @@ -702,6 +814,18 @@ CONFIG_RSBAC_AUTH_AUTH_PROT See AUTH model description for details. +AUTH support for effective and fs owner control +CONFIG_RSBAC_AUTH_DAC_OWNER + If enabled, AUTH also controls the requests CHANGE_DAC_EFF_OWNER + (change process effective owner) and CHANGE_DAC_FS_OWNER (change + process filesystem owner) on process targets. Changes to these Linux + DAC model owner settings do not affect RSBAC, so this option is off + by default. + + This option also requires the 'Control DAC process owner (seteuid, + setfsuid)' option from the 'Other options', which enables the requests + mentioned above. + RSBAC support for ACL policy CONFIG_RSBAC_ACL This turns on the Access Control List module. ACLs are kept on all @@ -788,6 +912,22 @@ CONFIG_RSBAC_CAP If softmode is enabled and turned on, only the minimum sets are applied. +Support CAP process hiding +CONFIG_RSBAC_CAP_PROC_HIDE + If enabled, you can hide the process properties shown in /proc from + other users, e.g. command line and current state. The hiding level is + set with the cap_process_hiding process attribute. There are three + possible values: + 0 / off: no hiding. + 1 / from other users: only processes running for the same user, a CAP + security officer or a CAP system admin may read the properties. + 2 / full: only this process and CAP security officers may read the + properties. + + The kernel command line switch rsbac_cap_process_hiding changes the + default value from 0 to 1. Thus, every normal user can only see her + own process properties. + CAP protection for AUTH module CONFIG_RSBAC_CAP_AUTH_PROT This option makes CAP care for AUTH module settings, e.g. attributes @@ -838,6 +978,30 @@ CONFIG_RSBAC_JAIL_NET_DEV_PROT Only with this option enabled, the JAIL module prevents network device configuration from within a jail. Recommended. +RSBAC support for Linux Resources (RES) policy +CONFIG_RSBAC_RES + The Linux Resources (RES) module allows to set minimum and maximum + Linux resource sets for single users and programs. These boundaries + are applied at CHANGE_OWNER on processes (setuid) and EXECUTE. + + Minimum settings have precedence over maximums, and program settings + have precedence over user settings. + + Default values for all users can be set at user RSBAC_ALL_USER with + uid 4294967292 ((rsbac_uid_t) -4). + + If softmode is enabled and turned on, only the minimum sets are + applied. + +RES protection for AUTH module +CONFIG_RSBAC_RES_AUTH_PROT + This option makes RES care for AUTH module settings, e.g. attributes + auth_may_setuid, auth_may_set_cap and the kernel-only pseudo attributes + auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. Those settings + are protected by the res_roles admin (read) and security officer (rw). + + See AUTH model description for AUTH details. + RSBAC policies switchable CONFIG_RSBAC_SWITCH @@ -901,6 +1065,8 @@ CONFIG_RSBAC_SOFTMODE_IND where is the module short name in capitals, e.g. RC, and is 1 (on) or 0 (off). + If policy switching is enabled, you can also use sys_rsbac_switch, e.g. + via switch_module command line tool. Allow disabling of Linux filesystem access control (DANGEROUS!) CONFIG_RSBAC_ALLOW_DAC_DISABLE @@ -969,7 +1135,7 @@ CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT Use this option, if you cannot access your network files properly, and keep it off otherwise. - + RSBAC check sys_syslog CONFIG_RSBAC_SYSLOG If enabled, the syscall sys_syslog() for system log is also checked, @@ -978,7 +1144,8 @@ CONFIG_RSBAC_SYSLOG RSBAC symlink redirection CONFIG_RSBAC_SYM_REDIR This feature optionally changes the contents of a symlink, based on - the owner ID or the RC role ID of the process accessing it. + the owner ID, the current MAC security level or the current RC role ID + of the process accessing it. Note: For technical reasons, all numeric characters at the end of the original symlink contents will be replaced, not appended to. @@ -1010,6 +1177,25 @@ CONFIG_RSBAC_SYM_REDIR_UID accesses show /tmpdir/tmp400, etc. It is of course advisable to protect the individual dirs against root. +Add MAC current security level +CONFIG_RSBAC_SYM_REDIR_MAC + With this option enabled, every read from a symlink, which has the + symlink_add_mac_level flag set, gets the calling process's current MAC + security level added in decimal notation. + + It can be used to e.g. provide separate /tmp dirs for all MAC levels + and thus avoid unwanted flow of information. + See 'Add user ID number' help to get an idea of how to do this. + +Also add MAC current category vector +CONFIG_RSBAC_SYM_REDIR_MAC_CAT + If enabled, the redirected symlink contents will not only contain the + process current MAC security level, but also its current category set + as the usual string of 0 and 1, separated by a colon. + + Warning: This will result in more possible values than your filesystem + can handle names and inodes, so please be careful. + Add RC role number CONFIG_RSBAC_SYM_REDIR_RC With this option enabled, every read from a symlink, which has the @@ -1017,7 +1203,7 @@ CONFIG_RSBAC_SYM_REDIR_RC role ID added in decimal notation. It can be used to e.g. provide individual /tmp dirs for all roles. - See 'Add user ID number' help to get an idea how to do this. + See 'Add user ID number' help to get an idea of how to do this. X support (normal user MODIFY_PERM access to ST_ioports) CONFIG_RSBAC_USER_MOD_IOPERM @@ -1083,6 +1269,15 @@ CONFIG_RSBAC_RMSG_NOSYSLOG parameter rsbac_nosyslog or via /proc/rsbac-info/debug. Useful for initial configuration on system installation. +Make RSBAC data files visible +CONFIG_RSBAC_DAT_VISIBLE + By default, the rsbac.dat directories containing the list data backups + are unreadable for any user. Unfortunately, some programs must be able + to read all directories, e.g. the quota tools. + + This option enables read and status access to the rsbac.dat + directories, but the files themselves are kept unreadable. + RSBAC extra statistics CONFIG_RSBAC_XSTATS If enabled, extended RSBAC statistics are collected. Currently these @@ -1113,6 +1308,16 @@ CONFIG_RSBAC_IPC_SEM denial of service attacks. Turn on for special needs, keep off otherwise. +Control DAC process owner (seteuid, setfsuid) +CONFIG_RSBAC_DAC_OWNER + Usually, only set*uid calls, which affect the real user ID used for + RSBAC decisions, issue a decision request CHANGE_OWNER for processes. + With this option, changes to the effective (CHANGE_DAC_EFF_OWNER) and + the filesystem (CHANGE_DAC_FS_OWNER) owner are also controlled. + + Please also see AUTH option 'AUTH support for effective and fs owner + control'. + Prompt for development and/or incomplete code/drivers CONFIG_EXPERIMENTAL @@ -3224,196 +3429,6 @@ CONFIG_PARIDE_ON26 called on26.o. You must also have a high-level driver for the type of device that you want to support. -EVMS Kernel Runtime -CONFIG_EVMS - EVMS runtime driver. This is a plugin-based framework for volume - management, and combines support for partitioning, software RAID, - LVM, and more into a single interface. - - User-space tools are required to perform administration of EVMS logical - volumes. Please visit for - more details on downloading and installing these tools. - - This driver is also available as a pair of modules called evms.o and - evms_passthru.o ( = code which can be inserted and removed from the - running kernel whenever you want). If you want to compile it as a module, - say M here and read . - -EVMS Local Device Manager Plugin -CONFIG_EVMS_LOCAL_DEV_MGR - Support for local IDE and SCSI devices. This plugin is required if EVMS - support is selected. - - This plugin is also available as a kernel module called ldev_mgr.o. - -EVMS DOS Partition Manager Plugin -CONFIG_EVMS_DOS_SEGMENT_MGR - Support for recognizing all partitions using the ever-popular DOS - partitioning scheme (MBRs & EBRs). 99% of the time you will need - this plugin to do anything useful with EVMS. - - This plugin also contains support for recognizing BSD disklabels, - UNIXWARE partitions, Solaris-X86 partitions, and OS/2 DLAT entries. - - This plugin is also available as a kernel module called dos_part.o. - -EVMS GPT Partition Manager Plugin -CONFIG_EVMS_GPT_SEGMENT_MGR - Support for recognizing all partitions using the new EFI GUID partitioning - scheme that is used by IA-64 machines. You should only need to enable this - plugin if you are running Linux on an IA-64 machine. All other architectures - can say 'N' here. - - This plugin is also available as a kernel module called gpt_part.o - -EVMS S/390 Partition Manager Plugin -CONFIG_EVMS_S390_SEGMENT_MGR - Support for recognizing all partitions created on S/390 machines. This - plugin recognizes CDL, LDL, and CMS partition formats. You should only need - to enable this plugin if you are running Linux on an S/390. All other - architectures can say 'N' here. - - This plugin is also available as a kernel module called s390_part.o - -EVMS SnapShot Feature Plugin -CONFIG_EVMS_SNAPSHOT - This feature plugin lets you create a snapshot of any volume - under EVMS control using any other device under under EVMS - control as the target for the snapshot volume. - - This plugin is also available as a kernel module called snapshot.o. - -EVMS DriveLink Feature Plugin -CONFIG_EVMS_DRIVELINK - This feature plugin lets you combine multiple devices into a - single virtual block device. The size of the virtual block - device is approximately equal to the sum of all its components. - It currently supports combining up to 60 devices (partitions, - disks, or logical volumes). - - This plugin is also available as a kernel module called evms_drivelink.o. - -EVMS Bad Block Relocation (BBR) Feature -CONFIG_EVMS_BBR - BBR is designed to remap I/O write failures to another safe - location on disk. Note that most disk drives have BBR built - into them, so software BBR will only be activated when all - hardware BBR replacement sectors have been used. - - This plugin is also available as a kernel module called evms_bbr.o. - -EVMS Linux LVM Plugin -CONFIG_EVMS_LVM - The LVM plugin is responsible for providing compatibility with the Linux - LVM. This plugin recognizes disks and partitions that are LVM physical - volumes (PVs), and assembles the appropriate volume groups (VGs). LVM - logical volumes (LVs) are exported as EVMS volumes with full read/write - support. In addition, support for striped and snapshotted volumes is - included. The corresponding EVMS Engine plugin must also be installed in - order to perform any administration of LVM VGs and LVs. - - This plugin is also available as a kernel module called lvm_vge.o. - -EVMS MD Plugin -CONFIG_EVMS_MD - The MD plugin is responsible for providing compatibility with the Linux - Software RAID driver (MD). It allows several devices to be combined into - one logical device. This can be used to simply append one disk or - partition to another, or to combine several redundant disks into a - RAID 1/4/5 device so as to provide protection against hard disk failures. - - This plugin is also available as a kernel module called md_core.o. - -EVMS MD RAID-Linear Plugin -CONFIG_EVMS_MD_LINEAR - The RAID-Linear personality combines disks and/or partitions simply by - appending one to the other. - - This plugin is also available as a kernel module called md_linear.o. - -EVMS MD RAID-0 Plugin -CONFIG_EVMS_MD_RAID0 - The RAID-0 personality combines disks and/or partitions into one - logical device using striping. This method writes data evenly across - all members in the device in order to increase the throughput rate if - each member resides on a distinct disk. - - This plugin is also available as a kernel module called md_raid0.o. - -EVMS MD RAID-1 Plugin -CONFIG_EVMS_MD_RAID1 - The RAID-1 personality implements mirroring, in which a logical device - consists of several disks that are exact copies of each other. In the - event of a mirror failure, the RAID-1 personality will continue to use - the remaining mirrors in the set, providing an error free device to the - higher levels of the kernel. In a set with N drives, the available space - is the capacity of a single drive, and the set protects against the - failure of N-1 drives. - - This plugin is also available as a kernel module called md_raid1.o. - -EVMS MD RAID-4/RAID-5 Plugin -CONFIG_EVMS_MD_RAID5 - A RAID-5 set of N drives with a capacity of C MB per drive provides - the capacity of C * (N-1) MB, and protects against a failure of a - single drive. For a given sector (row) number, (N-1) drives contain - data sectors, and one drive contains the parity protection. For a - RAID-4 set, the parity blocks are present on a single drive, while - a RAID-5 set distributes the parity across all drives in one of the - available parity distribution methods. - - This plugin is also available as a kernel module called md_raid5.o. - -EVMS AIX LVM Plugin -CONFIG_EVMS_AIX - The AIX LVM plugin is responsible for providing compatibility with the - AIX LVM. This plugin recognizes disks and partitions that are AIX disks, - and assembles the appropriate volume groups. AIX logical volumes are - exported as EVMS volumes with full read/write support. In addition, - support for striped volumes is included, and support for mirroring is - under development. - - You should only need to select this option if you are running on a PPC - machine and want to access AIX LVM volumes. The user-space plugin for - AIX will be available in the future. - - This plugin is also available as a kernel module called AIXlvm_vge.o. - -EVMS OS/2 LVM Plugin -CONFIG_EVMS_OS2 - Support for recognizing the type 0x35 partitions that later versions - of OS/2 use in its Logical Volume Manager. Provides binary - compatibility and includes Drive Linking and Bad Block Relocation - emulation. The user-space plugin for OS/2 will be available in the future. - - This plugin is also available as a kernel module called os2lvm_vge.o. - -EVMS Clustering Plugin -CONFIG_EVMS_ECR - - The EVMS Clustering Plugin is still under design and development. - Best to just say 'n' here. - - This plugin is available as a kernel module called evms_ecr.o. - -EVMS Debug Level -CONFIG_EVMS_INFO_CRITICAL - Set the level for kernel messages from EVMS. Each level on the list - produces message for that level and all levels above it. Thus, level - "Critical" only logs the most critical messages (and thus the fewest), - whereas level "Everything" produces more information that will probably - ever be useful. Level "Default" is a good starting point. Level "Debug" - is good if you are having problems with EVMS and want more basic info - on what's going on during the volume discovery process. - - EVMS also supports a boot-time kernel parameter to set the info level. - To use this method, specify "evms_info_level=5" at boot time, or add the - line "append = "evms_info_level=5"" to your lilo.conf file (replacing 5 - with your desired info level). See include/linux/evms/evms.h for the - numerical definitions of the info levels. To use this boot-time parameter, - the EVMS core driver must be statically built into the kernel (not as a - module). - Logical Volume Manager (LVM) support CONFIG_BLK_DEV_LVM This driver lets you combine several hard disks, hard disk @@ -6423,8 +6438,6 @@ CONFIG_SCHED_SERVER max_sleep_avg = 2 * HZ; starvation_limit = 2 * HZ; - vm.bdflush = 50 500 0 0 500 3000 80 50 0 (if HZ == 100) - If unsure or you don't select this, the Server Scheduler will be used. If you select none of the Scheduler Tweaks, the Server Scheduler will be used. @@ -6449,6 +6462,8 @@ CONFIG_SCHED_DESKTOP max_sleep_avg = 2 * HZ; starvation_limit = 2 * HZ; + vm.bdflush = 50 500 0 0 500 3000 80 50 0 (if HZ == 100) + vm.bdflush = 30 500 0 0 500 3000 80 30 0 (if HZ == 100) If unsure or you don't select this, the Server Scheduler will @@ -11430,11 +11445,16 @@ CONFIG_BONDING This is similar to the EQL driver, but it merges Ethernet segments instead of serial lines. + Informations on how to set up and use this can be found in + + If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read . The module will be called bonding.o. + If unsure, say N. + Intermediate queueing device support CONFIG_IMQ The imq device(s) is used as placeholder for QoS queueing disciplines. @@ -11449,6 +11469,11 @@ CONFIG_IMQ say M here and read . The module will be called imq.o + Informations on how to set up and use this can be found at + . + + If unsure, say N. + SLIP (serial line) support CONFIG_SLIP Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to @@ -12273,11 +12298,15 @@ CONFIG_EQUALIZER section 6.2 of the NET-3-HOWTO, available from . + Informations on how to set up and use this can be found in + + This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called eql.o. If you want to compile it as a - module, say M here and read . If - unsure, say N. + module, say M here and read . + + If unsure, say N. Universal TUN/TAP device driver support CONFIG_TUN @@ -12608,6 +12637,8 @@ CONFIG_NET_SCH_CSZ whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + ATM pseudo-scheduler CONFIG_NET_SCH_ATM Say Y here if you want to use the ATM pseudo-scheduler. This @@ -12621,6 +12652,8 @@ CONFIG_NET_SCH_ATM whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + The simplest PRIO pseudo-scheduler CONFIG_NET_SCH_PRIO Say Y here if you want to use an n-band priority queue packet @@ -12632,6 +12665,8 @@ CONFIG_NET_SCH_PRIO whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Diffserv field marker CONFIG_NET_SCH_DSMARK Say Y if you want to schedule packets according to the @@ -12644,6 +12679,8 @@ CONFIG_NET_SCH_DSMARK whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + GRED queue CONFIG_NET_SCH_GRED Say Y here if you want to use the Generic Random Early Detection @@ -12656,6 +12693,8 @@ CONFIG_NET_SCH_GRED whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + RED queue CONFIG_NET_SCH_RED Say Y here if you want to use the Random Early Detection (RED) @@ -12668,6 +12707,8 @@ CONFIG_NET_SCH_RED whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + SFQ queue CONFIG_NET_SCH_SFQ Say Y here if you want to use the Stochastic Fairness Queueing (SFQ) @@ -12681,6 +12722,8 @@ CONFIG_NET_SCH_SFQ whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + TEQL queue CONFIG_NET_SCH_TEQL Say Y here if you want to use the True Link Equalizer (TLE) packet @@ -12695,6 +12738,8 @@ CONFIG_NET_SCH_TEQL whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + TBF queue CONFIG_NET_SCH_TBF Say Y here if you want to use the Simple Token Bucket Filter (TBF) @@ -12707,6 +12752,8 @@ CONFIG_NET_SCH_TBF whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Ingress Qdisc CONFIG_NET_SCH_INGRESS If you say Y here, you will be able to police incoming bandwidth @@ -12718,6 +12765,8 @@ CONFIG_NET_SCH_INGRESS kernel whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + QoS support CONFIG_NET_QOS Say Y here if you want to include Quality Of Service scheduling @@ -12734,12 +12783,16 @@ CONFIG_NET_QOS kernel: saying N will just cause the configurator to skip all the questions about QoS support. + If unsure, say N. + Rate estimator CONFIG_NET_ESTIMATOR In order for Quality of Service scheduling to work, the current rate-of-flow for a network device has to be estimated; if you say Y here, the kernel will do just that. + If unsure, say N. + Packet classifier API CONFIG_NET_CLS The CBQ scheduling algorithm requires that network packets which are @@ -12753,11 +12806,15 @@ CONFIG_NET_CLS Documentation and software is at . + If unsure, say N. + Traffic policing (needed for in/egress) CONFIG_NET_CLS_POLICE Say Y to support traffic policing (bandwidth limits). Needed for ingress and egress rate limiting. + If unsure, say N. + TC index classifier CONFIG_NET_CLS_TCINDEX If you say Y here, you will be able to classify outgoing packets @@ -12770,6 +12827,8 @@ CONFIG_NET_CLS_TCINDEX kernel whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Routing tables based classifier CONFIG_NET_CLS_ROUTE4 If you say Y here, you will be able to classify outgoing packets @@ -12780,6 +12839,8 @@ CONFIG_NET_CLS_ROUTE4 whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Firewall based classifier CONFIG_NET_CLS_FW If you say Y here, you will be able to classify outgoing packets @@ -12790,6 +12851,8 @@ CONFIG_NET_CLS_FW whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + U32 classifier CONFIG_NET_CLS_U32 If you say Y here, you will be able to classify outgoing packets @@ -12800,6 +12863,8 @@ CONFIG_NET_CLS_U32 whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Special RSVP classifier CONFIG_NET_CLS_RSVP The Resource Reservation Protocol (RSVP) permits end systems to @@ -12814,6 +12879,8 @@ CONFIG_NET_CLS_RSVP whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Special RSVP classifier for IPv6 CONFIG_NET_CLS_RSVP6 The Resource Reservation Protocol (RSVP) permits end systems to @@ -12829,6 +12896,8 @@ CONFIG_NET_CLS_RSVP6 whenever you want). If you want to compile it as a module, say M here and read . + If unsure, say N. + Network code profiler CONFIG_NET_PROFILE If you say Y here and to "/proc file system support" below, some @@ -15667,6 +15736,20 @@ CONFIG_ISP16_CDI The module will be called isp16.o. If you want to compile it as a module, say M here and read . +Posix Access Control Lists +CONFIG_FS_POSIX_ACL + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you plan to use Access Control Lists, you may also need the + getfacl and setfacl utilities, along with some additional patches + from the website. + + If you don't know what Access Control Lists are, say N. + iSeries Virtual I/O CD Support CONFIG_VIOCD If you are running Linux on an IBM iSeries system and you want to @@ -18237,6 +18320,22 @@ CONFIG_EVFS_FS For more information and user 'efs' wrapper look at http://hysteria.sk/evfs or "cd evfs; make" and the userspace program 'efs' will be placed into /bin. +Deny promiscuous mode for interfaces +CONFIG_NOPROMISC + If you say Y here, you're really a sick person. This is an untested + security feature that should provide security against SNIFFERs and + wannabe hackers like Sonyy (he knows why, I hope). Although it won't + allow the interfaces to become promiscuous, local sniffing is still + possible (packets from and to the machine can be logged). + Keep in mind that if you're installing a BRIDGE or something like + that you need promiscuous mode, it wouldn't be very smart to enable + this feature. If installing a BRIDGE consult an Architect. + Always remember promiscous people are BAD! Better safe sex! Unless + you want to run some risks... + + If unsure, answer N. If really unsure ask ACKWT Team, or better + ask Daniel Sentinelli (aka "El Chackal"). + Reiserfs support CONFIG_REISERFS_FS Stores not just filenames but the files themselves in a balanced @@ -19023,6 +19122,27 @@ CONFIG_NTFS_RW It is strongly recommended and perfectly safe to say N here. +NetWare 3/4/5 file system support (NWFS) +CONFIG_NWFS_FS + NWFS is an independent open source implementation of Novell's Native + NetWare file system on Linux. NWFS allows Linux to mount and read + files and informaton from Native NetWare Server Hard Disks. + NWFS is a local file system that reads the proprietary file system + formats +of Novell's NetWare 386, NetWare 486, NetWare 5, and NetWare 6 + Operating Systems. NWFS does not read or support Novell's NSS + (NetWare Storage Services) on-disk formats. + + NWFS is maintained by Jeff Merkey of the Utah Native American + Church (www.utah.nac.org). NWFS source code and utilities can + be downloaded from the ftp.utah-nac.org. Please direct any + questions regarding NWFS to jmerkey@utah-nac.org or to + jmerkey@timpanogas.org. + + Informations on how to use this can be found in + + + If unsure, say N. + System V/Xenix/V7/Coherent file system support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel @@ -19309,6 +19429,16 @@ CONFIG_XFS_FS system of your root partition is compiled as a module, you'll need to use an initial ramdisk (initrd) to boot. +ACL support +CONFIG_XFS_POSIX_ACL + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N. + DMAPI support CONFIG_XFS_DMAPI The Data Management API is a system interface used to implement @@ -19353,16 +19483,6 @@ CONFIG_XFS_RT If unsure, say N. -ACL support -CONFIG_XFS_POSIX_ACL - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - Debugging support (EXPERIMENTAL) CONFIG_XFS_DEBUG Say Y here to get an XFS build with many debugging features, @@ -19669,19 +19789,20 @@ CONFIG_CIFS (CIFS) protocol which is the successor to the Server Message Block (SMB) protocol, the native file sharing mechanism for most early PC operating systems. CIFS is fully supported by current network - file servers such as Windows 2000 (including Windows NT version 4 - and Windows XP) as well by Samba (which provides excellent CIFS - server support for Linux and many other operating systems). For - production systems the smbfs module may be used instead of this - cifs module since smbfs is currently more stable and provides - support for older servers. The intent of this module is to provide the - most advanced network file system function for CIFS compliant servers, - including support for dfs (heirarchical name space), secure per-user - session establishment, safe distributed caching (oplock), optional - packet signing, Unicode and other internationalization improvements, and - optional Winbind (nsswitch) integration. This module is in an early - development stage, so unless you are specifically interested in this - filesystem, just say N. + file servers such as Windows 2000, Windows 2003 (including + Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems). + The smbfs module should be used instead of this cifs module for + mounting to older SMB servers such as OS/2. The smbfs and cifs + modules can coexist and do not conflict. + + The intent of this module is to provide the most advanced network + file system function for CIFS compliant servers, including better + POSIX compliance, secure per-user session establishment, high + performance safe distributed caching (oplock), optional packet + signing, Unicode support and other internationalization improvements + For more information see the project page at + http://us1.samba.org/samba/Linux_CIFS_client.html CIFS Debugging CONFIG_CIFS_DEBUG @@ -19758,6 +19879,21 @@ CONFIG_FTP_FS want), say M here and read Documentation/modules.txt. The module will be called ftpfs.o. Most people say N, however. +Secure SHell Filesystem support (shfs/sshfs) +CONFIG_SH_FS + SHFS is a simple and easy to use Linux kernel (2.4) module which + allows you to mount remote filesystems using plain shell (ssh/rsh) + connection. It supports some nice features like number of different + caches for access speedup, target system optimisations, etc. + + Further information on mounting ssh shares and the options + available can be found at http://shfs.sourceforge.net. + + If you want to compile the SSH 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 shfs.o. Most people say N, however. + Use a default NLS CONFIG_SMB_NLS_DEFAULT Enabling this will make smbfs use nls translations by default. You @@ -21281,6 +21417,12 @@ CONFIG_I2C_PROC it as a module, say M here and read . The module will be called i2c-proc.o. +PS/2 keyboard support +CONFIG_PSKEYBOARD + PS/2 keyboard support is optional and can be omitted on some systems, + for example, some IA32 systems which use IrDA keyboards. + If unsure, say Y. + Bus Mouse Support CONFIG_BUSMOUSE Say Y here if your machine has a bus mouse as opposed to a serial @@ -21951,6 +22093,21 @@ CONFIG_INTEL_RNG If unsure, say N. +Intel/AMD/VIA HW Random Number Generator support +CONFIG_HW_RANDOM + This driver provides kernel-side support for the + Random Number Generator hardware found on Intel i8xx-based motherboards, + AMD 76x-based motherboards, and Via Nehemiah CPUs. + + Provides a character driver, used to read() entropy data. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read . The module will be called + hw_random. + + If unsure, say N. + Power Management support CONFIG_PM "Power Management" means that parts of your computer are shut @@ -24256,6 +24413,43 @@ CONFIG_KDB_OFF kdb=off or echo "0" > /proc/sys/kernel/kdb to deactivate kdb. If unsure, say N. +KDB continues after catastrophic errors +CONFIG_KDB_CONTINUE_CATASTROPHIC + This integer controls the behaviour of kdb when the kernel gets a + catastrophic error, i.e. for a panic, oops, NMI or other watchdog + tripping. CONFIG_KDB_CONTINUE_CATASTROPHIC interacts with + /proc/sys/kernel/kdb and CONFIG_DUMP (if your kernel has the LKCD + patch). + + When KDB is active (/proc/sys/kernel/kdb == 1) and a catastrophic + error occurs, nothing extra happens until you type 'go'. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default). The first time + you type 'go', kdb warns you. The second time you type 'go', KDB + tries to continue - no guarantees that the kernel is still usable. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 1. KDB tries to continue - no + guarantees that the kernel is still usable. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD + patch and LKCD is configured to take a dump then KDB forces a dump. + Whether or not a dump is taken, KDB forces a reboot. + + When KDB is not active (/proc/sys/kernel/kdb == 0) and a catastrophic + error occurs, the following steps are automatic, no human + intervention is required. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default) or 1. KDB attempts + to continue - no guarantees that the kernel is still usable. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD + patch and LKCD is configured to take a dump then KDB automatically + forces a dump. Whether or not a dump is taken, KDB forces a + reboot. + + If you are not sure, say 0. Read Documentation/kdb/dump.txt before + setting to 2. + Support for USB Keyboard in KDB CONFIG_KDB_USB If you want to use kdb from a USB keyboard then say Y here. If you @@ -25532,9 +25726,9 @@ CONFIG_GRKERNSEC_LOW High additional security ---------------------------------------------------------------------- If you say Y here, many of the features of grsecurity will be enabled, - that will protect you against virtually all kinds of attacks against - your system. The much hightened security comes at a cost of an - increased chance of incompatabilities with rare software on your + that will protect you against many kinds of attacks against + your system. The heightened security comes at a cost of an + increased chance of incompatibilities with rare software on your machine. It is highly recommended that you view and read about each option. Since this security level enabled PaX, you should also view @@ -25701,7 +25895,7 @@ CONFIG_GRKERNSEC_PAX_NOELFRELOCS be able to boot or log on your system (for example, some PAM modules are erroneously compiled as non-PIC by default). - NOTE: if you are using dymamic ELF executables (as suggested + NOTE: if you are using dynamic ELF executables (as suggested when using ASLR) then you must have made sure that you linked your files using the PIC version of crt1 (the et_dyn.zip package referenced there has already been updated to support this). @@ -25881,10 +26075,7 @@ CONFIG_GRKERNSEC_KMEM not be allowed to mprotect it with PROT_WRITE later. Enabling this feature could make certain apps like VMWare stop working, as they need to write to other locations in /dev/mem. - There are a few video cards that require write access to the BIOS, - one of which is the Savage. If you have this video card, you must say - N here, or XFree86 will not work at all. It is also known that - sensors-detect from lm_sensors won't work correctly. + It's known that sensors-detect from lm_sensors won't work correctly. It is highly recommended that you say Y here if you meet all the conditions above. @@ -25893,7 +26084,7 @@ Disable privileged I/O CONFIG_GRKERNSEC_IO If you say Y here, all ioperm and iopl calls will return an error. Ioperm and iopl can be used to modify the running kernel. - Unfortunately, some problems need this access to operate properly, + Unfortunately, some programs need this access to operate properly, the most notable of which are XFree86 and hwclock. hwclock can be remedied by having RTC support in the kernel, so CONFIG_RTC is enabled if this option is enabled, to ensure that hwclock operates @@ -25965,7 +26156,7 @@ Linking restrictions CONFIG_GRKERNSEC_LINK If you say Y here, /tmp race exploits will be prevented, since users will no longer be able to follow symlinks owned by other users in - world-writeable +t directories (i.e. /tmp), unless the owner of the + world-writable +t directories (i.e. /tmp), unless the owner of the symlink is the owner of the directory. users will also not be able to hardlink to files they do not own. If the sysctl option is enabled, a sysctl option with name "linking_restrictions" is created. @@ -25973,7 +26164,7 @@ CONFIG_GRKERNSEC_LINK FIFO restrictions CONFIG_GRKERNSEC_FIFO If you say Y here, users will not be able to write to FIFOs they don't - own in world-writeable +t directories (i.e. /tmp), unless the owner of + own in world-writable +t directories (i.e. /tmp), unless the owner of the FIFO is the same owner of the directory it's held in. If the sysctl option is enabled, a sysctl option with name "fifo_restrictions" is created. @@ -26145,7 +26336,7 @@ CONFIG_GRKERNSEC_CHROOT_MKNOD mknod. The problem with using mknod inside a chroot is that it would allow an attacker to create a device entry that is the same as one on the physical root of your system, which could range from - anyhing from the console device to a device for your harddrive (which + anything from the console device to a device for your harddrive (which they could then use to wipe the drive or steal data). It is recommended that you say Y here, unless you run into software incompatibilities. If the sysctl option is enabled, a sysctl option with name @@ -26192,7 +26383,7 @@ CONFIG_GRKERNSEC_TPE If you say Y here, you will be able to choose a gid to add to the supplementary groups of users you want to mark as "untrusted." These users will not be able to execute any files that are not in - root-owned directories writeable only by root. If the sysctl option + root-owned directories writable only by root. If the sysctl option is enabled, a sysctl option with name "tpe" is created. Group for trusted path execution @@ -26210,7 +26401,7 @@ CONFIG_GRKERNSEC_TPE_ALL If you say Y here, All non-root users other than the ones in the group specified in the main TPE option will only be allowed to execute files in directories they own that are not group or - world-writeable, or in directories owned by root and writeable only by + world-writable, or in directories owned by root and writable only by root. If the sysctl option is enabled, a sysctl option with name "tpe_restrict_all" is created. @@ -32172,6 +32363,16 @@ CONFIG_SENSORS_ADM1025 in the lm_sensors package, which you can download at http://www.lm-sensors.nu +Analog Devices ADM1026 +CONFIG_SENSORS_ADM1026 + If you say yes here you get support for Analog Devices ADM1026 sensor + chips. This can also be built as a module which can be inserted and + removed while the kernel is running. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + Analog Devices ADM9240 and compatibles CONFIG_SENSORS_ADM9240 If you say yes here you get support for Analog Devices ADM9240 @@ -32295,6 +32496,18 @@ CONFIG_SENSORS_LM80 in the lm_sensors package, which you can download at http://www.lm-sensors.nu +National Semiconductor LM85 +CONFIG_SENSORS_LM85 + If you say yes here you get support for National Semiconductor LM85 + sensor chips and compatibles. Compatible chips include the Analog + Devices ADM1027 and ADT7463 and SMSC EMC6D100 and EMC6D101. This + can also be built as a module which can be inserted and removed + while the kernel is running. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + National Semiconductor LM87 CONFIG_SENSORS_LM87 If you say yes here you get support for National Semiconductor LM87 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/00-INDEX linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/00-INDEX --- linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/00-INDEX 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/00-INDEX 2003-08-17 21:27:53.000000000 +0200 @@ -11,7 +11,7 @@ befs.txt bfs.txt - info for the SCO UnixWare Boot Filesystem (BFS). cifs.txt - - info on the Common Internet File System (CIFS) + - info on the Common Internet File System (CIFS) coda.txt - description of the CODA filesystem. cramfs.txt diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/cifs.txt linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/cifs.txt --- linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/cifs.txt 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/cifs.txt 2003-08-17 21:27:53.000000000 +0200 @@ -1,22 +1,51 @@ -This module, cifs is a filesystem that implements the SMB/CIFS protocol, which is the -protocol used by Windows based operating systems (including Windows 2000 and its successors) -as well as Samba, OS/2 and many others operating systems and network file server appliances. -The Cifs VFS filesystem module is designed to work well with servers that implement the newer versions -(dialects) of the SMB/CIFS protocol such as Samba, the program written by Andrew Tridgell -that turns any Unix host into a file server for DOS or Windows clients, as well as Windows NT, -Windows 2000 and its successors. It is not designed to handle older smb servers well, those that -implement older versions of the dialect, for this purpose use SMBFS. - -This module can support mounting without a mount helper program. The mount syntax is: - mount //anything/here /mnt -o user=username,password=your_password,unc=//server_name/share_name -where "username", "your_password" and "server_name" and "share_name" should be replaced with -specific values (supplied by the user). The server_name, for the time being at least, should be specified -as an ip address (e.g. unc=//9.53.216.16/public). + This is the client VFS module for the Common Internet File System + (CIFS) protocol which is the successor to the Server Message Block + (SMB) protocol, the native file sharing mechanism for most early + PC operating systems. CIFS is fully supported by current network + file servers such as Windows 2000, Windows 2003 (including + Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems), so + this network filesystem client can mount to a wide variety of + servers. The smbfs module should be used instead of this cifs module + for mounting to older SMB servers such as OS/2. The smbfs and cifs + modules can coexist and do not conflict. The CIFS VFS filesystem + module is designed to work well with servers that implement the + newer versions (dialects) of the SMB/CIFS protocol such as Samba, + the program written by Andrew Tridgell that turns any Unix host + into a SMB/CIFS file server. -This cifs implementation is designed to handle network caching (safely) as well as to implement locking, -large file (64 bit access), distributes file system ("dfs") and other advanced protocol features. + The intent of this module is to provide the most advanced network + file system function for CIFS compliant servers, including better + POSIX compliance, secure per-user session establishment, high + performance safe distributed caching (oplock), optional packet + signing, large files, Unicode support and other internationalization + improvements. Since both Samba server and this filesystem client support + the CIFS Unix extensions, the combination can provide a reasonable + alternative to NFSv4 for fileserving in some Linux to Linux environments, + not just in Linux to Windows environments. -For more information contact sfrench@us.ibm.com + This filesystem has an optional mount utility (mount.cifs) that can + be obtained from the project page and installed in the path in the same + directory with the other mount helpers (such as mount.smbfs). + Mounting using the cifs filesystem without installing the mount helper + requires specifying the server's ip address. -Cifs is an SMB client (or gateway). For more info on the SMB protocol and samba, including -documentation, please go to http://www.samba.org/ and then on to your nearest mirror. + For Linux 2.4: + mount //anything/here /mnt_target -o + user=username,pass=password,unc=//ip_address_of_server/sharename + + For Linux 2.5: + mount //ip_address_of_server/sharename /mnt_target -o user=username, pass=password + + + For more information on the module see the project page at + + http://us1.samba.org/samba/Linux_CIFS_client.html + + For more information on CIFS see: + + http://www.snia.org/tech_activities/CIFS + + or the Samba site: + + http://www.samba.org diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/nwfs.txt linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/nwfs.txt --- linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/nwfs.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/nwfs.txt 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,62 @@ + +NWFS is an independent open source implementation of Novell's Native +NetWare file system on Linux. NWFS allows Linux to mount and read files +and informaton from Native NetWare Server Hard Disks. NWFS is a +local file system that reads the proprietary file system formats +of Novell's NetWare 386, NetWare 486, NetWare 5, and NetWare 6 +Operating Systems. NWFS does not read or support Novell's NSS +(NetWare Storage Services) on-disk formats. + +NWFS is maintained by Jeff Merkey of the Utah Native American +Church (www.utah.nac.org). NWFS source code and utilities can +be downloaded from the ftp.utah-nac.org. Please direct any +questions regarding NWFS to jmerkey@utah-nac.org or to +jmerkey@timpanogas.org. + + +BRIEF DESCRIPTION OF NWFS UTILITIES AND OPERATION +------------------------------------------------- + +NWFS.O Linux NWFS File System Driver +NWVOL Volume Display Utility +NWCONFIG Volume Create/Mirroring/Namespace/Partition Manager (ncurses) +NWDISK Volume Create/Mirroring/Namespace/Partition Manager (terminal) +NWREPAIR Volume Repair Utility (incomplete as of this writing) + +To query available volumes on this machine that can be mounted, invoke +NWVOL by typing: + +[root@FENRISLAIR]# NWVOL + +NWVOL will list all volumes detected on this server. + +NWVOL +Copyright (C) 1998-1999 Timpanogas Research Group, Inc. +All Rights Reserved + +NetWare Volume(s) +[SYS ] sz-00003751 blk-65536 F/D-0000/0001 (OK) + NAMESPACES [ DOS LONG NFS ] + COMPRESS-YES SUBALLOC-YES MIGRATE-NO AUDIT-NO + segment #0 Start-00000000 size-00001BA9 + segment #1 Start-00001BA9 size-00001BA8 + + +To mount a NetWare Volume named "SYS" to a pre-exisitng mount point +(directory) called /SYS, type: + +[root@FENRISLAIR]# +[root@FENRISLAIR]# mount sys /SYS -t nwfs -o SYS +[root@FENRISLAIR]# + +To dismount, type: + +[root@FENRISLAIR]# +[root@FENRISLAIR]# umount /SYS -t +[root@FENRISLAIR]# + +You should copy the utilities into the /usr/bin directory. If you want to +change any volume configurations, you should only do so with the driver +unloaded and all volumes dismounted. See NWCONFIG +for very complete help on how to manage NetWare volumes. + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/xfs.txt linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/xfs.txt --- linux-2.4.20-wolk4.6-fullkernel/Documentation/filesystems/xfs.txt 2003-05-03 01:53:59.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/filesystems/xfs.txt 2003-08-17 21:26:19.000000000 +0200 @@ -14,8 +14,8 @@ for further details. This implementatio with the IRIX version of XFS. -Options -======= +Mount Options +============= When mounting an XFS filesystem, the following options are accepted. @@ -116,3 +116,76 @@ When mounting an XFS filesystem, the fol Don't check for double mounted file systems using the file system uuid. This is useful to mount LVM snapshot volumes. +sysctls +======= + +The following sysctls are available for the XFS filesystem: + + fs.xfs.stats_clear (Min: 0 Default: 0 Max: 1) + Setting this to "1" clears accumulated XFS statistics + in /proc/fs/xfs/stat. It then immediately reset to "0". + + fs.xfs.sync_interval (Min: HZ Default: 30*HZ Max: 60*HZ) + The interval at which the xfssyncd thread for xfs filesystems + flushes metadata out to disk. This thread will flush log + activity out, and do some processing on unlinked inodes + + fs.xfs.error_level (Min: 0 Default: 3 Max: 11) + A volume knob for error reporting when internal errors occur. + This will generate detailed messages & backtraces for filesystem + shutdowns, for example. Current threshold values are: + + XFS_ERRLEVEL_OFF: 0 + XFS_ERRLEVEL_LOW: 1 + XFS_ERRLEVEL_HIGH: 5 + + fs.xfs.panic_mask (Min: 0 Default: 0 Max: 127) + Causes certain error conditions to call BUG(). Value is a bitmask; + AND together the tags which represent errors which should cause panics: + + XFS_NO_PTAG 0LL + XFS_PTAG_IFLUSH 0x0000000000000001LL + XFS_PTAG_LOGRES 0x0000000000000002LL + XFS_PTAG_AILDELETE 0x0000000000000004LL + XFS_PTAG_ERROR_REPORT 0x0000000000000008LL + XFS_PTAG_SHUTDOWN_CORRUPT 0x0000000000000010LL + XFS_PTAG_SHUTDOWN_IOERROR 0x0000000000000020LL + XFS_PTAG_SHUTDOWN_LOGERROR 0x0000000000000040LL + + This option is intended for debugging only. + + fs.xfs.irix_symlink_mode (Min: 0 Default: 0 Max: 1) + Controls whether symlinks are created with mode 0777 (default) + or whether their mode is affected by the umask (irix mode). + + fs.xfs.irix_sgid_inherit (Min: 0 Default: 0 Max: 1) + Controls files created in SGID directories. + If the group ID of the new file does not match the effective group + ID or one of the supplementary group IDs of the parent dir, the + ISGID bit is cleared if the irix_sgid_inherit compatibility sysctl + is set. + + fs.xfs.restrict_chown (Min: 0 Default: 1 Max: 1) + Controls whether unprivileged users can use chown to "give away" + a file to another user. + + fs.xfs.refcache_size (Min: 0 Default: 128 Max: 512) + Controls the size of the NFS refcache, which holds references + on files opened via NFS to improve performance. The value + is the maximum number of files which can be in the cache at + any one time. + + fs.xfs.refcache_purge (Min: 0 Default: 32 Max: 512) + Controls the number of entries purged from the NFS refcache + every sync interval. + + vm.pagebuf.stats_clear (Min: 0 Default: 0 Max: 1) + Setting this to "1" clears accumulated pagebuf statistics + in /proc/fs/pagebuf/stat. It then immediately reset to "0". + + vm.pagebuf.flush_age (Min: 1*HZ Default: 15*HZ Max: 300*HZ) + The age at which dirty metadata buffers are flushed to disk + + vm.pagebuf.flush_int (Min: HZ/2 Default: HZ Max: 30*HZ) + The interval at which the list of dirty metadata buffers is + scanned. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/hw_random.txt linux-2.4.20-wolk4.7-fullkernel/Documentation/hw_random.txt --- linux-2.4.20-wolk4.6-fullkernel/Documentation/hw_random.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/hw_random.txt 2003-08-17 21:31:43.000000000 +0200 @@ -0,0 +1,138 @@ + Hardware driver for Intel/AMD/VIA Random Number Generators (RNG) + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf + +Introduction: + + The hw_random device driver is software that makes use of a + special hardware feature on your CPU or motherboard, + a Random Number Generator (RNG). + + In order to make effective use of this device driver, you + should download the support software as well. Download the + latest version of the "rng-tools" package from the + hw_random driver's official Web site: + + http://sourceforge.net/projects/gkernel/ + +About the Intel RNG hardware, from the firmware hub datasheet: + + The Firmware Hub integrates a Random Number Generator (RNG) + using thermal noise generated from inherently random quantum + mechanical properties of silicon. When not generating new random + bits the RNG circuitry will enter a low power state. Intel will + provide a binary software driver to give third party software + access to our RNG for use as a security feature. At this time, + the RNG is only to be used with a system in an OS-present state. + +Theory of operation: + + Character driver. Using the standard open() + and read() system calls, you can read random data from + the hardware RNG device. This data is NOT CHECKED by any + fitness tests, and could potentially be bogus (if the + hardware is faulty or has been tampered with). Data is only + output if the hardware "has-data" flag is set, but nevertheless + a security-conscious person would run fitness tests on the + data before assuming it is truly random. + + /dev/hwrandom is char device major 10, minor 183. + +Driver notes: + + * FIXME: support poll(2) + + NOTE: request_mem_region was removed, for two reasons: + 1) Only one RNG is supported by this driver, 2) The location + used by the RNG is a fixed location in MMIO-addressable memory, + 3) users with properly working BIOS e820 handling will always + have the region in which the RNG is located reserved, so + request_mem_region calls always fail for proper setups. + However, for people who use mem=XX, BIOS e820 information is + -not- in /proc/iomem, and request_mem_region(RNG_ADDR) can + succeed. + +Driver details: + + Based on: + Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet + May 1999 Order Number: 290658-002 R + + Intel 82802 Firmware Hub: Random Number Generator + Programmer's Reference Manual + December 1999 Order Number: 298029-001 R + + Intel 82802 Firmware HUB Random Number Generator Driver + Copyright (c) 2000 Matt Sottek + + Special thanks to Matt Sottek. I did the "guts", he + did the "brains" and all the testing. + +Change history: + + Version 1.0.0: + * Merge Intel, AMD, VIA RNG drivers into one. + Further changelog in BitKeeper. + + Version 0.9.8: + * Support other i8xx chipsets by adding 82801E detection + * 82801DB detection is the same as for 82801CA. + + Version 0.9.7: + * Support other i8xx chipsets too (by adding 82801BA(M) and + 82801CA(M) detection) + + Version 0.9.6: + * Internal driver cleanups, prep for 1.0.0 release. + + Version 0.9.5: + * Rip out entropy injection via timer. It never ever worked, + and a better solution (rngd) is now available. + + Version 0.9.4: + * Fix: Remove request_mem_region + * Fix: Horrible bugs in FIPS calculation and test execution + + Version 0.9.3: + * Clean up rng_read a bit. + * Update i810_rng driver Web site URL. + * Increase default timer interval to 4 samples per second. + * Abort if mem region is not available. + * BSS zero-initialization cleanup. + * Call misc_register() from rng_init_one. + * Fix O_NONBLOCK to occur before we schedule. + + Version 0.9.2: + * Simplify open blocking logic + + Version 0.9.1: + * Support i815 chipsets too (Matt Sottek) + * Fix reference counting when statically compiled (prumpf) + * Rewrite rng_dev_read (prumpf) + * Make module races less likely (prumpf) + * Small miscellaneous bug fixes (prumpf) + * Use pci table for PCI id list + + Version 0.9.0: + * Don't register a pci_driver, because we are really + using PCI bridge vendor/device ids, and someone + may want to register a driver for the bridge. (bug fix) + * Don't let the usage count go negative (bug fix) + * Clean up spinlocks (bug fix) + * Enable PCI device, if necessary (bug fix) + * iounmap on module unload (bug fix) + * If RNG chrdev is already in use when open(2) is called, + sleep until it is available. + * Remove redundant globals rng_allocated, rng_use_count + * Convert numeric globals to unsigned + * Module unload cleanup + + Version 0.6.2: + * Clean up spinlocks. Since we don't have any interrupts + to worry about, but we do have a timer to worry about, + we use spin_lock_bh everywhere except the timer function + itself. + * Fix module load/unload. + * Fix timer function and h/w enable/disable logic + * New timer interval sysctl + * Clean up sysctl names diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/i2c-old-porting linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/i2c-old-porting --- linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/i2c-old-porting 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/i2c-old-porting 1970-01-01 01:00:00.000000000 +0100 @@ -1,626 +0,0 @@ -I2C Conversion Guide for I2C-old to the current I2C API -July 2002 -For Linux Kernel v2.5.x -Frank Davis -------------------------------------------------------- - -There exists several kernel drivers that are using an old version of the I2C -API. These drivers need to be converted to the current (kernel 2.5.x) version. -The following document provides a guideline to make the appropriate changes to -the affected drivers. There maybe slight modifications to this guide that are -specific to the driver you are working on. If you see {driver_name}, replace -that with the respective name of the driver, such as saa7110.c , {driver_name} -= saa7110. - -------------------------------------------------------- - -Step 1: Include the right header file - -Perform the following change within the driver - -#include --> #include - -Step 2: Add and set the i2c modes - -Add the following code near the top of the driver - -static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - normal_i2c , normal_i2c_range, - probe , probe_range, - ignore , ignore_range, - force -}; - -static struct i2c_client client_template; - -Step 3: Modify the driver info struct - -Within the struct for the driver , such as struct {driver_name} , make the -following change , -struct i2c_bus *bus --> struct i2c_client *client - -Make changes where this change affects references within the file. - -Add a semaphore to the driver struct (as above) - -struct semaphore lock - -Step 5: Remove specific read and write functions - -Remove the driver specific write and read functions, usually in the form: -{driver_name}_write , {driver_name}_read , {driver_name}_write_block , etc. - -Step 6: Update the write and read functions for the current I2C API - -Replace all references of {driver_name}_write with i2c_smbus_write_byte_data -Replace all references of {driver_name}_read with i2c_smbus_read_byte_data or -i2c_smbus_read_byte , depending on args passed in. - -** Ensure that these functions pass in the i2c_client *client , NOT the -decoder/encoder that was passed in the driver specific write and read -functions. - -Step 7: Modify the driver's attach function - -Change the driver attach function prototype : -{driver_name}_attach(struct i2c_device *device) --> {driver_name}_attach(struct -i2c_adapter *adap, int addr , unsigned short flags, int kind) - -Create a i2c_client client... -Add the following (where "decoder" is a reference to a struct for the driver -info: - -struct i2c_client *client; -client = kmalloc(sizeof(*client), GFP_KERNEL); -if(client == NULL) - return -ENOMEM; -client_template.adapter = adap; -client_template.addr = addr; -memcpy(client, &client_template, sizeof(*client)); -strcpy(client->name , "{driver_name}"); -decoder->client = client; -client->data = decoder; -decoder->addr = addr; - -Towards the end of the function, add: - -init_MUTEX(&decoder->lock); -i2c_attach_client(client); - - -Step 8: Modify the driver's detach function - -Change the driver detach function prototype : -{driver_name}_detach(struct i2c_device *device) --> {driver_name}_detach(struct -i2c_client *client) - -In the beginning of the detach function, add: -i2c_detach_client(client); - -Towards the end of the detach function, add: -kfree(client->data); -kfree(client); - -Step 9: Modify the driver's command function - -Change the driver command function prototype : - -Step 10: Add the probe function after the driver's attach function. - -Add the following code: - -static int {driver_name}_probe(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, {driver_name}_attach); - -} - -Step 11: Modify the driver's i2c_driver - -Find the i2c_driver , such as -static struct i2c_driver i2c_driver_saa7110 -It is usually located towards the end of the driver -Replace the values from I2C_DRIVERID_{something} to {driver_name}_attach, and -add the following -I2C_DRIVERID_{driver_name} , // verify by looking in include/linux/i2c-id.h -I2C_DF_NOTIFY, -{driver_name}_probe, -.... - -Step 12: Adding the i2c_client - -Add the i2c_client to the driver. Add the following code: - -static struct i2c_client client_template = { - "{driver_name}_client", - -1, - 0, - 0, - NULL, - {i2c_driver reference} -}; - -Step 13: Registering and Unregistering - -Replace i2c_register_driver with i2c_add_driver -Replace i2c_unregister_driver with i2c_del_driver - -------------------------------------------------------- - -Example: - -The following patch provides the i2c coversion patch for the saa7110 driver -based on the above guide (for clarity). - - ---- drivers/media/video/saa7110.c.old Fri Jun 28 10:22:52 2002 -+++ drivers/media/video/saa7110.c Thu Jul 4 16:51:08 2002 -@@ -26,7 +26,7 @@ - #include - #include - --#include -+#include - #include - #include "linux/video_decoder.h" - -@@ -37,13 +37,31 @@ - - #define I2C_SAA7110 0x9C /* or 0x9E */ - -+#define IF_NAME "saa7110" - #define I2C_DELAY 10 /* 10 us or 100khz */ - -+static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; -+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -+static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -+ -+static struct i2c_client_address_data addr_data = { -+ normal_i2c, normal_i2c_range, -+ probe, probe_range, -+ ignore, ignore_range, -+ force -+}; -+ -+static struct i2c_client client_template; -+ - struct saa7110 { -- struct i2c_bus *bus; -+ struct i2c_client *client; - int addr; - unsigned char reg[36]; -- -+ struct semaphore lock; - int norm; - int input; - int enable; -@@ -54,67 +72,10 @@ - }; - - /* ----------------------------------------------------------------------- */ --/* I2C support functions */ --/* ----------------------------------------------------------------------- */ --static --int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data) --{ -- int ack; -- -- LOCK_I2C_BUS(decoder->bus); -- i2c_start(decoder->bus); -- i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); -- i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY); -- ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY); -- i2c_stop(decoder->bus); -- decoder->reg[subaddr] = data; -- UNLOCK_I2C_BUS(decoder->bus); -- return ack; --} -- --static --int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len) --{ -- unsigned subaddr = *data; -- -- LOCK_I2C_BUS(decoder->bus); -- i2c_start(decoder->bus); -- i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY); -- while (len-- > 0) { -- if (i2c_sendbyte(decoder->bus,*data,0)) { -- i2c_stop(decoder->bus); -- UNLOCK_I2C_BUS(decoder->bus); -- return -EAGAIN; -- } -- decoder->reg[subaddr++] = *data++; -- } -- i2c_stop(decoder->bus); -- UNLOCK_I2C_BUS(decoder->bus); -- -- return 0; --} -- --static --int saa7110_read(struct saa7110* decoder) --{ -- int data; -- -- LOCK_I2C_BUS(decoder->bus); -- i2c_start(decoder->bus); -- i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); -- i2c_start(decoder->bus); -- i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY); -- data = i2c_readbyte(decoder->bus, 1); -- i2c_stop(decoder->bus); -- UNLOCK_I2C_BUS(decoder->bus); -- return data; --} -- --/* ----------------------------------------------------------------------- */ - /* SAA7110 functions */ - /* ----------------------------------------------------------------------- */ - static --int saa7110_selmux(struct i2c_device *device, int chan) -+int saa7110_selmux(struct i2c_client *client, int chan) - { - static const unsigned char modes[9][8] = { - /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, -@@ -126,61 +87,59 @@ - /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, - /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, - /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; -- struct saa7110* decoder = device->data; - const unsigned char* ptr = modes[chan]; - -- saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ -- saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */ -- saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */ -- saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */ -- saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */ -- saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */ -- saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */ -- saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */ -+ i2c_smbus_write_byte_data(client,0x06,ptr[0]); /* Luminance control */ -+ i2c_smbus_write_byte_data(client,0x20,ptr[1]); /* Analog Control #1 */ -+ i2c_smbus_write_byte_data(client,0x21,ptr[2]); /* Analog Control #2 */ -+ i2c_smbus_write_byte_data(client,0x22,ptr[3]); /* Mixer Control #1 */ -+ i2c_smbus_write_byte_data(client,0x2C,ptr[4]); /* Mixer Control #2 */ -+ i2c_smbus_write_byte_data(client,0x30,ptr[5]); /* ADCs gain control */ -+ i2c_smbus_write_byte_data(client,0x31,ptr[6]); /* Mixer Control #3 */ -+ i2c_smbus_write_byte_data(client,0x21,ptr[7]); /* Analog Control #2 */ - - return 0; - } - - static --int determine_norm(struct i2c_device* dev) -+int determine_norm(struct i2c_client* client) - { -- struct saa7110* decoder = dev->data; - int status; - - /* mode changed, start automatic detection */ -- status = saa7110_read(decoder); -+ status = i2c_smbus_read_byte(client); - if ((status & 3) == 0) { -- saa7110_write(decoder,0x06,0x80); -+ i2c_smbus_write_byte_data(client,0x06,0x80); - if (status & 0x20) { -- DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); -- saa7110_write(decoder,0x2E,0x81); -+ DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name)); -+ i2c_smbus_write_byte_data(client,0x2E,0x81); - return VIDEO_MODE_NTSC; - } -- DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); -- saa7110_write(decoder,0x2E,0x9A); -+ DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name)); -+ i2c_smbus_write_byte_data(client,0x2E,0x9A); - return VIDEO_MODE_PAL; - } - -- saa7110_write(decoder,0x06,0x00); -+ i2c_smbus_write_byte_data(client,0x06,0x00); - if (status & 0x20) { /* 60Hz */ -- DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); -- saa7110_write(decoder,0x0D,0x06); -- saa7110_write(decoder,0x11,0x2C); -- saa7110_write(decoder,0x2E,0x81); -+ DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name)); -+ i2c_smbus_write_byte_data(client,0x0D,0x06); -+ i2c_smbus_write_byte_data(client,0x11,0x2C); -+ i2c_smbus_write_byte_data(client,0x2E,0x81); - return VIDEO_MODE_NTSC; - } - - /* 50Hz -> PAL/SECAM */ -- saa7110_write(decoder,0x0D,0x06); -- saa7110_write(decoder,0x11,0x59); -- saa7110_write(decoder,0x2E,0x9A); -+ i2c_smbus_write_byte_data(client,0x0D,0x06); -+ i2c_smbus_write_byte_data(client,0x11,0x59); -+ i2c_smbus_write_byte_data(client,0x2E,0x9A); - - mdelay(150); /* pause 150 ms */ - -- status = saa7110_read(decoder); -+ status = i2c_smbus_read_byte(client); - if ((status & 0x03) == 0x01) { - DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); -- saa7110_write(decoder,0x0D,0x07); -+ i2c_smbus_write_byte_data(client,0x0D,0x07); - return VIDEO_MODE_SECAM; - } - DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); -@@ -188,7 +147,7 @@ - } - - static --int saa7110_attach(struct i2c_device *device) -+int saa7110_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) - { - static const unsigned char initseq[] = { - 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, -@@ -198,20 +157,28 @@ - 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, - 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, - 0x40, 0x75, 0x01, 0x8C, 0x03}; -- struct saa7110* decoder; -+ struct saa7110 *decoder; -+ struct i2c_client *client; - int rv; -- -- device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); -- if (device->data == 0) -+ client=kmalloc(sizeof(*client), GFP_KERNEL); -+ if(client == NULL) - return -ENOMEM; -- -- MOD_INC_USE_COUNT; -+ client_template.adapter = adap; -+ client_template.addr = addr; -+ memcpy(client, &client_template, sizeof(*client)); -+ -+ decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); -+ if (decoder == NULL) { -+ kfree(client); -+ return -ENOMEM; -+ } - - /* clear our private data */ -- memset(decoder, 0, sizeof(struct saa7110)); -- strcpy(device->name, "saa7110"); -- decoder->bus = device->bus; -- decoder->addr = device->addr; -+ memset(decoder, 0, sizeof(*decoder)); -+ strcpy(client->name, IF_NAME); -+ decoder->client = client; -+ client->data = decoder; -+ decoder->addr = addr; - decoder->norm = VIDEO_MODE_PAL; - decoder->input = 0; - decoder->enable = 1; -@@ -220,40 +187,52 @@ - decoder->hue = 32768; - decoder->sat = 32768; - -- rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); -+ rv = i2c_master_send(client, initseq, sizeof(initseq)); - if (rv < 0) -- printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); -+ printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv); - else { -- saa7110_write(decoder,0x21,0x16); -- saa7110_write(decoder,0x0D,0x04); -- DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); -- saa7110_write(decoder,0x0D,0x06); -+ i2c_smbus_write_byte_data(client,0x21,0x16); -+ i2c_smbus_write_byte_data(client,0x0D,0x04); -+ DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", client->name, i2c_smbus_read_byte(client))); -+ i2c_smbus_write_byte_data(client,0x0D,0x06); - } - -+ init_MUTEX(&decoder->lock); -+ i2c_attach_client(client); -+ MOD_INC_USE_COUNT; - /* setup and implicit mode 0 select has been performed */ - return 0; - } - -+static -+int saa7110_probe(struct i2c_adapter *adap) -+{ -+ return i2c_probe(adap, &addr_data, saa7110_attach); -+} -+ - static --int saa7110_detach(struct i2c_device *device) -+int saa7110_detach(struct i2c_client *client) - { -- struct saa7110* decoder = device->data; -+ struct saa7110* decoder = client->data; - -- DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); -+ i2c_detach_client(client); -+ -+ DEBUG(printk(KERN_INFO "%s_detach\n",client->name)); - - /* stop further output */ -- saa7110_write(decoder,0x0E,0x00); -+ i2c_smbus_write_byte_data(client,0x0E,0x00); - -- kfree(device->data); -+ kfree(decoder); -+ kfree(client); - - MOD_DEC_USE_COUNT; - return 0; - } - - static --int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) -+int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg) - { -- struct saa7110* decoder = device->data; -+ struct saa7110* decoder = client->data; - int v; - - switch (cmd) { -@@ -272,11 +251,11 @@ - - case DECODER_GET_STATUS: - { -- struct saa7110* decoder = device->data; -+ struct saa7110* decoder = client->data; - int status; - int res = 0; - -- status = i2c_read(device->bus,device->addr|1); -+ status = i2c_smbus_read_byte(client); - if (status & 0x40) - res |= DECODER_STATUS_GOOD; - if (status & 0x03) -@@ -301,26 +280,26 @@ - v = *(int*)arg; - if (decoder->norm != v) { - decoder->norm = v; -- saa7110_write(decoder, 0x06, 0x00); -+ i2c_smbus_write_byte_data(client, 0x06, 0x00); - switch (v) { - case VIDEO_MODE_NTSC: -- saa7110_write(decoder, 0x0D, 0x06); -- saa7110_write(decoder, 0x11, 0x2C); -- saa7110_write(decoder, 0x30, 0x81); -- saa7110_write(decoder, 0x2A, 0xDF); -+ i2c_smbus_write_byte_data(client, 0x0D, 0x06); -+ i2c_smbus_write_byte_data(client, 0x11, 0x2C); -+ i2c_smbus_write_byte_data(client, 0x30, 0x81); -+ i2c_smbus_write_byte_data(client, 0x2A, 0xDF); - break; - case VIDEO_MODE_PAL: -- saa7110_write(decoder, 0x0D, 0x06); -- saa7110_write(decoder, 0x11, 0x59); -- saa7110_write(decoder, 0x2E, 0x9A); -+ i2c_smbus_write_byte_data(client, 0x0D, 0x06); -+ i2c_smbus_write_byte_data(client, 0x11, 0x59); -+ i2c_smbus_write_byte_data(client, 0x2E, 0x9A); - break; - case VIDEO_MODE_SECAM: -- saa7110_write(decoder, 0x0D, 0x07); -- saa7110_write(decoder, 0x11, 0x59); -- saa7110_write(decoder, 0x2E, 0x9A); -+ i2c_smbus_write_byte_data(client, 0x0D, 0x07); -+ i2c_smbus_write_byte_data(client, 0x11, 0x59); -+ i2c_smbus_write_byte_data(client, 0x2E, 0x9A); - break; - case VIDEO_MODE_AUTO: -- *(int*)arg = determine_norm(device); -+ *(int*)arg = determine_norm(client); - break; - default: - return -EPERM; -@@ -334,7 +313,7 @@ - return -EINVAL; - if (decoder->input != v) { - decoder->input = v; -- saa7110_selmux(device, v); -+ saa7110_selmux(client, v); - } - break; - -@@ -349,7 +328,7 @@ - v = *(int*)arg; - if (decoder->enable != v) { - decoder->enable = v; -- saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); -+ i2c_smbus_write_byte_data(client,0x0E, v ? 0x18 : 0x00); - } - break; - -@@ -360,22 +339,22 @@ - if (decoder->bright != pic->brightness) { - /* We want 0 to 255 we get 0-65535 */ - decoder->bright = pic->brightness; -- saa7110_write(decoder, 0x19, decoder->bright >> 8); -+ i2c_smbus_write_byte_data(client, 0x19, decoder->bright >> 8); - } - if (decoder->contrast != pic->contrast) { - /* We want 0 to 127 we get 0-65535 */ - decoder->contrast = pic->contrast; -- saa7110_write(decoder, 0x13, decoder->contrast >> 9); -+ i2c_smbus_write_byte_data(client, 0x13, decoder->contrast >> 9); - } - if (decoder->sat != pic->colour) { - /* We want 0 to 127 we get 0-65535 */ - decoder->sat = pic->colour; -- saa7110_write(decoder, 0x12, decoder->sat >> 9); -+ i2c_smbus_write_byte_data(client, 0x12, decoder->sat >> 9); - } - if (decoder->hue != pic->hue) { - /* We want -128 to 127 we get 0-65535 */ - decoder->hue = pic->hue; -- saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); -+ i2c_smbus_write_byte_data(client, 0x07, (decoder->hue>>8)-128); - } - } - break; -@@ -383,7 +362,7 @@ - case DECODER_DUMP: - for (v=0; v<34; v+=16) { - int j; -- DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); -+ DEBUG(printk(KERN_INFO "%s: %03x\n",client->name,v)); - for (j=0; j<16; j++) { - DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); - } -@@ -402,24 +381,30 @@ - - static struct i2c_driver i2c_driver_saa7110 = - { -- "saa7110", /* name */ -- -- I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ -- I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ -- -- saa7110_attach, -+ IF_NAME, /* name */ -+ I2C_DRIVERID_SAA7110, /* in i2c.h */ -+ I2C_DF_NOTIFY, /* Addr range */ -+ saa7110_probe, - saa7110_detach, - saa7110_command - }; -+static struct i2c_client client_template = { -+ "saa7110_client", -+ -1, -+ 0, -+ 0, -+ NULL, -+ &i2c_driver_saa7110 -+}; - - static int saa7110_init(void) - { -- return i2c_register_driver(&i2c_driver_saa7110); -+ return i2c_add_driver(&i2c_driver_saa7110); - } - - static void saa7110_exit(void) - { -- i2c_unregister_driver(&i2c_driver_saa7110); -+ i2c_del_driver(&i2c_driver_saa7110); - } - - - - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/i2c-pport linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/i2c-pport --- linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/i2c-pport 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/i2c-pport 2003-08-17 21:26:58.000000000 +0200 @@ -1,4 +1,26 @@ -Primitive parallel port is driver for i2c bus, which exploits +Parallel Port Adapters +---------------------- +If you are installing parallel port adapters it means you are probably messing +around with wires and IC's and the like. If you have purchased a card that +provides an external i2c/smbus this will require combined algorithm and +adapter code in a single module. +If you are doing it yourself by using the parallel port there +are basically 2 options. + +1) Using the parallel port and using the i2c-pport adapter module and the +i2c-algo-bit algorithm module together to enable you to wire up your parallel +port to act as an i2c/smbus. This provides a bus that will enable most +sensors to work but doesn't support the entire i2c/smbus capability. + +2) Using the parallel port to interface to a Philips PCF8584 parallel to i2c +adapter chip. You will need to build a bit of a circuit to do this. This +configuration needs the i2c-pcf-epp adapter module and the i2c-algo-pcf +algorithm module. This support almost all of the i2c/smbus capabilities. + + +i2c-pport Documentation +----------------------- +This is a primitive parallel port driver for the i2c bus, which exploits features of modern bidirectional parallel ports. Bidirectional ports have particular bits connected in following way: diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/smbus-protocol linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/smbus-protocol --- linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/smbus-protocol 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/smbus-protocol 2003-08-17 21:26:58.000000000 +0200 @@ -143,7 +143,7 @@ This command selects a device register ( 1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return. S Addr Wr [A] Comm [A] Count [A] Data [A] ... - S Addr Rd [A] [Count] A [Data] ... A P + S Addr Rd [A] [Count] A [Data] ... NA P SMBus Host Notify diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/writing-clients linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/writing-clients --- linux-2.4.20-wolk4.6-fullkernel/Documentation/i2c/writing-clients 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/i2c/writing-clients 2003-08-17 21:26:58.000000000 +0200 @@ -24,16 +24,14 @@ all clients from it. Remember, a driver routines, a client structure specific information like the actual I2C address. - struct i2c_driver foo_driver - { - /* name */ "Foo version 2.3 and later driver", - /* id */ I2C_DRIVERID_FOO, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &foo_attach_adapter, - /* detach_client */ &foo_detach_client, - /* command */ &foo_command, /* May be NULL */ - /* inc_use */ &foo_inc_use, /* May be NULL */ - /* dec_use */ &foo_dec_use /* May be NULL */ + static struct i2c_driver foo_driver = { + .owner = THIS_MODULE, + .name = "Foo version 2.3 driver", + .id = I2C_DRIVERID_FOO, /* usually from i2c-id.h */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = &foo_attach_adapter, + .detach_client = &foo_detach_client, + .command = &foo_command /* may be NULL */ } The name can be chosen freely, and may be upto 40 characters long. Please @@ -50,43 +48,8 @@ This is almost always what you want. All other fields are for call-back functions which will be explained below. - -Module usage count -================== - -If your driver can also be compiled as a module, there are moments at -which the module can not be removed from memory. For example, when you -are doing a lengthy transaction, or when you create a /proc directory, -and some process has entered that directory (this last case is the -main reason why these call-backs were introduced). - -To increase or decrease the module usage count, you can use the -MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module -which needs to get its usage count changed; that is why each driver -module has to implement its own callback. - - void foo_inc_use (struct i2c_client *client) - { - #ifdef MODULE - MOD_INC_USE_COUNT; - #endif - } - - void foo_dec_use (struct i2c_client *client) - { - #ifdef MODULE - MOD_DEC_USE_COUNT; - #endif - } - -Do not call these call-back functions directly; instead, use one of the -following functions defined in i2c.h: - void i2c_inc_use_client(struct i2c_client *); - void i2c_dec_use_client(struct i2c_client *); - -You should *not* increase the module count just because a device is -detected and a client created. This would make it impossible to remove -an adapter driver! +There use to be two additional fields in this structure, inc_use et dec_use, +for module usage count, but these fields were obsoleted and removed. Extra client data diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/dump.txt linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/dump.txt --- linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/dump.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/dump.txt 2003-08-17 21:26:24.000000000 +0200 @@ -0,0 +1,364 @@ +Interaction between KDB and LKCD. + +Executive summary: Do not select CONFIG_KDB_CONTINUE_CATASTROPHIC=2 or +use KDB command 'sr c' without first patching LKCD to use KDB data. + +Both KDB and LKCD try to stop all the other cpus, so the system is not +changing while it is being debugged or dumped. KDB will cope with cpus +that cannot be stopped, some versions of LKCD will just hang. In +particular, when LKCD is invoked from KDB, LKCD will attempt to stop +the other cpus again and may hang. + +Some versions of LKCD detect that other cpus are not responding and +ignore them. This is almost as bad, the data is changing while it is +being dumped. Also the method used to avoid hung cpus has been known +to cause oops when LKCD has finished dumping. + +LKCD does not know about several special cases on IA64, including INIT +and MCA backtraces, interrupt handlers, out of line code etc. LKCD +cannot capture cpu state on any cpu that is not responding to OS +interrupts, which means that any cpu that is spinning in a disabled +loop cannot be debugged. Any cpu that calls into SAL for MCA +rendezvous cannot be debugged. Even when LKCD captures IA64 state, the +user space lcrash code cannot unwind through any assembler code, which +rules out all the interesting cases. + +KDB knows far more than LKCD about architecture peculiarities, stack +formats, interrupt handling etc. The methods used by KDB to stop the +other processors and capture their state are far more reliable than +those used by LKCD. KDB can capture INIT and MCA data on IA64, as well +as save the state of cpus before they enter SAL. + +Rather than duplicating the complex KDB code in LKCD, LKCD can be +patched to use the information that has already been captured by KDB. +Obviously this only works when LKCD is invoked from KDB. If you invoke +LKCD directly from the console with SysRq-c or the dump() function is +called from code outside KDB then you get the old and broken LKCD +processing. Because lcrash uses the old unwind algorithm which cannot +unwind through IA64 assembler code, KDB kludges the saved state into +something that the old unwind algorithm can cope with. Calling LKCD +from KDB gives you a clean dump, but you have to patch LKCD first. + +There are two ways to invoke LKCD from KDB. One way is manual, using +the KDB 'sr c' command. This is identical to doing SysRq-C from the +console except that it goes through KDB first, so LKCD can use the data +that KDB has captured. Obviously 'sr c' requires human intervention +and KDB must be on, it is up to the person doing the debugging if they +want to take a dump. + +The second way is to set CONFIG_KDB_CONTINUE_CATASTROPHIC=2. With this +setting, you automatically get a dump for catastrophic errors. A +catastrophic error is a panic, oops, NMI or other watchdog tripping, +INIT and MCA events on IA64. CONFIG_KDB_CONTINUE_CATASTROPHIC=2 has no +effect on debugging events such as break points, single step etc. so it +does not interfere with manual debugging. + +When CONFIG_KDB_CONTINUE_CATASTROPHIC=2 and KDB is on, a catastrophic +error will drop into KDB to allow manual debugging, typing 'go' will +take a dump and force a reboot. With this setting and KDB is off, KDB +detects a catastrophic error, does enough processing to capture the +state, takes a dump and forces a reboot - all automatic with no human +intervention. + +For unattended and clean LKCD dumps, patch LKCD to use KDB data. Use + CONFIG_DUMP=y + CONFIG_KDB=y + CONFIG_KDB_OFF=y + CONFIG_KDB_CONTINUE_CATASTROPHIC=2 + +If you want human intervention before taking a dump, use + CONFIG_DUMP=y + CONFIG_KDB=y + CONFIG_KDB_OFF=n + CONFIG_KDB_CONTINUE_CATASTROPHIC=2 + + +The following are indicative patches against lkcd 4.1, kernel 2.4.20. +You may have to to modify the patches for other kernels or other +versions of lkcd. + +diff -urp lkcd/drivers/dump/dump_base.c lkcd/drivers/dump/dump_base.c +--- lkcd/drivers/dump/dump_base.c Thu May 1 13:10:12 2003 ++++ lkcd/drivers/dump/dump_base.c Fri Jun 20 12:28:16 2003 +@@ -207,6 +207,9 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#endif + + /* + * ----------------------------------------------------------------------- +@@ -852,6 +855,13 @@ dump_silence_system(void) + unsigned int stage = 0; + int cpu = smp_processor_id(); + ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ /* kdb is in control, the system is already silenced */ ++ printk(KERN_ALERT "LKCD entered from KDB\n"); ++ } ++#endif /* CONFIG_KDB */ ++ + if (in_interrupt()) { + printk(KERN_ALERT "Dumping from interrupt handler !\n"); + printk(KERN_ALERT "Uncertain scenario - but will try my best\n"); +@@ -861,6 +871,9 @@ dump_silence_system(void) + * another approach + */ + } + /* see if there's something to do before we re-enable interrupts */ ++#ifdef CONFIG_KDB ++ if (!KDB_IS_RUNNING()) ++#endif /* CONFIG_KDB */ + (void)__dump_silence_system(stage); + +@@ -905,6 +918,9 @@ dump_silence_system(void) + + /* now increment the stage and do stuff after interrupts are enabled */ + stage++; ++#ifdef CONFIG_KDB ++ if (!KDB_IS_RUNNING()) ++#endif /* CONFIG_KDB */ + (void)__dump_silence_system(stage); + + /* time to leave */ +diff -urp lkcd/drivers/dump/dump_i386.c lkcd/drivers/dump/dump_i386.c +--- lkcd/drivers/dump/dump_i386.c Tue Jul 9 07:14:11 2002 ++++ lkcd/drivers/dump/dump_i386.c Fri Jun 20 12:29:12 2003 +@@ -27,6 +27,10 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include ++#endif /* CONFIG_KDB */ + + static int alloc_dha_stack(void) + { +@@ -119,6 +123,31 @@ save_other_cpu_states(void) + { + int i; + ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ /* invoked from kdb, which has already saved all the state */ ++ int cpu; ++ struct kdb_running_process *krp; ++ for (cpu = 0, krp = kdb_running_process; cpu < smp_num_cpus; ++cpu, ++krp) { ++ if (krp->seqno < kdb_seqno - 1 || ++ !krp->regs || ++ !krp->p || ++ kdb_process_cpu(krp->p) != cpu) { ++ printk(KERN_WARNING "No KDB data for cpu %d, it will not be in the LKCD dump\n", cpu); ++ continue; ++ } ++ if (cpu == smp_processor_id()) ++ continue; /* dumped by save_this_cpu_state */ ++ // kdb_printf("%s: cpu %d task %p regs %p\n", __FUNCTION__, cpu, krp->p, krp->regs); ++ save_this_cpu_state(cpu, krp->regs, krp->p); ++ } ++ return; ++ } ++ printk(KERN_WARNING "This kernel supports KDB but LKCD was invoked directly, not via KDB.\n"); ++ printk(KERN_WARNING "Falling back to the old and broken LKCD method of getting data from all cpus,\n"); ++ printk(KERN_WARNING "do not be surprised if LKCD hangs.\n"); ++#endif /* CONFIG_KDB */ ++ + if (smp_num_cpus > 1) { + atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1); + for (i = 0; i < NR_CPUS; i++) +diff -urp lkcd/drivers/dump/dump_ia64.c lkcd/drivers/dump/dump_ia64.c +--- lkcd/drivers/dump/dump_ia64.c Tue Jul 9 07:14:11 2002 ++++ lkcd/drivers/dump/dump_ia64.c Fri Jun 20 12:31:41 2003 +@@ -30,6 +30,10 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include ++#endif /* CONFIG_KDB */ + + extern unsigned long irq_affinity[]; + +@@ -75,6 +79,12 @@ save_this_cpu_state(int cpu, struct pt_r + + if (tsk && dump_header_asm.dha_stack[cpu]) { + memcpy((void*)dump_header_asm.dha_stack[cpu], tsk, THREAD_SIZE); ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ static void kludge_for_broken_lcrash(int); ++ kludge_for_broken_lcrash(cpu); ++ } ++#endif /* CONFIG_KDB */ + } + return; + } +@@ -107,6 +117,32 @@ save_other_cpu_states(void) + { + int i; + ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ /* invoked from kdb, which has already saved all the state */ ++ int cpu; ++ struct kdb_running_process *krp; ++ for (cpu = 0, krp = kdb_running_process; cpu < smp_num_cpus; ++cpu, ++krp) { ++ if (krp->seqno < kdb_seqno - 1 || ++ !krp->regs || ++ !krp->arch.sw || ++ !krp->p || ++ kdb_process_cpu(krp->p) != cpu) { ++ printk(KERN_WARNING "No KDB data for cpu %d, it will not be in the LKCD dump\n", cpu); ++ continue; ++ } ++ if (cpu == smp_processor_id()) ++ continue; /* dumped by save_this_cpu_state */ ++ // kdb_printf("%s: cpu %d task %p regs %p\n", __FUNCTION__, cpu, krp->p, krp->regs); ++ save_this_cpu_state(cpu, krp->regs, krp->p); ++ } ++ return; ++ } ++ printk(KERN_WARNING "This kernel supports KDB but LKCD was invoked directly, not via KDB.\n"); ++ printk(KERN_WARNING "Falling back to the old and broken LKCD method of getting data from all cpus,\n"); ++ printk(KERN_WARNING "do not be surprised if LKCD hangs.\n"); ++#endif /* CONFIG_KDB */ ++ + if (smp_num_cpus > 1) { + atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1); + for (i = 0; i < NR_CPUS; i++) +@@ -380,3 +416,131 @@ void * __dump_memcpy(void * dest, const + } + return(vp); + } ++ ++#ifdef CONFIG_KDB ++/* ++ * lcrash is broken. It incorrectly assumes that all tasks are blocked, it ++ * assumes that all code is built by gcc (and therefore it cannot unwind through ++ * assembler code), it assumes that there is only one pt_regs at the base of the ++ * stack (where user space entered the kernel). Dumping from kdb (or any ++ * interrupt context) breaks all those assumptions, resulting in a good dump ++ * that lcrash cannot get any useful backtraces from. ++ * ++ * The real fix is to correct lcrash, using libunwind. That is not going to ++ * happen any time soon, so this kludge takes the kdb data and reformats it to ++ * suit the broken lcrash code. The task state is unwound past the interrupt ++ * frame (pt_regs) before kdb, then a switch_stack is synthesized in place of ++ * the pt_regs, using the unwound data. ksp is changed to point to this ++ * switch_stack, making it look like the task is blocked with no interrupt. ++ * ++ * This will not work when the interrupt occurred in a leaf function, with no ++ * save of b0. But the old unwind code in lcrash cannot cope with that either, ++ * so no change. ++ */ ++ ++static inline void * ++kludge_copy_addr(int cpu, void *addr, struct task_struct *p) ++{ ++ return (char *)addr - (char *)p + (char *)(dump_header_asm.dha_stack[cpu]); ++} ++ ++static void ++kludge_for_broken_lcrash(int cpu) ++{ ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ struct task_struct *p, *p_copy; ++ struct switch_stack *sw, *sw_copy, *sw_new; ++ struct pt_regs *regs; ++ struct unw_frame_info info; ++ kdb_symtab_t symtab; ++ kdb_machreg_t sp; ++ int count, i; ++ char nat; ++ ++ if (krp->seqno < kdb_seqno - 1 || ++ !krp->regs || ++ user_mode(krp->regs) || ++ !krp->arch.sw || ++ !krp->p || ++ kdb_process_cpu(krp->p) != cpu) ++ return; ++ p = krp->p; ++ regs = krp->regs; ++ sw = krp->arch.sw; ++#if 0 ++ { ++ char buf[80]; ++ sprintf(buf, "btc %d\n", cpu); ++ kdb_parse(buf, regs); ++ } ++#endif ++ ++ unw_init_frame_info(&info, p, sw); ++ count = 0; ++ do { ++ unw_get_sp(&info, &sp); ++ // kdb_printf("sp 0x%lx regs 0x%lx\n", sp, regs); ++ } while (sp < (kdb_machreg_t)regs && unw_unwind(&info) >= 0 && count++ < 200); ++ if (count >= 200) { ++ printk(KERN_WARNING "Unwind for process %d on cpu %d looped\n", p->pid, cpu); ++ return; ++ } ++ ++ /* Must not touch the real stack data, kludge the data using the copies ++ * in dump_header_asm. ++ */ ++ p_copy = kludge_copy_addr(cpu, p, p); ++ sw_new = (struct switch_stack *)((u64)(regs + 1) + 16) - 1; ++ sw_copy = kludge_copy_addr(cpu, sw_new, p); ++ // kdb_printf("p_copy 0x%p sw_new 0x%p sw_copy 0x%p\n", p_copy, sw_new, sw_copy); ++ memset(sw_copy, 0, sizeof(*sw_copy)); ++ ++ sw_copy->caller_unat = sw->caller_unat; ++ unw_access_ar(&info, UNW_AR_FPSR, &sw_copy->ar_fpsr, 0); ++ for (i = 2; i <= 5; ++i) ++ unw_access_fr(&info, i, &sw_copy->f2 + i - 2, 0); ++ for (i = 10; i <= 31; ++i) ++ unw_access_fr(&info, i, &sw_copy->f10 + i - 10, 0); ++ for (i = 4; i <= 7; ++i) ++ unw_access_gr(&info, i, &sw_copy->r4 + i - 4, &nat, 0); ++ for (i = 0; i <= 5; ++i) ++ unw_access_br(&info, i, &sw_copy->b0 + i, 0); ++ sw_copy->ar_pfs = *info.cfm_loc; ++ unw_access_ar(&info, UNW_AR_LC, &sw_copy->ar_lc, 0); ++ unw_access_ar(&info, UNW_AR_UNAT, &sw_copy->ar_unat, 0); ++ unw_access_ar(&info, UNW_AR_RNAT, &sw_copy->ar_rnat, 0); ++ /* FIXME: unwind.c returns the original bspstore, not the value that ++ * matches the current unwind state. Calculate our own value for the ++ * modified bspstore. This should work but does not ++ * unw_access_ar(&info, UNW_AR_BSPSTORE, &sw_copy->ar_bspstore, 0); ++ */ ++ sw_copy->ar_bspstore = (unsigned long)ia64_rse_skip_regs((unsigned long *)info.bsp, (*info.cfm_loc >> 7) & 0x7f); ++ unw_access_pr(&info, &sw_copy->pr, 0); ++ ++ /* lcrash cannot unwind through the new spinlock contention code and it ++ * is too important a case to ignore. So the kludge extracts the ++ * calling IP before saving the data. ++ */ ++ if (kdbnearsym(regs->cr_iip, &symtab) && ++ strncmp(symtab.sym_name, "ia64_spinlock_contention", 24) == 0) ++ unw_get_rp(&info, &sw_copy->b0); ++ ++ p_copy->thread.ksp = (__u64)sw_new - 16; ++ dump_header_asm.dha_smp_regs[cpu] = *((struct pt_regs *)((unsigned long)p + THREAD_SIZE) - 1); ++#if 0 ++ { ++ /* debug. Destructive overwrite of task, then bt the result in kdb to ++ * validate the modified task. ++ */ ++ char buf[80]; ++ memcpy(p, p_copy, THREAD_SIZE); ++ krp->regs = NULL; ++ krp->arch.sw = sw_new; ++ sprintf(buf, "btc %d\n", cpu); ++ kdb_parse(buf, NULL); ++ while(1){}; ++ } ++#endif ++} ++ ++#endif /* CONFIG_KDB */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/kdb_bp.man linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/kdb_bp.man --- linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/kdb_bp.man 2003-05-03 01:53:59.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/kdb_bp.man 2003-08-17 21:26:24.000000000 +0200 @@ -1,4 +1,4 @@ -.TH BD 1 "17 January 2002" +.TH BD 1 "1 June 2003" .SH NAME bp, bpa, bph, bpha, bd, bc, be, bl \- breakpoint commands .SH SYNOPSIS @@ -6,9 +6,9 @@ bp \fIaddress-expression\fP .LP bpa \fIaddress-expression\fP .LP -bph \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +bph \fIaddress-expression\fP [\f(CWDATAR|DATAW|DATAA|IO\fP [\fIlength\fP]] .LP -bpha \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +bpha \fIaddress-expression\fP [\f(CWDATAR|DATAW|DATAA|IO\fP [\fIlength\fP]] .LP bd \fIbreakpoint-number\fP .LP @@ -52,7 +52,9 @@ Causes the kernel debugger to be entered \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. +breakpoints that may be established. On arm mode XScale platform +(thumb mode is not supported yet), +debugger is triggered by reading from the specified address. The \fBbph\fP or \fBbpha\fP commands must be used. .TP 8 @@ -63,14 +65,23 @@ to four bytes if it is not explicitly sp 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. +required. On arm mode XScale platform, the debugger is triggered +after having overwritten the specified address. 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. +commands must be used. This type of breakpoint is not valid in +arm mode XScale platform. This option is not valid in arm +mode XScale platform. + +.TP 8 +DATAA +Enters the kernel debugger after the data in specified address has +been accessed (read or write), this option is only used in arm +mode XScale platform. .P The @@ -106,6 +117,9 @@ breakpoints that can be set. .IP ix86 8 Four. .PD 0 +.IP xscale 8 +Two for insruction breakpoints and another two for data breakpoint. +.PD 0 .IP ia64 8 ? .PD 0 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/kdb_bt.man linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/kdb_bt.man --- linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/kdb_bt.man 2003-05-05 20:04:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/kdb_bt.man 2003-08-17 21:26:24.000000000 +0200 @@ -1,4 +1,4 @@ -.TH BT 1 "16 March 2003" +.TH BT 1 "20 July 2003" .SH NAME bt \- Stack Traceback command .SH SYNOPSIS @@ -10,7 +10,7 @@ btt .LP bta [ DRSTZU ] .LP -btc +btc [] .SH DESCRIPTION .hy 0 The @@ -75,10 +75,11 @@ Unrunnable. .PD 1 .P The \fBbtc\fP command will analyze the stack for the current process on -each cpu. +a specified cpu or, if no cpu number is supplied, for the current +process on all cpus. It does not switch to the other cpus, instead it uses the task structures to identify and issue \fBbtt\fR against the current task on -each cpu. +the desired cpus. .P For each function, the stack trace prints at least two lines. The first line contains four or five fields\ :- diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/kdb_rd.man linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/kdb_rd.man --- linux-2.4.20-wolk4.6-fullkernel/Documentation/kdb/kdb_rd.man 2003-05-03 01:53:59.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Documentation/kdb/kdb_rd.man 2003-08-17 21:26:24.000000000 +0200 @@ -1,8 +1,8 @@ -.TH RD 1 "17 January 2002" +.TH RD 1 "1 June 2003" .SH NAME rd, rm\- Register manipulation commands .SH SYNOPSIS -rd [c|d|u] +rd [[c [n]]|d|u] .LP rm \fIregister-name\fP \fInew-contents\fP .LP @@ -10,17 +10,24 @@ ef
.SH DESCRIPTION The .B rd -command is used to display the contents of processor registers. +command is used to display the contents of processor and coprocessor 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. +was entered. 'n' argumnet is only used for XScale platform to identify +the want coprocessor number, while 'd' option is not valid for XScale platform. .P -With the 'c' argument, the processor control registers +On IA32 and IA64, 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 +On XScale, 'c' argument is used to display the +all coprocessor control registers or specified coprocessor registers by +argumnet 'n'. Argument 'u' is used to display the +registers for the current task as of the last time the current task +entered the kernel. Argument 'd' is not supported. +.P On ix86, the .B rm command allows modification of a register. The following @@ -45,6 +52,16 @@ convenience names are provided: \fB%® address on the stack of the current registers, and \fB%csp\fP shows the current stack pointer within kdb itself. .P +While on XScale, both the cpu registers and most coprocessor +registers can be be modified. \fIregister-name\fP can be followings like +r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, +r15, cpsr to address cpu registers. For the coprocessor registers in XSacle, +either alias name or \fICpcc[CRndd[CRmbb[Opaa]]]\fP can be used to address +the register in coprocessor cc with CRn=dd, CRm=bb and opcode2=aa. All aa, bb, cc, dd can be +1 or 2 decimal digitals, the default value is 0 when any of them is omitted. Name +acc0_h and acc0_l are used to identify the high byte and +low word of accumulator in coprocessor 0. +.P The .B ef command displays an exception frame at the specified address. @@ -65,6 +82,10 @@ rd Display general register set. .TP 8 +rd c 0 +Display coprocessor 0 registers. + +.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 @@ -77,5 +98,17 @@ be the value the user-mode application w from the kernel. .TP 8 +rm %acc0_h 0 +Set the contents of high byte of accumulator to zero. + +.TP 8 rm dr0 0xc1287220 Set the value of the \fBdr0\fB register to \f(CW0xc1287220\fP. + +.TP 8 +rm %InVLD_BTB 0 +Write 0 to coprocessor 15 register with CRn=7, CRm=5, opcode2=6. + +.TP 8 +rm %CP15CRn7CRm5Op6 0 +Same with above. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/MAINTAINERS linux-2.4.20-wolk4.7-fullkernel/MAINTAINERS --- linux-2.4.20-wolk4.6-fullkernel/MAINTAINERS 2003-08-04 23:06:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/MAINTAINERS 2003-08-17 21:30:36.000000000 +0200 @@ -575,13 +575,6 @@ L: emu10k1-devel@lists.sourceforge.net W: http://sourceforge.net/projects/emu10k1/ S: Maintained -ENTERPRISE VOLUME MANAGEMENT SYSTEM (EVMS) -P: Mark Peloquin, Steve Pratt, Kevin Corry -M: peloquin@us.ibm.com, slpratt@us.ibm.com, corryk@us.ibm.com -L: evms-devel@lists.sourceforge.net -W: http://www.sourceforge.net/projects/evms/ -S: Supported - ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell M: Philip.Blundell@pobox.com diff -Naurp linux-2.4.20-wolk4.6-fullkernel/Makefile linux-2.4.20-wolk4.7-fullkernel/Makefile --- linux-2.4.20-wolk4.6-fullkernel/Makefile 2003-08-17 21:04:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/Makefile 2003-08-17 21:31:39.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = -wolk4.6s +EXTRAVERSION = -wolk4.7s KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -103,7 +103,6 @@ export MODLIB # CPPFLAGS := -D__KERNEL__ -I$(HPATH) -CPPFLAGS += $(patsubst %,-I%,$(CROSS_COMPILE_INC)) CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common -Wno-unused \ @@ -240,7 +239,6 @@ DRIVERS-$(CONFIG_GSC) += drivers/gsc/gsc DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o -DRIVERS-$(CONFIG_EVMS) += drivers/evms/evmsdrvr.o DRIVERS-$(CONFIG_DXR3) += drivers/media/em8300/dxr3.o DRIVERS-$(CONFIG_SENSORS) += drivers/sensors/sensor.o DRIVERS := $(DRIVERS-y) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/VERSION linux-2.4.20-wolk4.7-fullkernel/VERSION --- linux-2.4.20-wolk4.6-fullkernel/VERSION 2003-08-17 21:04:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/VERSION 2003-08-17 21:31:24.000000000 +0200 @@ -1 +1 @@ -WOLK v4.6s "Server Edition" FINAL, based on 2.4.20 +WOLK v4.7s "Server Edition" FINAL, based on 2.4.20 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/WOLK-CHANGELOG linux-2.4.20-wolk4.7-fullkernel/WOLK-CHANGELOG --- linux-2.4.20-wolk4.6-fullkernel/WOLK-CHANGELOG 2003-08-17 21:04:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/WOLK-CHANGELOG 2003-08-17 22:28:14.000000000 +0200 @@ -1,3 +1,37 @@ +Changelog from v4.6s -> v4.7s +----------------------------- ++ added: shfs v0.32-pre1 +o added: new CPU capabilites for recent cpu's +o added: Intel/AMD/VIA HW Random Number Generator support +o added: Deny promiscuous mode for interfaces +o added: WRR packet scheduler +o fixed: ptrace swap race +o fixed: steal_locks: we should be in full LSB compliance now +o fixed: nbd: multiple race conditions +o fixed: nbd: race conditions and various other deadlocks +o fixed: beyond_eof check in generic_direct_IO +o fixed: reiserfs: some issues with extended inode attributes +o fixed: ext3fs: ext3_read_inode() race fix +o fixed: ext3fs: missing TASK_RUNNING in jbd transaction code +o fixed: ext3fs: handle aborted journals +o fixed: v4l2: wrong poll_table usage. We have epoll too. +o fixed: RMAP: OOM killer braindamage fix fix fix fix + (yes, it's the 4th fix fix ;) and it _works_ now! +o updated: IPVS v1.0.10 +o updated: rsbac v1.2.2 +o updated: DRBD v0.6.6 +o updated: grsec: tons of PaX updates/fixes +o updated: XFS v1.3.0-pre5 +o updated: kdb v4.3 +o updated: EVMS v2.1.0 +o updated: q->full revision 2 +o updated: i2c v2.8.0 Final +o updated: lmsensors v2.8.0 Final +o updated: CIFS v0.8.7 +o removed: EVMS v1.x code +o changed: Make 'PS/2 keyboard support' an option + + Changelog from v4.5s -> v4.6s ----------------------------- o fixed: BUG() while booting (missing brackets :pp) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/WOLK-README linux-2.4.20-wolk4.7-fullkernel/WOLK-README --- linux-2.4.20-wolk4.6-fullkernel/WOLK-README 2003-08-17 21:04:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/WOLK-README 2003-08-17 22:28:31.000000000 +0200 @@ -1,4 +1,4 @@ -Kernel - patched - WOLK v4.6s - Base: Linux kernel 2.4.20 +Kernel - patched - WOLK v4.7s - Base: Linux kernel 2.4.20 located at http://sf.net/projects/wolk by Marc-Christian Petersen -------------------------------------------------------------------------- diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/all/Config-SECURITY.in linux-2.4.20-wolk4.7-fullkernel/arch/all/Config-SECURITY.in --- linux-2.4.20-wolk4.6-fullkernel/arch/all/Config-SECURITY.in 2003-05-03 02:37:26.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/all/Config-SECURITY.in 2003-08-17 21:31:45.000000000 +0200 @@ -39,6 +39,10 @@ if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86 fi +# Deny promiscuous mode for interfaces +bool 'Deny promiscuous mode for interfaces' CONFIG_NOPROMISC +dep_bool ' Kill promiscuous processes and their parents' CONFIG_NOPROMISC_KILL $CONFIG_NOPROMISC + # Encrypted Virtual File System (EVFS) dep_tristate 'Encrypted Virtual File System (EVFS)' CONFIG_EVFS_FS $CONFIG_EXPERIMENTAL diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/alpha/config.in linux-2.4.20-wolk4.7-fullkernel/arch/alpha/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/alpha/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/alpha/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -3,9 +3,6 @@ # see Documentation/kbuild/config-language.txt. # -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_ALPHA y define_bool CONFIG_UID16 n define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/alpha/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/alpha/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/alpha/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/alpha/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -801,12 +801,3 @@ CONFIG_DEBUG_KERNEL=y CONFIG_MATHEMU=y # CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/arm/config.in linux-2.4.20-wolk4.7-fullkernel/arch/arm/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/arm/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/arm/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -4,9 +4,6 @@ # mainmenu_name "Linux Kernel Configuration" -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_ARM y define_bool CONFIG_EISA n define_bool CONFIG_SBUS n diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/arm/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/arm/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/arm/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/arm/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -515,12 +515,3 @@ CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_LL=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/cris/config.in linux-2.4.20-wolk4.7-fullkernel/arch/cris/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/cris/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/cris/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -4,9 +4,6 @@ # mainmenu_name "Linux/CRIS Kernel Configuration" -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/cris/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/cris/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/cris/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/cris/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -520,12 +520,3 @@ CONFIG_MSDOS_PARTITION=y # Kernel hacking # # CONFIG_PROFILE is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/config.in linux-2.4.20-wolk4.7-fullkernel/arch/i386/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/config.in 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/config.in 2003-08-17 21:31:30.000000000 +0200 @@ -4,9 +4,6 @@ # mainmenu_name "Linux Kernel Configuration" -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_X86 y define_bool CONFIG_SBUS n @@ -582,8 +579,6 @@ source drivers/pnp/Config.in source drivers/block/Config.in -source drivers/evms/Config.in - source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then @@ -728,6 +723,7 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; th dep_tristate ' KDB modules' CONFIG_KDB_MODULES $CONFIG_KDB if [ "$CONFIG_KDB" = "y" ]; then bool ' KDB off by default' CONFIG_KDB_OFF + int ' KDB continues after catastrophic errors' CONFIG_KDB_CONTINUE_CATASTROPHIC 0 if [ "$CONFIG_USB" != "n" ] ; then bool ' Support for USB Keyboard in KDB' CONFIG_KDB_USB fi diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/i386/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/defconfig 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/defconfig 2003-08-17 21:31:47.000000000 +0200 @@ -1,7 +1,6 @@ # # Automatically generated by make menuconfig: don't edit # -O1_SCHEDULER=y CONFIG_X86=y # CONFIG_SBUS is not set CONFIG_UID16=y @@ -60,28 +59,27 @@ CONFIG_X86_MCE=y # CPU Frequency scaling # # CONFIG_CPU_FREQ is not set -# CONFIG_TOSHIBA is not set -# CONFIG_I8K is not set -# CONFIG_THINKPAD is not set + +# +# Laptop support +# +# CONFIG_LAPTOP is not set # CONFIG_MICROCODE is not set # CONFIG_X86_MSR is not set # CONFIG_X86_CPUID is not set +# CONFIG_VIA_NORTHBRIDGE_FIXUP is not set # CONFIG_EDD is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set # CONFIG_HIGHMEM is not set -CONFIG_FORCE_MAX_ZONEORDER=11 -CONFIG_1GB=y -# CONFIG_2GB is not set -# CONFIG_3GB is not set -# CONFIG_05GB is not set # CONFIG_SBFSPEC is not set # CONFIG_MATH_EMULATION is not set CONFIG_MTRR=y # CONFIG_BIGPHYS_AREA is not set # CONFIG_SMP is not set CONFIG_X86_UP_APIC=y +# CONFIG_X86_UP_APIC_ERRORS is not set CONFIG_X86_UP_IOAPIC=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y @@ -97,18 +95,18 @@ CONFIG_HAVE_DEC_LOCK=y # CONFIG_BADMEM is not set # -# Scheduler, Low Latency, Preempt - Tweaks +# Scheduler, Low Latency, Preempt, Elevator # CONFIG_MAX_USER_RT_PRIO=100 CONFIG_MAX_RT_PRIO=0 -CONFIG_HZ=100 -CONFIG_LOLAT=y -# CONFIG_LOLAT_SYSCTL is not set -# CONFIG_BLK_DEV_ELEVATOR_LOWLAT is not set +CONFIG_HZ=200 +CONFIG_BLK_DEV_ELEVATOR_NORMAL=y CONFIG_PREEMPT=y +# CONFIG_PREEMPT_WARN is not set CONFIG_MEMORYPOOL=y +# CONFIG_GCC_OPTIMIZATION1 is not set # CONFIG_NO_OOM is not set -CONFIG_SCHED_SERVER=y +CONFIG_SCHED_DESKTOP=y # # General setup @@ -121,7 +119,7 @@ CONFIG_PCI=y CONFIG_PCI_GOANY=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y -CONFIG_ISA=y +# CONFIG_ISA is not set CONFIG_PCI_NAMES=y # CONFIG_EISA is not set # CONFIG_MCA is not set @@ -129,13 +127,13 @@ CONFIG_PCI_NAMES=y # CONFIG_PCMCIA is not set # CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_MISC=m # # Power Management support @@ -154,7 +152,9 @@ CONFIG_APM_DISPLAY_BLANK=y # # ACPI Support # -# CONFIG_ACPI is not set +CONFIG_ACPI=y +CONFIG_ACPI_HT_ONLY=y +CONFIG_ACPI_BOOT=y # CONFIG_VTUNE is not set # @@ -165,12 +165,19 @@ CONFIG_APM_DISPLAY_BLANK=y # # Parallel port support # -# CONFIG_PARPORT is not set - -# -# Rule Set Based Access Control (RSBAC) -# -# CONFIG_RSBAC is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +# CONFIG_PARPORT_SERIAL is not set +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_SUPERIO=y +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y # # Plug and Play configuration @@ -181,54 +188,41 @@ CONFIG_APM_DISPLAY_BLANK=y # # Block devices # -CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_FD=m # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set # CONFIG_CDROM_PKTCDVD is not set CONFIG_BLK_DEV_LOOP=m -# CONFIG_CIPHER_TWOFISH_LOOP is not set +CONFIG_CIPHER_TWOFISH_LOOP=m +CONFIG_BLK_DEV_CLOOP=m # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_DRBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_STATS is not set # -# Enterprise Volume Management System (EVMS) -# -# CONFIG_EVMS is not set -# CONFIG_EVMS_LOCAL_DEV_MGR is not set -# CONFIG_EVMS_DOS_SEGMENT_MGR is not set -# CONFIG_EVMS_GPT_SEGMENT_MGR is not set -# CONFIG_EVMS_SNAPSHOT is not set -# CONFIG_EVMS_DRIVELINK is not set -# CONFIG_EVMS_BBR is not set -# CONFIG_EVMS_LVM is not set -# CONFIG_EVMS_MD is not set -# CONFIG_EVMS_MD_LINEAR is not set -# CONFIG_EVMS_MD_RAID0 is not set -# CONFIG_EVMS_MD_RAID1 is not set -# CONFIG_EVMS_MD_RAID5 is not set -# CONFIG_EVMS_AIX is not set -# CONFIG_EVMS_OS2 is not set - -# # Multi-device support (RAID and LVM) # -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set -# CONFIG_BLK_DEV_DM is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_LVM=m +CONFIG_BLK_DEV_DM=m +CONFIG_MEMORYPOOL=y +CONFIG_BLK_DEV_DM_BBR=m +CONFIG_BLK_DEV_DM_SPARSE=m # # Networking options @@ -243,33 +237,151 @@ CONFIG_UNIX=y CONFIG_UNIX_MAX_SOCKETS=16384 CONFIG_INET=y # CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_IP_NMAP_FREAK_PATCH is not set -# CONFIG_NET_STEALTH is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y +CONFIG_IP_NMAP_FREAK_PATCH=y +CONFIG_NET_STEALTH=y +CONFIG_NET_STEALTH_LOG=y # # IP: Netfilter Configuration # -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_ARPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_H323=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_QUOTA=m +CONFIG_IP_NF_POOL=m +# CONFIG_IP_POOL_STATISTICS is not set +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_MPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TIME=m +CONFIG_IP_NF_MATCH_RANDOM=m +CONFIG_IP_NF_MATCH_PSD=m +CONFIG_IP_NF_MATCH_NTH=m +CONFIG_IP_NF_MATCH_IPV4OPTIONS=m +CONFIG_IP_NF_MATCH_FUZZY=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STEALTH=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_IPLIMIT=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_STRING=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_PRIO_ACCEPTQ=y +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_NETLINK=m +CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_TARGET_TARPIT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_NAT_H323=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_IMQ=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y # CONFIG_IP_NF_COMPAT_IPFWADM is not set # +# IP: NF-HIPAC Configuration +# +CONFIG_IP_NF_HIPAC=m +CONFIG_IP_NF_HIPAC_CTHELP=m + +# # IP: Virtual Server Configuration # -# CONFIG_IP_VS is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_DEBUG=y +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m # CONFIG_PSEUDO_ACLS is not set -# CONFIG_CIPE is not set -# CONFIG_IPV6 is not set +CONFIG_CIPE=m +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_TARGET_IMQ=m # # Kernel Web Servers @@ -278,14 +390,32 @@ CONFIG_INET=y # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set # CONFIG_IPX is not set -# CONFIG_ATALK is not set +CONFIG_ATALK=m # # Appletalk devices # -# CONFIG_DEV_APPLETALK is not set +CONFIG_DEV_APPLETALK=y +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y # CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_IPF is not set +# CONFIG_BRIDGE_EBT_ARPF is not set +# CONFIG_BRIDGE_EBT_VLANF is not set +# CONFIG_BRIDGE_EBT_MARKF is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set @@ -298,7 +428,30 @@ CONFIG_INET=y # # QoS and/or fair queueing # -# CONFIG_NET_SCHED is not set +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_WRR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y # # Network testing @@ -308,7 +461,30 @@ CONFIG_INET=y # # IP Security Protocol (FreeS/WAN IPSEC) # -# CONFIG_IPSEC is not set +CONFIG_IPSEC=m +CONFIG_IPSEC_IPIP=y +CONFIG_IPSEC_AH=y +CONFIG_IPSEC_AUTH_HMAC_MD5=y +CONFIG_IPSEC_AUTH_HMAC_SHA1=y +CONFIG_IPSEC_ESP=y +CONFIG_IPSEC_ENC_3DES=y +CONFIG_IPSEC_ALG=y +CONFIG_IPSEC_ALG_MD5=m +CONFIG_IPSEC_ALG_SHA1=m +CONFIG_IPSEC_ALG_SHA2=m +CONFIG_IPSEC_ALG_3DES=m +CONFIG_IPSEC_ALG_AES=m +CONFIG_IPSEC_ALG_BLOWFISH=m +CONFIG_IPSEC_ALG_TWOFISH=m +CONFIG_IPSEC_ALG_SERPENT=m +CONFIG_IPSEC_ALG_CAST=m +# CONFIG_IPSEC_ALG_NULL is not set +CONFIG_IPSEC_ALG_CRYPTOAPI=m +CONFIG_IPSEC_ALG_NON_LIBRE=y +# CONFIG_IPSEC_ALG_1DES is not set +CONFIG_IPSEC_IPCOMP=y +CONFIG_IPSEC_DEBUG=y +CONFIG_IPSEC_NAT_TRAVERSAL=y # # Network device support @@ -320,10 +496,10 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set -# CONFIG_BONDING is not set +CONFIG_BONDING=m # CONFIG_EQUALIZER is not set -# CONFIG_IMQ is not set -# CONFIG_TUN is not set +CONFIG_IMQ=m +CONFIG_TUN=m # CONFIG_ETHERTAP is not set # @@ -335,35 +511,66 @@ CONFIG_NET_ETHERNET=y # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set # CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=m +CONFIG_BC90X=m +CONFIG_TYPHOON=m # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_PCNET32_OLD is not set +# CONFIG_NET_AMD8111 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_NET_BCM4400 is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +CONFIG_8139TOO_TUNE_TWISTER=y +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_SIS900_OLD is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -CONFIG_NET_GIGABIT_ETH=y -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_NETGEAR_GA621 is not set -# CONFIG_NETGEAR_GA622 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_SK9DLIN is not set -# CONFIG_NET_BROADCOM is not set -# CONFIG_TIGON3 is not set +# CONFIG_NET_GIGABIT_ETH is not set # CONFIG_FDDI is not set -# CONFIG_NETCONSOLE is not set +CONFIG_NETCONSOLE=m # CONFIG_HIPPI is not set # CONFIG_PLIP is not set # CONFIG_SLIP is not set @@ -371,12 +578,35 @@ CONFIG_NET_GIGABIT_ETH=y # # PPP (point-to-point protocol) support # -# CONFIG_PPP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m # # Wireless LAN (non-hamradio) # -# CONFIG_NET_RADIO is not set +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WL2400 is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m +CONFIG_HOSTAP=m +CONFIG_PLX_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_NET_WIRELESS=y # # Token Ring devices @@ -384,7 +614,7 @@ CONFIG_NET_GIGABIT_ETH=y # CONFIG_TR is not set # CONFIG_NET_FC is not set # CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set +CONFIG_SHAPER=m # # Wan interfaces @@ -422,17 +652,17 @@ CONFIG_IDEDISK_MULTI_MODE=y # CONFIG_BLK_DEV_COMMERIAL is not set # CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set -CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDESCSI=m # CONFIG_IDE_TASK_IOCTL is not set -# CONFIG_IDE_TASKFILE_IO is not set +CONFIG_IDE_TASKFILE_IO=y # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set CONFIG_BLK_DEV_IDEPCI=y -CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_SHARE_IRQ is not set CONFIG_BLK_DEV_IDEDMA_PCI=y CONFIG_BLK_DEV_OFFBOARD=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set @@ -460,9 +690,9 @@ CONFIG_BLK_DEV_PIIX=y CONFIG_PIIX_TUNING=y # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC202XX is not set -# CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_PDC202XX=y +CONFIG_PDC202XX_BURST=y +CONFIG_PDC202XX_FORCE=y # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIS5513 is not set @@ -471,11 +701,11 @@ CONFIG_PIIX_TUNING=y # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y -CONFIG_IDEDMA_IVB=y +# CONFIG_IDEDMA_IVB is not set # CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set +CONFIG_BLK_DEV_ATARAID=m +CONFIG_BLK_DEV_ATARAID_PDC=m # CONFIG_BLK_DEV_ATARAID_HPT is not set # @@ -484,13 +714,14 @@ CONFIG_BLK_DEV_IDE_MODES=y CONFIG_SCSI=m CONFIG_BLK_DEV_SD=m CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set +CONFIG_CHR_DEV_ST=m # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m -# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 # CONFIG_CHR_DEV_SCH is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SM is not set CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y @@ -498,61 +729,7 @@ CONFIG_SCSI_LOGGING=y # # SCSI low-level drivers # -CONFIG_SCSI_LOWLEVEL=y -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AACRAID is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_MEGARAID2 is not set -# CONFIG_SCSI_ISCSI is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2XXX is not set -# CONFIG_SCSI_NEWISP is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC395x_TRMS1040 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_LOWLEVEL is not set # # Fusion MPT device support @@ -566,7 +743,17 @@ CONFIG_SCSI_LOWLEVEL=y # # IEEE 1394 (FireWire) support (EXPERIMENTAL) # -# CONFIG_IEEE1394 is not set +CONFIG_IEEE1394=m +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m +# CONFIG_IEEE1394_VERBOSEDEBUG is not set # # I2O device support @@ -591,19 +778,95 @@ CONFIG_SCSI_LOWLEVEL=y # # ISDN subsystem # -# CONFIG_ISDN is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set +CONFIG_ISDN=m +CONFIG_ISDN_BOOL=y +CONFIG_ISDN_PPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_LZSCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DIVERSION is not set + +# +# Passive ISDN cards +# +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_HISAX=y +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_1TR6 is not set +# CONFIG_HISAX_NI1 is not set +CONFIG_HISAX_MAX_CARDS=8 +# CONFIG_HISAX_TELESPCI is not set +# CONFIG_HISAX_S0BOX is not set +# CONFIG_HISAX_FRITZPCI is not set +# CONFIG_HISAX_AVM_A1_PCMCIA is not set +# CONFIG_HISAX_ELSA is not set +# CONFIG_HISAX_DIEHLDIVA is not set +# CONFIG_HISAX_SEDLBAUER is not set +# CONFIG_HISAX_NETJET is not set +# CONFIG_HISAX_NETJET_U is not set +# CONFIG_HISAX_NICCY is not set +# CONFIG_HISAX_BKM_A4T is not set +# CONFIG_HISAX_SCT_QUADRO is not set +# CONFIG_HISAX_GAZEL is not set +# CONFIG_HISAX_HFC_PCI is not set +# CONFIG_HISAX_W6692 is not set +# CONFIG_HISAX_HFC_SX is not set +# CONFIG_HISAX_ENTERNOW_PCI is not set +# CONFIG_HISAX_DEBUG is not set +# CONFIG_HISAX_SEDLBAUER_CS is not set +# CONFIG_HISAX_ELSA_CS is not set +# CONFIG_HISAX_AVM_A1_CS is not set +# CONFIG_HISAX_ST5481 is not set +CONFIG_HISAX_FRITZ_PCIPNP=m + +# +# Active ISDN cards +# +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_EICON is not set +# CONFIG_ISDN_DRV_TPAM is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m +# CONFIG_ISDN_DRV_AVMB1_B1ISA is not set +# CONFIG_ISDN_DRV_AVMB1_B1PCI is not set +# CONFIG_ISDN_DRV_AVMB1_B1PCIV4 is not set +# CONFIG_ISDN_DRV_AVMB1_T1ISA is not set +# CONFIG_ISDN_DRV_AVMB1_B1PCMCIA is not set +# CONFIG_ISDN_DRV_AVMB1_AVM_CS is not set +# CONFIG_ISDN_DRV_AVMB1_T1PCI is not set +# CONFIG_ISDN_DRV_AVMB1_C4 is not set +# CONFIG_HYSDN is not set +# CONFIG_HYSDN_CAPI is not set # # Input core support # -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set @@ -611,18 +874,22 @@ CONFIG_SCSI_LOWLEVEL=y # Character devices # CONFIG_VT=y -# CONFIG_ECC is not set +CONFIG_ECC=m CONFIG_VT_CONSOLE=y CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +# CONFIG_PPDEV is not set # # I2C support # # CONFIG_I2C is not set +CONFIG_PSKEYBOARD=y # # Mice @@ -638,6 +905,32 @@ CONFIG_PSMOUSE=y # Joysticks # # CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set # CONFIG_QIC02_TAPE is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_IPMI_PANIC_EVENT is not set @@ -648,13 +941,39 @@ CONFIG_PSMOUSE=y # # Watchdog Cards # -# CONFIG_WATCHDOG is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_WAFER_WDT is not set +CONFIG_I810_TCO=m +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_SCx200_WDT is not set +CONFIG_SOFT_WATCHDOG=m +# CONFIG_W83877F_WDT is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_AMD7XX_TCO is not set +# CONFIG_DEADMAN is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_HANGCHECK_COMP is not set +# CONFIG_HANGCHECK_THREAD is not set +# CONFIG_HANGCHECK_DELAY is not set # CONFIG_SCx200_GPIO is not set # CONFIG_AMD_RNG is not set -# CONFIG_INTEL_RNG is not set +CONFIG_INTEL_RNG=m +# CONFIG_HW_RANDOM is not set # CONFIG_AMD_PM768 is not set # CONFIG_NVRAM is not set -# CONFIG_RTC is not set +CONFIG_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -668,38 +987,68 @@ CONFIG_PSMOUSE=y CONFIG_AGP=m CONFIG_AGP_INTEL=y CONFIG_AGP_I810=y -CONFIG_AGP_VIA=y -CONFIG_AGP_AMD=y -CONFIG_AGP_AMD_8151=y -CONFIG_AGP_SIS=y -CONFIG_AGP_ALI=y +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_AMD_8151 is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_SWORKS is not set CONFIG_AGP_NVIDIA=y -CONFIG_AGP_SWORKS=y # # Direct Rendering Manager (XFree86 DRI support) # -# CONFIG_DRM is not set +CONFIG_DRM=y +CONFIG_DRM_43=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_GAMMA is not set +CONFIG_DRM_R128=m +# CONFIG_DRM_RADEON is not set +CONFIG_DRM_I810=m +# CONFIG_DRM_I830 is not set +# CONFIG_DRM_MGA is not set # CONFIG_MWAVE is not set -# CONFIG_PROCINFO is not set +# CONFIG_BATTERY_GERICOM is not set +CONFIG_PROCINFO=m # CONFIG_IBMASM is not set # # Multimedia devices # -# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_W9966 is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set # -# DXR3 / H+ +# Radio Adapters # -# CONFIG_EM8300 is not set -# CONFIG_EM8300_DICOMFIX is not set -# CONFIG_EM8300_DICOMCTRL is not set -# CONFIG_EM8300_DICOMPAL is not set -# CONFIG_ADV717X is not set -# CONFIG_ADV717X_PIXELPORT16BIT is not set -# CONFIG_ADV717X_PIXELPORTPAL is not set -# CONFIG_BT865 is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set + +# +# Hollywood Plus / DXR3 support +# +# CONFIG_DXR3 is not set # # *_vid drivers @@ -711,26 +1060,29 @@ CONFIG_AGP_SWORKS=y # # File systems # -# CONFIG_QUOTA is not set -# CONFIG_QFMT_V1 is not set -# CONFIG_QFMT_V2 is not set -# CONFIG_QIFACE_COMPAT is not set +CONFIG_QUOTA=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QIFACE_COMPAT=y +CONFIG_QIFACE_V1=y +# CONFIG_QIFACE_V2 is not set # CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=m # CONFIG_TRUSTEES is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m # CONFIG_BEFS_FS is not set # CONFIG_BEFS_DEBUG is not set # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set +CONFIG_FAT_FS=m # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set +CONFIG_CRAMFS=y CONFIG_TMPFS=y CONFIG_RAMFS=y CONFIG_ISO9660_FS=m @@ -739,12 +1091,14 @@ CONFIG_ZISOFS=y # CONFIG_CD_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set +CONFIG_NTFS_FS=m # CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_PROC_CONFIG=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set @@ -754,38 +1108,40 @@ CONFIG_DEVPTS_FS=y # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set # CONFIG_BADFS_FS is not set +CONFIG_LUFS_FS=m # # VFS settings # CONFIG_FILE_SOFT=8192 CONFIG_FILE_HARD=65536 -CONFIG_FILE_RESERVED=128 +CONFIG_FILE_RESERVED=256 # # Journalling File Systems # # CONFIG_JFFS_FS is not set # CONFIG_JFFS2_FS is not set -# CONFIG_REISERFS_FS is not set +CONFIG_REISERFS_FS=m # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set CONFIG_EXT3_FS=y CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set +CONFIG_EXT3_INDEX=y # CONFIG_EXT3_FS_LAPTOP is not set # CONFIG_JFS_FS is not set # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set -# CONFIG_XFS_FS is not set -# CONFIG_XFS_POSIX_ACL is not set +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y # CONFIG_XFS_RT is not set -# CONFIG_XFS_QUOTA is not set +CONFIG_XFS_QUOTA=y # CONFIG_XFS_DMAPI is not set # CONFIG_XFS_DEBUG is not set # CONFIG_PAGEBUF_DEBUG is not set @@ -805,7 +1161,7 @@ CONFIG_NFSD_TCP=y CONFIG_SUNRPC=m CONFIG_LOCKD=m CONFIG_LOCKD_V4=y -# CONFIG_CIFS is not set +CONFIG_CIFS=m CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT is not set # CONFIG_NCP_FS is not set @@ -817,10 +1173,16 @@ CONFIG_SMB_FS=m # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set -# CONFIG_OCFS_FS is not set +CONFIG_OCFS_FS=m # CONFIG_AFS_FS is not set -# CONFIG_FTP_FS is not set +CONFIG_FTP_FS=m +CONFIG_SH_FS=m +CONFIG_SH_FS_DEBUG0=y +# CONFIG_SH_FS_DEBUG1 is not set +# CONFIG_SH_FS_DEBUG2 is not set +# CONFIG_SH_FS_DEBUG3 is not set CONFIG_ZISOFS_FS=m +CONFIG_FS_MBCACHE=y # # Partition Types @@ -834,11 +1196,11 @@ CONFIG_NLS=y # Native Language Support # CONFIG_NLS_DEFAULT="iso8859-15" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set # CONFIG_NLS_CODEPAGE_860 is not set @@ -857,7 +1219,7 @@ CONFIG_NLS_DEFAULT="iso8859-15" # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -867,10 +1229,10 @@ CONFIG_NLS_DEFAULT="iso8859-15" # CONFIG_NLS_ISO8859_9 is not set # CONFIG_NLS_ISO8859_13 is not set # CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set +CONFIG_NLS_UTF8=y # # Console drivers @@ -883,17 +1245,172 @@ CONFIG_VIDEO_SELECT=y # # Frame-buffer support # -# CONFIG_FB is not set +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y # -# Sound support +# Frame Buffer Boot Logos (FBBL) # -# CONFIG_SOUND_WOLK is not set +# CONFIG_FRAME_BUFFER_BOOT_NOLOGO is not set +CONFIG_FRAME_BUFFER_BOOT_LOGOS=y +# CONFIG_FB_LOGO_TUX_MENU is not set +CONFIG_FB_LOGO_WOLK_MENU=y +CONFIG_FB_LOGO_WOLK1=y +# CONFIG_FB_LOGO_MISC_MENU is not set +# CONFIG_FB_LOGO_BZD_MENU is not set +# CONFIG_FB_LOGO_DEBIAN_MENU is not set +# CONFIG_FB_LOGO_PLD_MENU is not set +# CONFIG_FB_LOGO_REDHAT_MENU is not set +# CONFIG_FB_LOGO_MANDRAKE_MENU is not set +# CONFIG_FB_LOGO_SLACKWARE_MENU is not set +# CONFIG_FB_LOGO_GENTOO_MENU is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_VESA=y +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_HGA is not set +CONFIG_VIDEO_SELECT=y +# CONFIG_FB_MAN_LFB is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_INTEL is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_VMWARE_SVGA is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +CONFIG_FONT_6x11=y +CONFIG_FONT_PEARL_8x8=y +CONFIG_FONT_ACORN_8x8=y + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_AUDIGY is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # -# CONFIG_USB is not set +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_UHCI=m +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_MIDI is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +CONFIG_USB_HIDDEV=y +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_STV680 is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set +CONFIG_USB_LOGITECH_CAM=m +# CONFIG_USB_LOGITECH_DEBUG is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USBDNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_BRLVGER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_SPEEDTOUCH is not set # # Bluetooth support @@ -903,13 +1420,33 @@ CONFIG_VIDEO_SELECT=y # # Kernel hacking # -# CONFIG_DEBUG_KERNEL is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_KWATCHDOG is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KMSGDUMP is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_OPROFILE is not set +# CONFIG_PROC_MEMMAP is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +CONFIG_KALLSYMS=y +# CONFIG_X86_REMOTE_DEBUG is not set +CONFIG_WLI_EARLY_PRINTK=y +CONFIG_EARLY_CONSOLE_VGA=y +# CONFIG_EARLY_CONSOLE_3F8 is not set +# CONFIG_EARLY_CONSOLE_3E8 is not set +# CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK is not set # # Library routines # -CONFIG_ZLIB_INFLATE=m -# CONFIG_ZLIB_DEFLATE is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m # # Security Options @@ -918,14 +1455,155 @@ CONFIG_ZLIB_INFLATE=m # # Grsecurity # -# CONFIG_GRKERNSEC is not set +CONFIG_GRKERNSEC=y +# CONFIG_GRKERNSEC_LOW is not set +# CONFIG_GRKERNSEC_MID is not set +# CONFIG_GRKERNSEC_HI is not set +CONFIG_GRKERNSEC_CUSTOM=y + +# +# Address Space Protection +# +CONFIG_GRKERNSEC_PAX_NOEXEC=y +# CONFIG_GRKERNSEC_PAX_PAGEEXEC is not set +CONFIG_GRKERNSEC_PAX_SEGMEXEC=y +# CONFIG_GRKERNSEC_PAX_EMUTRAMP is not set +CONFIG_GRKERNSEC_PAX_MPROTECT=y +# CONFIG_GRKERNSEC_PAX_NOELFRELOCS is not set +CONFIG_GRKERNSEC_PAX_ASLR=y +# CONFIG_GRKERNSEC_PAX_RANDKSTACK is not set +CONFIG_GRKERNSEC_PAX_RANDUSTACK=y +CONFIG_GRKERNSEC_PAX_RANDMMAP=y +# CONFIG_GRKERNSEC_PAX_RANDEXEC is not set +CONFIG_GRKERNSEC_KMEM=y +# CONFIG_GRKERNSEC_IO is not set +CONFIG_GRKERNSEC_PROC_MEMMAP=y +CONFIG_GRKERNSEC_HIDESYM=y + +# +# ACL options +# +CONFIG_GRKERNSEC_ACL_HIDEKERN=y +CONFIG_GRKERNSEC_ACL_MAXTRIES=3 +CONFIG_GRKERNSEC_ACL_TIMEOUT=30 + +# +# Filesystem Protections +# +CONFIG_GRKERNSEC_PROC=y +# CONFIG_GRKERNSEC_PROC_USER is not set +CONFIG_GRKERNSEC_PROC_USERGROUP=y +CONFIG_GRKERNSEC_PROC_GID=1001 +CONFIG_GRKERNSEC_PROC_ADD=y +CONFIG_GRKERNSEC_LINK=y +CONFIG_GRKERNSEC_FIFO=y +CONFIG_GRKERNSEC_CHROOT=y +CONFIG_GRKERNSEC_CHROOT_MOUNT=y +CONFIG_GRKERNSEC_CHROOT_DOUBLE=y +CONFIG_GRKERNSEC_CHROOT_PIVOT=y +CONFIG_GRKERNSEC_CHROOT_CHDIR=y +CONFIG_GRKERNSEC_CHROOT_CHMOD=y +CONFIG_GRKERNSEC_CHROOT_FCHDIR=y +CONFIG_GRKERNSEC_CHROOT_MKNOD=y +CONFIG_GRKERNSEC_CHROOT_SHMAT=y +CONFIG_GRKERNSEC_CHROOT_UNIX=y +CONFIG_GRKERNSEC_CHROOT_FINDTASK=y +CONFIG_GRKERNSEC_CHROOT_NICE=y +CONFIG_GRKERNSEC_CHROOT_SYSCTL=y +CONFIG_GRKERNSEC_CHROOT_CAPS=y + +# +# Kernel Auditing +# +CONFIG_GRKERNSEC_AUDIT_GROUP=y +CONFIG_GRKERNSEC_AUDIT_GID=1007 +CONFIG_GRKERNSEC_EXECLOG=y +CONFIG_GRKERNSEC_RESLOG=y +CONFIG_GRKERNSEC_CHROOT_EXECLOG=y +CONFIG_GRKERNSEC_AUDIT_CHDIR=y +CONFIG_GRKERNSEC_AUDIT_MOUNT=y +CONFIG_GRKERNSEC_AUDIT_IPC=y +CONFIG_GRKERNSEC_SIGNAL=y +CONFIG_GRKERNSEC_FORKFAIL=y +CONFIG_GRKERNSEC_TIME=y + +# +# Executable Protections +# +CONFIG_GRKERNSEC_EXECVE=y +CONFIG_GRKERNSEC_DMESG=y +CONFIG_GRKERNSEC_RANDPID=y +CONFIG_GRKERNSEC_TPE=y +CONFIG_GRKERNSEC_TPE_ALL=y +CONFIG_GRKERNSEC_TPE_GID=1005 + +# +# Network Protections +# +CONFIG_GRKERNSEC_RANDNET=y +CONFIG_GRKERNSEC_RANDISN=y +CONFIG_GRKERNSEC_RANDID=y +CONFIG_GRKERNSEC_RANDSRC=y +CONFIG_GRKERNSEC_RANDRPC=y +CONFIG_GRKERNSEC_RANDPING=y +CONFIG_GRKERNSEC_SOCKET=y +CONFIG_GRKERNSEC_SOCKET_ALL=y +CONFIG_GRKERNSEC_SOCKET_ALL_GID=1004 +CONFIG_GRKERNSEC_SOCKET_CLIENT=y +CONFIG_GRKERNSEC_SOCKET_CLIENT_GID=1003 +CONFIG_GRKERNSEC_SOCKET_SERVER=y +CONFIG_GRKERNSEC_SOCKET_SERVER_GID=1002 + +# +# Sysctl support +# +CONFIG_GRKERNSEC_SYSCTL=y + +# +# Logging options +# +CONFIG_GRKERNSEC_FLOODTIME=10 +CONFIG_GRKERNSEC_FLOODBURST=4 + +# +# Rule Set Based Access Control (RSBAC) +# +# CONFIG_RSBAC is not set # # Cryptography support (CryptoAPI) # -# CONFIG_CRYPTO is not set -# CONFIG_CIPHERS is not set -# CONFIG_DIGESTS is not set -# CONFIG_CRYPTODEV is not set +CONFIG_CRYPTO=m +CONFIG_CIPHERS=y +CONFIG_CIPHER_AES=m +CONFIG_CIPHER_MARS=m +CONFIG_CIPHER_RC6=m +CONFIG_CIPHER_SERPENT=m +CONFIG_CIPHER_TWOFISH=m +CONFIG_CIPHER_3DES=m +CONFIG_CIPHER_BLOWFISH=m +CONFIG_CIPHER_CAST5=m +CONFIG_CIPHER_GOST=m +CONFIG_CIPHER_IDEA=m +CONFIG_CIPHER_RC5=m +# CONFIG_CIPHER_NULL is not set +# CONFIG_CIPHER_DES is not set +# CONFIG_CIPHER_DFC is not set +# CONFIG_CIPHER_BLOWFISH_OLD is not set +CONFIG_DIGESTS=y +CONFIG_DIGEST_MD5=m +CONFIG_DIGEST_SHA1=m +CONFIG_DIGEST_RIPEMD160=m +CONFIG_DIGEST_SHA256=m +CONFIG_DIGEST_SHA384=m +CONFIG_DIGEST_SHA512=m +CONFIG_CRYPTODEV=y +CONFIG_CRYPTOLOOP=m +# CONFIG_CRYPTOLOOP_ATOMIC is not set +# CONFIG_CRYPTOLOOP_DEBUG is not set +CONFIG_IPSEC_TUNNEL=m +# CONFIG_SCONTEXTS is not set # CONFIG_SYSTRACE is not set # CONFIG_RENICE_USER is not set +# CONFIG_CMDLINE_ENABLE is not set +# CONFIG_EVFS_FS is not set diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kdb/ChangeLog linux-2.4.20-wolk4.7-fullkernel/arch/i386/kdb/ChangeLog --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kdb/ChangeLog 2003-05-05 20:04:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kdb/ChangeLog 2003-08-17 21:26:25.000000000 +0200 @@ -1,3 +1,9 @@ +2003-06-20 Keith Owens + + * Add CONFIG_KDB_CONTINUE_CATASTROPHIC. + * Correct KDB_ENTER() definition. + * kdb v4.3-2.4.20-i386-1. + 2003-05-02 Keith Owens * Add kdba_fp_value(). diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/Makefile linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/Makefile --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/Makefile 2003-05-03 02:37:22.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/Makefile 2003-08-17 21:31:46.000000000 +0200 @@ -53,6 +53,7 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o tr obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o +obj-$(CONFIG_X86_USE_3DNOW) += i386_ksyms.o obj-$(CONFIG_KMSGDUMP) += kmsgdump.o obj-$(CONFIG_MXT) += mxt.o obj-$(CONFIG_SISBUG) += sisbug.o diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/apic.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/apic.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/apic.c 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/apic.c 2003-08-17 21:31:46.000000000 +0200 @@ -37,6 +37,7 @@ int using_apic_timer = 0; int prof_multiplier[NR_CPUS] = { 1, }; int prof_old_multiplier[NR_CPUS] = { 1, }; int prof_counter[NR_CPUS] = { 1, }; +static int enabled_via_apicbase; int get_maxlvt(void) { @@ -142,6 +143,13 @@ void disable_local_APIC(void) value = apic_read(APIC_SPIV); value &= ~APIC_SPIV_APIC_ENABLED; apic_write_around(APIC_SPIV, value); + + if (enabled_via_apicbase) { + unsigned int l, h; + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_ENABLE; + wrmsr(MSR_IA32_APICBASE, l, h); + } } /* @@ -466,7 +474,6 @@ static struct { static void apic_pm_suspend(void *data) { - unsigned int l, h; unsigned long flags; if (apic_pm_state.perfctr_pmdev) @@ -486,9 +493,6 @@ static void apic_pm_suspend(void *data) __save_flags(flags); __cli(); disable_local_APIC(); - rdmsr(MSR_IA32_APICBASE, l, h); - l &= ~MSR_IA32_APICBASE_ENABLE; - wrmsr(MSR_IA32_APICBASE, l, h); __restore_flags(flags); } @@ -647,6 +651,7 @@ static int __init detect_init_APIC (void l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); + enabled_via_apicbase = 1; } } /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/entry.S linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/entry.S --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/entry.S 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/entry.S 2003-08-17 21:31:31.000000000 +0200 @@ -45,7 +45,6 @@ #include #include #include -#include EBX = 0x00 ECX = 0x04 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/head.S linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/head.S --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/head.S 2003-05-03 02:33:29.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/head.S 2003-08-17 21:31:43.000000000 +0200 @@ -34,7 +34,7 @@ #define X86_HARD_MATH CPU_PARAMS+6 #define X86_CPUID CPU_PARAMS+8 #define X86_CAPABILITY CPU_PARAMS+12 -#define X86_VENDOR_ID CPU_PARAMS+28 +#define X86_VENDOR_ID CPU_PARAMS+36 /* * swapper_pg_dir is the main page directory, address 0x00101000 @@ -485,10 +485,10 @@ ENTRY(gdt_table) * The APM segments have byte granularity and their bases * and limits are set at run time. */ - .quad 0x0040920000000000 /* 0x40 APM set up for bad BIOS's */ - .quad 0x00409a0000000000 /* 0x48 APM CS code */ - .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ - .quad 0x0040920000000000 /* 0x58 APM DS data */ + .quad 0x0040930000000000 /* 0x40 APM set up for bad BIOS's */ + .quad 0x00409b0000000000 /* 0x48 APM CS code */ + .quad 0x00009b0000000000 /* 0x50 APM CS 16 code (16 bit) */ + .quad 0x0040930000000000 /* 0x58 APM DS data */ .fill NR_CPUS*16,8,0 /* space for TSS's and LDT's, 128byte aligned for new x86 CPUs */ #ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/ldt.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/ldt.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/ldt.c 2003-05-03 02:37:57.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/ldt.c 2003-08-17 21:31:05.000000000 +0200 @@ -124,7 +124,7 @@ static int write_ldt(void * ptr, unsigne } #ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC - if (current->flags & PF_PAX_SEGMEXEC && (ldt_info.contents & 2)) { + if ((current->flags & PF_PAX_SEGMEXEC) && (ldt_info.contents & 2)) { error = -EINVAL; goto out_unlock; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/process.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/process.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/process.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/process.c 2003-08-17 21:31:46.000000000 +0200 @@ -169,7 +169,6 @@ static int __init idle_setup (char *str) __setup("idle=", idle_setup); -static long no_idt[2]; static int reboot_mode; int reboot_thru_bios; @@ -240,7 +239,8 @@ static struct unsigned long long * base __attribute__ ((packed)); } real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, -real_mode_idt = { 0x3ff, 0 }; +real_mode_idt = { 0x3ff, 0 }, +no_idt = { 0, 0 }; /* This is 16-bit protected mode code to disable paging and the cache, switch to real mode and jump to the BIOS reset code. @@ -456,7 +456,7 @@ void machine_dump(int callertype) chkpnt=100; cli(); chkpnt++; -#if __SMP__ +#ifdef CONFIG_SMP /* * Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. @@ -654,7 +654,7 @@ void machine_dump(int callertype) void machine_restart(char * __unused) { -#if CONFIG_SMP +#ifdef CONFIG_SMP int cpuid; cpuid = GET_APIC_ID(apic_read(APIC_ID)); @@ -697,6 +697,14 @@ void machine_restart(char * __unused) #endif /* CONFIG_KDB */ if (!netdump_func) smp_send_stop(); +#elif CONFIG_X86_LOCAL_APIC + if (cpu_has_apic) { + __cli(); + disable_local_APIC(); + __sti(); + } +#endif +#ifdef CONFIG_X86_IO_APIC disable_IO_APIC(); #endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/setup.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/setup.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/setup.c 2003-08-05 22:23:15.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/setup.c 2003-08-17 21:31:42.000000000 +0200 @@ -2084,6 +2084,37 @@ static void __init winchip2_protect_mcr( #endif +static void __init init_c3(struct cpuinfo_x86 *c) +{ + u32 lo, hi; + + /* Test for Centaur Extended Feature Flags presence */ + if (cpuid_eax(0xC0000000) >= 0xC0000001) { + /* store Centaur Extended Feature Flags as + * word 5 of the CPU capability bit array + */ + c->x86_capability[5] = cpuid_edx(0xC0000001); + } + + switch (c->x86_model) { + case 6 ... 8: /* Cyrix III family */ + rdmsr (MSR_VIA_FCR, lo, hi); + lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ + wrmsr (MSR_VIA_FCR, lo, hi); + + set_bit(X86_FEATURE_CX8, c->x86_capability); + set_bit(X86_FEATURE_3DNOW, c->x86_capability); + + /* fall through */ + + case 9: /* Nehemiah */ + default: + get_model_name(c); + display_cacheinfo(c); + break; + } +} + static void __init init_centaur(struct cpuinfo_x86 *c) { enum { @@ -2224,19 +2255,7 @@ static void __init init_centaur(struct c break; case 6: - switch (c->x86_model) { - case 6 ... 8: /* Cyrix III family */ - rdmsr (MSR_VIA_FCR, lo, hi); - lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ - wrmsr (MSR_VIA_FCR, lo, hi); - - set_bit(X86_FEATURE_CX8, &c->x86_capability); - set_bit(X86_FEATURE_3DNOW, &c->x86_capability); - - get_model_name(c); - display_cacheinfo(c); - break; - } + init_c3(c); break; } } @@ -2898,10 +2917,16 @@ void __init identify_cpu(struct cpuinfo_ /* Intel-defined flags: level 0x00000001 */ if ( c->cpuid_level >= 0x00000001 ) { - cpuid(0x00000001, &tfms, &junk, &junk, - &c->x86_capability[0]); + u32 capability, excap; + cpuid(0x00000001, &tfms, &junk, &excap, &capability); + c->x86_capability[0] = capability; + c->x86_capability[4] = excap; c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; + if (c->x86 == 0xf) { + c->x86 += (tfms >> 20) & 0xff; + c->x86_model += ((tfms >> 16) & 0xF) << 4; + } c->x86_mask = tfms & 15; } else { /* Have CPUID level 0 only - unheard of */ @@ -3108,7 +3133,7 @@ static int show_cpuinfo(struct seq_file "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, + "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe", /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -3123,7 +3148,20 @@ static int show_cpuinfo(struct seq_file NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Other (Linux-defined) */ - "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL, + "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Intel-defined (#2) */ + "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2", + "est", NULL, "cid", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* VIA/Cyrix/Centaur-defined */ + NULL, NULL, "xstore", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/smp.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/smp.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/smp.c 2003-05-03 02:37:57.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/smp.c 2003-08-17 21:31:05.000000000 +0200 @@ -531,7 +531,8 @@ void flush_tlb_all(void) void smp_kdb_stop(void) { - send_IPI_allbutself(KDB_VECTOR); + if (!KDB_FLAG(NOIPI)) + send_IPI_allbutself(KDB_VECTOR); } #endif /* CONFIG_KDB */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/smpboot.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/smpboot.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/smpboot.c 2003-05-03 02:37:14.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/smpboot.c 2003-08-17 21:30:45.000000000 +0200 @@ -464,17 +464,18 @@ void __init smp_callin(void) calibrate_delay(); Dprintk("Stack at about %p\n",&cpuid); -#ifdef CONFIG_KDB - /* Activate any preset global breakpoints on this cpu */ - kdb(KDB_REASON_SILENT, 0, 0); -#endif /* CONFIG_KDB */ - /* * Save our processor parameters */ smp_store_cpu_info(cpuid); disable_APIC_timer(); + +#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. */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/traps.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/traps.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/kernel/traps.c 2003-05-10 10:21:19.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/kernel/traps.c 2003-08-17 21:30:53.000000000 +0200 @@ -1008,20 +1008,16 @@ void set_ldt_desc(unsigned int n, void * { #ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long temp, cr3; pgd_t* pgd; pmd_t* pmd; - unsigned long __pe = _KERNPG_TABLE + __pa(__KERNEL_TEXT_OFFSET); - - asm("movl %%cr3,%0":"=r" (pgd)); - pgd = (pgd_t *)__va(pgd) + __pgd_offset(__KERNEL_TEXT_OFFSET); - pmd = pmd_offset(pgd, __KERNEL_TEXT_OFFSET); - if (cpu_has_pse) { - __pe += _PAGE_PSE; - if (cpu_has_pge) - __pe += _PAGE_GLOBAL; + asm("movl %%cr3,%0":"=r" (cr3)); + for (temp = __KERNEL_TEXT_OFFSET; temp < __KERNEL_TEXT_OFFSET + 0x00400000UL; temp += (1UL << PMD_SHIFT)) { + pgd = (pgd_t *)__va(cr3) + __pgd_offset(temp); + pmd = pmd_offset(pgd, temp); + set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_RW)); } - set_pmd(pmd, __pmd(__pe)); __flush_tlb_all(); #endif @@ -1032,13 +1028,11 @@ void set_ldt_desc(unsigned int n, void * #endif #ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC - __pe = __PAGE_KERNEL_RO + __pa(__KERNEL_TEXT_OFFSET); - if (cpu_has_pse) { - __pe += _PAGE_PSE; - if (cpu_has_pge) - __pe += _PAGE_GLOBAL; + for (temp = __KERNEL_TEXT_OFFSET; temp < __KERNEL_TEXT_OFFSET + 0x00400000UL; temp += (1UL << PMD_SHIFT)) { + pgd = (pgd_t *)__va(cr3) + __pgd_offset(temp); + pmd = pmd_offset(pgd, temp); + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); } - set_pmd(pmd, __pmd(__pe)); flush_tlb_all(); #endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/mm/fault.c linux-2.4.20-wolk4.7-fullkernel/arch/i386/mm/fault.c --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/mm/fault.c 2003-05-03 02:37:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/mm/fault.c 2003-08-17 21:30:39.000000000 +0200 @@ -140,7 +140,6 @@ asmlinkage void do_invalid_op(struct pt_ extern unsigned long idt; #if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) -static void pax_report_fault(struct pt_regs *regs); static int pax_handle_fetch_fault(struct pt_regs *regs); #endif @@ -176,7 +175,7 @@ asmlinkage int do_page_fault(struct pt_r __asm__("movl %%cr2,%0":"=r" (address)); /* It's safe to allow irq's after cr2 has been saved */ - if (likely(regs->eflags & X86_EFLAGS_IF)) + if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); #endif @@ -331,7 +330,7 @@ bad_area: #endif if (address >= SEGMEXEC_TASK_SIZE) { - pax_report_fault(regs); + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); do_exit(SIGKILL); } } @@ -533,11 +532,10 @@ static int pax_handle_fetch_fault(struct regs->eip < current->mm->end_code) { err = get_user(esp_4, (unsigned long*)(regs->esp-4UL)); - if (!err && esp_4 != regs->eip) { - regs->eip += current->mm->delta_exec; - return 5; - } - return 1; + if (err || esp_4 == regs->eip) + return 1; + regs->eip += current->mm->delta_exec; + return 5; } } #endif @@ -582,7 +580,7 @@ static int pax_handle_fetch_fault(struct if (handler == SIG_DFL || handler == SIG_IGN) { if (!(current->flags & PF_PAX_EMUTRAMP)) return 1; - } else if (ka->sa.sa_flags & SA_SIGINFO) + } else if (!(ka->sa.sa_flags & SA_SIGINFO)) return 1; #endif @@ -665,7 +663,7 @@ static int pax_handle_fetch_fault(struct (jmp & 0xF8FF) == 0xE0FF && (mov2 & 0x07) == ((jmp>>8) & 0x07) && (call & 0xF8FF) == 0xD0FF && - (regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])) + regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]]) { ((unsigned long *)regs)[trans[mov1 & 0x07]] = addr1; ((unsigned long *)regs)[trans[mov2 & 0x07]] = addr2; @@ -695,7 +693,7 @@ static int pax_handle_fetch_fault(struct if ((mov & 0xF8) == 0xB8 && jmp == 0xE9 && (call & 0xF8FF) == 0xD0FF && - (regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])) + regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]]) { ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; regs->eip += addr2 + 10; @@ -707,51 +705,20 @@ static int pax_handle_fetch_fault(struct return 1; /* PaX in action */ } -static void pax_report_fault(struct pt_regs *regs) +void pax_report_insns(void *pc) { - struct task_struct *tsk = current; - struct mm_struct *mm = current->mm; - char* buffer = (char*)__get_free_page(GFP_ATOMIC); - char* path=NULL; unsigned long i; - if (buffer) { - struct vm_area_struct* vma; - - down_read(&mm->mmap_sem); - vma = mm->mmap; - while (vma) { - if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { - break; - } - vma = vma->vm_next; - } - if (vma) - path = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt, buffer, PAGE_SIZE); - up_read(&mm->mmap_sem); - } - if (tsk->curr_ip) - printk(KERN_ERR "PAX: From %u.%u.%u.%u: terminating task: %.930s(%.16s):%d, uid/euid: %u/%u, " - "EIP: %08lX, ESP: %08lX\n", NIPQUAD(tsk->curr_ip), - path, tsk->comm, tsk->pid, tsk->uid, tsk->euid, - regs->eip, regs->esp); - else - printk(KERN_ERR "PAX: terminating task: %.930s(%.16s):%d, uid/euid: %u/%u, " - "EIP: %08lX, ESP: %08lX\n", path, tsk->comm, tsk->pid, - tsk->uid, tsk->euid, regs->eip, regs->esp); - - if (buffer) free_page((unsigned long)buffer); - printk(KERN_ERR "PAX: bytes at EIP: "); + printk(KERN_ERR "PAX: bytes at PC: "); for (i = 0; i < 20; i++) { unsigned char c; - if (get_user(c, (unsigned char*)(regs->eip+i))) { + if (get_user(c, (unsigned char*)pc+i)) { printk("."); break; } printk("%02x ", c); } printk("\n"); - do_coredump(SIGKILL, regs); } #endif @@ -773,7 +740,7 @@ asmlinkage int pax_do_page_fault(struct __asm__("movl %%cr2,%0":"=r" (address)); /* It's safe to allow irq's after cr2 has been saved */ - if (regs->eflags & X86_EFLAGS_IF) + if (likely(regs->eflags & X86_EFLAGS_IF)) local_irq_enable(); if (unlikely((error_code & 5) != 5 || @@ -794,15 +761,15 @@ asmlinkage int pax_do_page_fault(struct #endif #ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP - case 4: return 0; case 3: - case 2: return 1; + case 2: + return 1; #endif case 1: default: - pax_report_fault(regs); + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); do_exit(SIGKILL); } } @@ -838,7 +805,7 @@ asmlinkage int pax_do_page_fault(struct * raise a page fault (such as those set up by PaX, or the copy-on-write * mechanism). in effect it means that we do *not* need to flush the TLBs * for our target pages since their PTEs are simply not in the TLBs at all. - * the best thing in omitting it is that we gain around 15-20% speed in + * the best thing in omitting it is that we gain around 15-20% speed in the * fast path of the page fault handler and can get rid of tracing since we * can no longer flush unintended entries. */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/i386/vmlinux.lds.S linux-2.4.20-wolk4.7-fullkernel/arch/i386/vmlinux.lds.S --- linux-2.4.20-wolk4.6-fullkernel/arch/i386/vmlinux.lds.S 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/i386/vmlinux.lds.S 2003-08-17 21:28:27.000000000 +0200 @@ -9,6 +9,7 @@ SECTIONS . = __PAGE_OFFSET + 0x100000; .text.startup : { BYTE(0xEA) /* jmp far */ + #ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC LONG(startup_32 + __KERNEL_TEXT_OFFSET - __PAGE_OFFSET) #else @@ -30,13 +31,7 @@ SECTIONS .data.init_task : { *(.data.init_task) } . = ALIGN(4096); - .data.page_aligned : { - *(.data.swapper_pg_dir) - *(.data.pg0) - *(.data.pg1) - *(.data.pg2) - *(.data.empty_zero_page) - } + .data.page_aligned : { *(.data.swapper_pg_dir) } _edata = .; /* End of data section */ @@ -50,7 +45,12 @@ SECTIONS . = ALIGN(4096); /* Init code and data */ __init_begin = .; - .data.init : { *(.data.init) } + .data.init : { + *(.data.pg0) + *(.data.pg1) + *(.data.pg2) + *(.data.init) + } . = ALIGN(16); __setup_start = .; .setup.init : { *(.setup.init) } @@ -98,7 +98,10 @@ SECTIONS . += __KERNEL_TEXT_OFFSET; #endif - .rodata.page_aligned : { *(.data.idt) } + .rodata.page_aligned : { + *(.data.empty_zero_page) + *(.data.idt) + } .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ia64/config.in linux-2.4.20-wolk4.7-fullkernel/arch/ia64/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/ia64/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ia64/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -1,8 +1,5 @@ mainmenu_name "Kernel configuration of Linux for IA-64 machines" -# O(1) Scheduler -define_bool O1_SCHEDULER y - mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -148,7 +145,6 @@ if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then source drivers/block/Config.in source drivers/ieee1394/Config.in source drivers/message/i2o/Config.in - source drivers/evms/Config.in source drivers/md/Config.in source drivers/message/fusion/Config.in diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ia64/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ia64/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ia64/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ia64/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -978,16 +978,3 @@ CONFIG_IA64_EARLY_PRINTK_UART_BASE=0 # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set - -CONFIG_KDB=y -CONFIG_KDB_OFF=n -CONFIG_FRAME_POINTER=n - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ia64/kernel/entry.S linux-2.4.20-wolk4.7-fullkernel/arch/ia64/kernel/entry.S --- linux-2.4.20-wolk4.6-fullkernel/arch/ia64/kernel/entry.S 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ia64/kernel/entry.S 2003-08-17 21:30:35.000000000 +0200 @@ -1170,18 +1170,18 @@ sys_call_table: data8 sys_getdents64 data8 sys_getunwind // 1215 data8 sys_readahead - data8 sys_setxattr - data8 sys_lsetxattr - data8 sys_fsetxattr - data8 sys_getxattr // 1220 - data8 sys_lgetxattr - data8 sys_fgetxattr - data8 sys_listxattr - data8 sys_llistxattr - data8 sys_flistxattr // 1225 - data8 sys_removexattr - data8 sys_lremovexattr - data8 sys_fremovexattr + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1220 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1225 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall data8 sys_tkill data8 ia64_ni_syscall // 1230 data8 ia64_ni_syscall diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/m68k/config.in linux-2.4.20-wolk4.7-fullkernel/arch/m68k/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/m68k/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/m68k/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -3,9 +3,6 @@ # see Documentation/kbuild/config-language.txt. # -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/m68k/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/m68k/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/m68k/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/m68k/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -334,13 +334,3 @@ CONFIG_FONT_PEARL_8x8=y # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/mips/config.in linux-2.4.20-wolk4.7-fullkernel/arch/mips/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/mips/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/mips/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -2,10 +2,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_MIPS y define_bool CONFIG_MIPS32 y define_bool CONFIG_MIPS64 n diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/mips/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/mips/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/mips/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/mips/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -648,13 +648,3 @@ CONFIG_CROSSCOMPILE=y # # CONFIG_ZLIB_INFLATE is not set # CONFIG_ZLIB_DEFLATE is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/mips64/config.in linux-2.4.20-wolk4.7-fullkernel/arch/mips64/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/mips64/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/mips64/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -2,10 +2,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_MIPS y define_bool CONFIG_MIPS32 n define_bool CONFIG_MIPS64 y diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/mips64/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/mips64/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/mips64/defconfig 2003-05-03 02:37:06.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/mips64/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -595,13 +595,3 @@ CONFIG_CROSSCOMPILE=y # # CONFIG_ZLIB_INFLATE is not set # CONFIG_ZLIB_DEFLATE is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/parisc/config.in linux-2.4.20-wolk4.7-fullkernel/arch/parisc/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/parisc/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/parisc/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -3,9 +3,6 @@ # see the Configure script. # -# O(1) Scheduler -define_bool O1_SCHEDULER y - mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_PARISC y @@ -106,8 +103,6 @@ source drivers/parport/Config.in source drivers/block/Config.in -source drivers/evms/Config.in - source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/parisc/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/parisc/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/parisc/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/parisc/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -868,13 +868,3 @@ CONFIG_SOUND_HARMONY=y # Kernel hacking # CONFIG_MAGIC_SYSRQ=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/config.in linux-2.4.20-wolk4.7-fullkernel/arch/ppc/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -3,10 +3,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y @@ -261,7 +257,6 @@ endmenu source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in -source drivers/evms/Config.in source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/IVMS8_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/IVMS8_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/IVMS8_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/IVMS8_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -543,13 +543,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/SM850_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/SM850_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/SM850_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/SM850_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -503,13 +503,3 @@ CONFIG_8xx_CPU6=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/SPD823TS_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/SPD823TS_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/SPD823TS_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/SPD823TS_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -502,13 +502,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/TQM823L_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/TQM823L_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/TQM823L_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/TQM823L_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -503,13 +503,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/TQM850L_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/TQM850L_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/TQM850L_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/TQM850L_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -503,13 +503,3 @@ CONFIG_8xx_CPU6=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/TQM860L_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/TQM860L_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/TQM860L_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/TQM860L_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -552,13 +552,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/apus_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/apus_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/apus_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/apus_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -904,13 +904,3 @@ CONFIG_ZLIB_DEFLATE=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/briq_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/briq_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/briq_defconfig 2003-05-03 01:54:02.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/briq_defconfig 2002-11-29 00:53:11.000000000 +0100 @@ -795,13 +795,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/bseip_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/bseip_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/bseip_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/bseip_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -502,13 +502,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/common_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/common_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/common_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/common_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -1044,13 +1044,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/est8260_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/est8260_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/est8260_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/est8260_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -478,13 +478,3 @@ CONFIG_SCC1_ENET=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/gemini_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/gemini_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/gemini_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/gemini_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -574,13 +574,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/ibmchrp_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/ibmchrp_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/ibmchrp_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/ibmchrp_defconfig 2003-08-17 21:27:34.000000000 +0200 @@ -776,13 +776,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/mbx_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/mbx_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/mbx_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/mbx_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -498,13 +498,3 @@ CONFIG_8xx_CPU6=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/oak_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/oak_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/oak_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/oak_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -454,13 +454,3 @@ CONFIG_MSDOS_PARTITION=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/pal4_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/pal4_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/pal4_defconfig 2003-05-03 01:54:02.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/pal4_defconfig 2002-11-29 00:53:11.000000000 +0100 @@ -565,13 +565,3 @@ CONFIG_MSDOS_PARTITION=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/pmac_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/pmac_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/pmac_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/pmac_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -1152,13 +1152,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/power3_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/power3_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/power3_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/power3_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -788,13 +788,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/rpxcllf_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/rpxcllf_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/rpxcllf_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/rpxcllf_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -503,13 +503,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/rpxlite_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/rpxlite_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/rpxlite_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/rpxlite_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -500,13 +500,3 @@ CONFIG_8xx_COPYBACK=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/spruce_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/spruce_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/spruce_defconfig 2003-05-03 01:54:02.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/spruce_defconfig 2002-11-29 00:53:11.000000000 +0100 @@ -504,13 +504,3 @@ CONFIG_MSDOS_PARTITION=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/walnut_defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/walnut_defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/configs/walnut_defconfig 2003-05-03 02:00:13.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/configs/walnut_defconfig 2003-08-17 21:27:35.000000000 +0200 @@ -458,13 +458,3 @@ CONFIG_MSDOS_PARTITION=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/ppc/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -1049,13 +1049,3 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_XMON=y # CONFIG_BDI_SWITCH is not set # CONFIG_MORE_COMPILE_OPTIONS is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/ppc64/config.in linux-2.4.20-wolk4.7-fullkernel/arch/ppc64/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/ppc64/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/ppc64/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -2,10 +2,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_UID16 n define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y @@ -106,7 +102,6 @@ fi endmenu source drivers/block/Config.in -source drivers/evms/Config.in source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/s390/config.in linux-2.4.20-wolk4.7-fullkernel/arch/s390/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/s390/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/s390/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -3,9 +3,6 @@ # see Documentation/kbuild/config-language.txt. # -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_ISA n define_bool CONFIG_EISA n define_bool CONFIG_MCA n @@ -72,8 +69,6 @@ endmenu source drivers/s390/Config.in -source drivers/evms/Config.in - if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/s390/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/s390/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/s390/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/s390/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -278,13 +278,3 @@ CONFIG_IBM_PARTITION=y # Kernel hacking # CONFIG_MAGIC_SYSRQ=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/s390x/config.in linux-2.4.20-wolk4.7-fullkernel/arch/s390x/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/s390x/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/s390x/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -3,9 +3,6 @@ # see Documentation/kbuild/config-language.txt. # -# O(1) Scheduler -define_bool O1_SCHEDULER y - define_bool CONFIG_ISA n define_bool CONFIG_EISA n define_bool CONFIG_MCA n @@ -76,8 +73,6 @@ endmenu source drivers/s390/Config.in -source drivers/evms/Config.in - if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/s390x/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/s390x/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/s390x/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/s390x/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -278,13 +278,3 @@ CONFIG_IBM_PARTITION=y # Kernel hacking # CONFIG_MAGIC_SYSRQ=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/sh/config.in linux-2.4.20-wolk4.7-fullkernel/arch/sh/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/sh/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/sh/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -2,10 +2,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - mainmenu_name "Linux/SuperH Kernel Configuration" define_bool CONFIG_SUPERH y diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/sh/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/sh/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/sh/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/sh/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -208,13 +208,3 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_MAGIC_SYSRQ is not set CONFIG_SH_STANDARD_BIOS=y CONFIG_SH_EARLY_PRINTK=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/sparc/config.in linux-2.4.20-wolk4.7-fullkernel/arch/sparc/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/sparc/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/sparc/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -2,10 +2,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - mainmenu_name "Linux/SPARC Kernel Configuration" define_bool CONFIG_UID16 y diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/sparc/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/sparc/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/sparc/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/sparc/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -422,13 +422,3 @@ CONFIG_NLS_DEFAULT="iso8859-1" # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/sparc64/defconfig linux-2.4.20-wolk4.7-fullkernel/arch/sparc64/defconfig --- linux-2.4.20-wolk4.6-fullkernel/arch/sparc64/defconfig 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/sparc64/defconfig 2003-08-17 21:30:35.000000000 +0200 @@ -929,12 +929,3 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y - -# -# XFS addons -# -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_DMAPI is not set diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/um/config.in linux-2.4.20-wolk4.7-fullkernel/arch/um/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/um/config.in 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/um/config.in 2003-08-17 21:27:38.000000000 +0200 @@ -1,8 +1,5 @@ define_bool CONFIG_USERMODE y -# O(1) Scheduler -define_bool O1_SCHEDULER y - mainmenu_name "Linux/Usermode Kernel Configuration" define_bool CONFIG_ISA n diff -Naurp linux-2.4.20-wolk4.6-fullkernel/arch/x86_64/config.in linux-2.4.20-wolk4.7-fullkernel/arch/x86_64/config.in --- linux-2.4.20-wolk4.6-fullkernel/arch/x86_64/config.in 2003-05-03 02:11:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/arch/x86_64/config.in 2003-08-17 21:28:35.000000000 +0200 @@ -2,10 +2,6 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # - -# O(1) Scheduler -define_bool O1_SCHEDULER y - mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_X86_64 y diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/Makefile 2003-05-03 02:33:22.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/Makefile 2003-08-17 21:29:10.000000000 +0200 @@ -8,7 +8,7 @@ mod-subdirs := dio hil mtd sbus video macintosh usb input telephony sgi ide \ message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ - fc4 net/hamradio i2c acpi bluetooth sensors evms cpufreq + fc4 net/hamradio i2c acpi bluetooth sensors cpufreq subdir-y := parport char block net sound misc media cdrom hotplug subdir-m := $(subdir-y) @@ -51,6 +51,5 @@ subdir-$(CONFIG_SENSORS) += sensors subdir-$(CONFIG_ACPI) += acpi subdir-$(CONFIG_BLUEZ) += bluetooth -subdir-$(CONFIG_EVMS) += evms include $(TOPDIR)/Rules.make diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/Makefile 2003-05-03 02:33:23.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/Makefile 2003-08-17 21:29:12.000000000 +0200 @@ -4,14 +4,9 @@ O_TARGET := drbd.o -obj-y := drbd_fs.o drbd_main.o drbd_proc.o drbd_receiver.o drbd_req-2.4.o \ - drbd_syncer.o +obj-y := drbd_fs.o drbd_main.o drbd_proc.o drbd_receiver.o drbd_req-2.4.o drbd_syncer.o obj-m := $(O_TARGET) -ifdef DEBUG - EXTRA_CFLAGS += -DEMU10K1_DEBUG -endif - include $(TOPDIR)/Rules.make clean: diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd.h linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd.h 2003-05-13 12:26:29.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd.h 2003-08-17 21:29:12.000000000 +0200 @@ -1,6 +1,6 @@ /* drbd.h - Kernel module for 2.2.x Kernels + Kernel module for 2.2.x/2.4.x Kernels This file is part of drbd by Philipp Reisner. @@ -25,9 +25,9 @@ #include #ifdef __KERNEL__ -#define API_VERSION 61 +#define API_VERSION 62 #define PRO_VERSION 62 -#define REL_VERSION "0.6.3" +#define REL_VERSION "0.6.6" #include #include #else @@ -77,6 +77,7 @@ struct net_config { IN int wire_protocol; IN int try_connect_int; /* seconds */ IN int ping_int; /* seconds */ + IN int sndbuf_size; /* socket send buffer size */ }; enum ret_codes { @@ -112,7 +113,8 @@ typedef enum { Secondary=2, // role Human=4, // flag for set_state TimeoutExpired=8, // flag for set_state - DontBlameDrbd=16 // flag for set_state + DontBlameDrbd=16, // flag for set_state + DontWait=32 // flag for set_state } Drbd_State; typedef enum { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_fs.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_fs.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_fs.c 2003-05-03 02:33:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_fs.c 2003-08-17 21:29:12.000000000 +0200 @@ -147,11 +147,6 @@ int drbd_ioctl_set_disk(struct Drbd_Conf mdev->lo_usize = new_conf.disk_size; mdev->do_panic = new_conf.do_panic; - filp=filp_open("/etc/.drbd-disable",O_RDONLY,0); - if(!IS_ERR(filp)) { - memset(&drbd_conf[i].free_ee,1,sizeof(struct list_head)); - } - if (mdev->lo_usize) { blk_size[MAJOR_NR][minor] = mdev->lo_usize; /* @@ -202,9 +197,8 @@ STATIC int drbd_ioctl_set_net(struct Drbd_Conf *mdev, struct ioctl_net_config * arg) { int i,minor; - enum ret_codes retcode; + enum ret_codes retcode = NoError; struct net_config new_conf; - static unsigned long mg[]={0xE6167704,0xE6167704,0xFB187102}; minor=(int)(mdev-drbd_conf); @@ -250,21 +244,17 @@ int drbd_ioctl_set_net(struct Drbd_Conf drbd_thread_stop(&mdev->receiver); drbd_free_sock(minor); -#define get_ulong(A) *((unsigned long*)A) - - for(i=0;i<3;i++) { - if((get_ulong(system_utsname.nodename)^mg[i]) == DRBD_MAGIC) { - memset(&drbd_conf[minor].a_timeout,1, - sizeof(struct timer_list)); - } - } - memcpy(&mdev->conf,&new_conf, sizeof(struct net_config)); if (!mdev->transfer_log) { mdev->transfer_log = kmalloc(sizeof(struct tl_entry) * mdev->conf.tl_size, GFP_KERNEL); + if (!mdev->transfer_log) { + printk(KERN_ERR DEVICE_NAME + "%d: could not kmalloc transfer_log\n", minor); + goto fail_ioctl; + } tl_init(&drbd_conf[minor]); } @@ -292,7 +282,7 @@ int drbd_set_state(int minor,Drbd_State || drbd_conf[minor].cstate == SyncingQuick) return -EINPROGRESS; - if(newstate == Secondary && + if( (newstate & Secondary) && (test_bit(WRITER_PRESENT, &drbd_conf[minor].flags) || drbd_is_mounted(minor) == MountedRW)) return -EBUSY; @@ -327,6 +317,11 @@ int drbd_set_state(int minor,Drbd_State while (atomic_read(&drbd_conf[minor].pending_cnt) > 0 || atomic_read(&drbd_conf[minor].unacked_cnt) > 0 ) { + if((newstate & Secondary) && (newstate & DontWait)) { + set_bit(BECOME_SECONDARY,&drbd_conf[minor].flags); + return 0; + } + printk(KERN_ERR DEVICE_NAME "%d: set_state(%d,%d,%d)\n", minor, @@ -351,6 +346,7 @@ int drbd_set_state(int minor,Drbd_State drbd_conf[minor].cstate >= Connected ? ConnectedCnt : ArbitraryCnt); } + drbd_conf[minor].gen_cnt[Flags] |= MDF_Consistent; } else { set_device_ro(MKDEV(MAJOR_NR, minor), TRUE ); } @@ -394,10 +390,12 @@ int drbd_ioctl(struct inode *inode, stru case BLKROGET: case BLKFLSBUF: case BLKSSZGET: +#ifdef BLKBSZGET + case BLKBSZGET: +#endif case BLKPG: err=blk_ioctl(inode->i_rdev, cmd, arg); #else - up(&mdev->ctl_mutex); RO_IOCTLS(inode->i_rdev, arg); #endif break; @@ -485,6 +483,7 @@ int drbd_ioctl(struct inode *inode, stru } set_cstate(mdev,Unconfigured); + mdev->state = Secondary; break; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_int.h linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_int.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_int.h 2003-05-13 12:26:29.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_int.h 2003-08-17 21:29:12.000000000 +0200 @@ -209,7 +209,7 @@ typedef enum { struct Drbd_thread { struct task_struct *task; struct semaphore mutex; - int t_state; + volatile int t_state; int (*function) (struct Drbd_thread *); int minor; }; @@ -225,6 +225,10 @@ typedef struct drbd_request_struct drbd_ #else typedef struct request drbd_request_t; #define GET_SECTOR(A) ((A)->sector) +// dirty hack; smp_mb's are not defined for 2.2.x +// lets discard them... +#define smp_mb() ((void)0) +#define smp_mb__after_clear_bit() ((void)0) #endif struct tl_entry { @@ -249,7 +253,7 @@ struct Tl_epoch_entry { #define COLLECT_ZOMBIES 1 #define SEND_PING 2 #define WRITER_PRESENT 3 -/* 4 */ +#define BECOME_SECONDARY 4 #define DO_NOT_INC_CONCNT 5 #define WRITE_HINT_QUEUED 6 @@ -497,6 +501,15 @@ extern int drbd_proc_get_info(char *, ch #define SIGSET_OF(P) (&(P)->pending.signal) #endif +#ifdef REDHAT_2_4_20 +# define SIGMASK_LOCK sighand->siglock +# define RECALC_SIGPENDING(TSK) (recalc_sigpending_tsk(TSK)) +inline void recalc_sigpending_tsk(struct task_struct *t); +#else +# define SIGMASK_LOCK sigmask_lock +# define RECALC_SIGPENDING(TSK) (recalc_sigpending(TSK)) +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) #define del_timer_sync(A) del_timer(A) //typedef struct wait_queue wait_queue_t; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_main.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_main.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_main.c 2003-05-03 02:33:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_main.c 2003-08-17 21:29:12.000000000 +0200 @@ -772,21 +772,21 @@ int drbd_send(struct Drbd_Conf *mdev, Dr oldfs = get_fs(); set_fs(KERNEL_DS); - spin_lock_irqsave(¤t->sigmask_lock, flags); + spin_lock_irqsave(¤t->SIGMASK_LOCK, flags); oldset = current->blocked; sigfillset(¤t->blocked); sigdelset(¤t->blocked,DRBD_SIG); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, flags); + RECALC_SIGPENDING(current); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK, flags); while(1) { rv = sock_sendmsg(sock, &msg, header_size+data_size); if ( rv == -ERESTARTSYS) { - spin_lock_irqsave(¤t->sigmask_lock,flags); + spin_lock_irqsave(¤t->SIGMASK_LOCK,flags); if (sigismember(SIGSET_OF(current), DRBD_SIG)) { sigdelset(SIGSET_OF(current), DRBD_SIG); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, + RECALC_SIGPENDING(current); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK, flags); if(ti.timeout_happened) { break; @@ -795,7 +795,7 @@ int drbd_send(struct Drbd_Conf *mdev, Dr continue; } } - spin_unlock_irqrestore(¤t->sigmask_lock,flags); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK,flags); } if (rv <= 0) break; sent += rv; @@ -839,15 +839,15 @@ int drbd_send(struct Drbd_Conf *mdev, Dr } - spin_lock_irqsave(¤t->sigmask_lock, flags); + spin_lock_irqsave(¤t->SIGMASK_LOCK, flags); current->blocked = oldset; if(app_got_sig) { sigaddset(SIGSET_OF(current), DRBD_SIG); } else { sigdelset(SIGSET_OF(current), DRBD_SIG); } - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, flags); + RECALC_SIGPENDING(current); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK, flags); if (/*rv == -ERESTARTSYS &&*/ ti.timeout_happened) { printk(KERN_DEBUG DEVICE_NAME @@ -987,7 +987,7 @@ int __init drbd_init(void) &drbd_ops, NULL); # endif #endif - + // FIXME paranoia: check kmalloc return value! drbd_blocksizes = kmalloc(sizeof(int)*minor_count,GFP_KERNEL); drbd_sizes = kmalloc(sizeof(int)*minor_count,GFP_KERNEL); drbd_conf = kmalloc(sizeof(struct Drbd_Conf)*minor_count,GFP_KERNEL); @@ -1530,12 +1530,62 @@ void drbd_queue_signal(int signal,struct read_lock(&tasklist_lock); if (task) { - spin_lock_irqsave(&task->sigmask_lock, flags); + spin_lock_irqsave(&task->SIGMASK_LOCK, flags); sigaddset(SIGSET_OF(task), signal); - recalc_sigpending(task); - spin_unlock_irqrestore(&task->sigmask_lock, flags); + RECALC_SIGPENDING(task); + spin_unlock_irqrestore(&task->SIGMASK_LOCK, flags); if (task->state & TASK_INTERRUPTIBLE) wake_up_process(task); } read_unlock(&tasklist_lock); } +#ifdef REDHAT_2_4_20 + +// copied from redhat's kernel-2.4.20-13.9 kernel/signal.c +// to avoid a recompile of the redhat kernel + +#include // for _NSIG_WORDS + +/* + * Re-calculate pending state from the set of locally pending + * signals, globally pending signals, and blocked signals. + */ +static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) +{ + unsigned long ready; + long i; + + switch (_NSIG_WORDS) { + default: + for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) + ready |= signal->sig[i] &~ blocked->sig[i]; + break; + + case 4: ready = signal->sig[3] &~ blocked->sig[3]; + ready |= signal->sig[2] &~ blocked->sig[2]; + ready |= signal->sig[1] &~ blocked->sig[1]; + ready |= signal->sig[0] &~ blocked->sig[0]; + break; + + case 2: ready = signal->sig[1] &~ blocked->sig[1]; + ready |= signal->sig[0] &~ blocked->sig[0]; + break; + + case 1: ready = signal->sig[0] &~ blocked->sig[0]; + } + return ready != 0; +} + +#define PENDING(p,b) has_pending_signals(&(p)->signal, (b)) + +inline void recalc_sigpending_tsk(struct task_struct *t) +{ + if (t->signal->group_stop_count > 0 || + PENDING(&t->pending, &t->blocked) || + PENDING(&t->signal->shared_pending, &t->blocked)) + t->sigpending = 1; + else + t->sigpending = 0; +} + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_proc.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_proc.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_proc.c 2003-05-03 02:33:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_proc.c 2003-08-17 21:29:12.000000000 +0200 @@ -73,7 +73,7 @@ STATIC int drbd_syncer_progress(char *bu /* unit 1024 bytes */ total_kb = blk_size[MAJOR_NR][minor]; /* synced_to unit 512 bytes */ - left_kb = drbd_conf[minor].synced_to / 2; + left_kb = total_kb - drbd_conf[minor].synced_to / 2; res = (left_kb/1024)*1000/(total_kb/1024 + 1); { @@ -94,7 +94,7 @@ STATIC int drbd_syncer_progress(char *bu else sz+=sprintf(buf+sz,"(%lu/%lu)K\n\t", left_kb, total_kb); - /* see driver/md/md.c + /* see drivers/md/md.c * We do not want to overflow, so the order of operands and * the * 100 / 100 trick are important. We do a +1 to be * safe against division by zero. We only estimate anyway. @@ -105,7 +105,7 @@ STATIC int drbd_syncer_progress(char *bu */ dt = ((jiffies - drbd_conf[minor].resync_mark) / HZ); if (!dt) dt++; - db = (drbd_conf[minor].resync_mark_cnt/2) - left_kb; + db = (drbd_conf[minor].synced_to - drbd_conf[minor].resync_mark_cnt)/2; rt = (dt * (left_kb / (db/100+1)))/100; /* seconds */ if (rt > 3600) { @@ -185,8 +185,6 @@ STATIC int drbd_syncer_progress(char *bu */ for (i = 0; i < minor_count; i++) { - if( drbd_conf[i].cstate < Connected ) - drbd_conf[i].o_state = Unknown; rlen = rlen + sprintf(buf + rlen, "%d: cs:%s st:%s/%s ns:%u nr:%u dw:%u dr:%u" @@ -202,7 +200,7 @@ STATIC int drbd_syncer_progress(char *bu atomic_read(&drbd_conf[i].pending_cnt), atomic_read(&drbd_conf[i].unacked_cnt)); - if (drbd_conf[i].synced_to != 0) + if (drbd_conf[i].cstate == SyncingAll) rlen += drbd_syncer_progress(buf+rlen,i); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_receiver.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_receiver.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_receiver.c 2003-05-03 02:33:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_receiver.c 2003-08-17 21:29:12.000000000 +0200 @@ -143,6 +143,7 @@ STATIC void drbd_dio_end_sec(struct buff clear_bit(BH_Dirty, &bh->b_state); clear_bit(BH_Lock, &bh->b_state); + smp_mb__after_clear_bit(); /* Do not move a list entry if it is waited for * in drbd_wait_{sync,active}_ee @@ -714,16 +715,16 @@ STATIC struct socket *drbd_wait_for_conn if(mdev->conf.try_connect_int) { unsigned long flags; del_timer_sync(&accept_timeout); - spin_lock_irqsave(¤t->sigmask_lock,flags); + spin_lock_irqsave(¤t->SIGMASK_LOCK,flags); if (sigismember(SIGSET_OF(current), DRBD_SIG)) { sigdelset(SIGSET_OF(current), DRBD_SIG); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, + RECALC_SIGPENDING(current); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK, flags); if(sock) sock_release(sock); return 0; } - spin_unlock_irqrestore(¤t->sigmask_lock,flags); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK,flags); } return sock; @@ -789,7 +790,7 @@ int drbd_connect(struct Drbd_Conf* mdev) #else sock->sk->nonagle=0; #endif - sock->sk->sndbuf = 2*65535; + sock->sk->sndbuf = mdev->conf.sndbuf_size ; msock->sk->priority=TC_PRIO_INTERACTIVE; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) @@ -818,7 +819,7 @@ static void syncer_starts(struct Drbd_Co mdev->resync_mark = jiffies; mdev->resync_mark_start = jiffies; /* This is in units of 1024 bytes... */ - mdev->resync_mark_cnt = blk_size[MAJOR_NR][mdev - drbd_conf] << 1; + mdev->resync_mark_cnt = 0; } STATIC inline int receive_cstate(struct Drbd_Conf* mdev) @@ -1192,6 +1193,16 @@ void drbdd(int minor) while (TRUE) { drbd_collect_zombies(minor); // in case a syncer exited. + if(test_bit(BECOME_SECONDARY,&drbd_conf[minor].flags)) { + if(atomic_read(&drbd_conf[minor].pending_cnt) == 0 && + atomic_read(&drbd_conf[minor].unacked_cnt) == 0) { + drbd_set_state(minor,Secondary|DontWait); + if( drbd_conf[minor].state == Secondary ) { + clear_bit(BECOME_SECONDARY, + &drbd_conf[minor].flags); + } + } + } if (drbd_recv(drbd_conf+minor,&header,sizeof(Drbd_Packet),0) != sizeof(Drbd_Packet)) break; @@ -1243,7 +1254,7 @@ void drbdd(int minor) break; case BecomeSec: /* both, secondary_remote */ - drbd_set_state(minor,Secondary); + drbd_set_state(minor,Secondary|DontWait); break; case SetConsistent: /* both, should only happen on SEC at end of Sync */ @@ -1263,6 +1274,7 @@ void drbdd(int minor) out: + drbd_conf[minor].o_state = Unknown; del_timer_sync(&drbd_conf[minor].a_timeout); drbd_thread_stop_nowait(&drbd_conf[minor].syncer); @@ -1326,6 +1338,7 @@ void drbdd(int minor) /* Since syncer's blocks are also counted, there is no hope that pending_cnt is zero. */ atomic_set(&drbd_conf[minor].pending_cnt,0); + smp_mb(); // smp_mb__after_atomic_set(); wake_up_interruptible(&drbd_conf[minor].state_wait); clear_bit(DO_NOT_INC_CONCNT,&drbd_conf[minor].flags); @@ -1350,12 +1363,12 @@ int drbdd_init(struct Drbd_thread *thi) unsigned long flags; thi->t_state = Running; - spin_lock_irqsave(¤t->sigmask_lock,flags); + spin_lock_irqsave(¤t->SIGMASK_LOCK,flags); if (sigismember(SIGSET_OF(current), SIGTERM)) { sigdelset(SIGSET_OF(current), SIGTERM); - recalc_sigpending(current); + RECALC_SIGPENDING(current); } - spin_unlock_irqrestore(¤t->sigmask_lock,flags); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK,flags); } } @@ -1414,10 +1427,10 @@ int drbd_asender(struct Drbd_thread *thi while(thi->t_state == Running) { rr=drbd_recv(mdev,((char*)&pkt)+rsize,sizeof(pkt)-rsize,1); if(rr == -ERESTARTSYS) { - spin_lock_irqsave(¤t->sigmask_lock,flags); + spin_lock_irqsave(¤t->SIGMASK_LOCK,flags); sigemptyset(SIGSET_OF(current)); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock,flags); + RECALC_SIGPENDING(current); + spin_unlock_irqrestore(¤t->SIGMASK_LOCK,flags); rr=0; } else if(rr <= 0) break; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_req-2.2.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_req-2.2.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_req-2.2.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_req-2.2.c 2003-08-17 21:29:12.000000000 +0200 @@ -0,0 +1,284 @@ +/* +-*- linux-c -*- + drbd.c + Kernel module for 2.2.x Kernels + + This file is part of drbd by Philipp Reisner. + + Copyright (C) 1999-2001, Philipp Reisner . + main author. + + drbd 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. + + drbd 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 drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifdef HAVE_AUTOCONF +#include +#endif +#ifdef CONFIG_MODVERSIONS +#include +#endif + +#include +#include "drbd.h" +#include "drbd_int.h" + +void drbd_end_req(struct request *req, int nextstate, int uptodate) +{ + /* This callback will be called in irq context by the IDE drivers, + and in Softirqs/Tasklets/BH context by the SCSI drivers. + This function is called by the receiver in kernel-thread context. + Try to get the locking right :) */ + + struct Drbd_Conf* mdev = &drbd_conf[MINOR(req->rq_dev)]; + int wake_asender=0; + unsigned long flags=0; + + if (req->cmd == READ) + goto end_it_unlocked; + + /* This was a hard one! Can you see the race? + (It hit me about once out of 20000 blocks) + + switch(status) { + ..: status = ...; + } + */ + + spin_lock_irqsave(&mdev->req_lock,flags); + + switch (req->rq_status & 0xfffe) { + case RQ_DRBD_NOTHING: + req->rq_status = nextstate | (uptodate ? 1 : 0); + break; + case RQ_DRBD_SENT: + if (nextstate == RQ_DRBD_WRITTEN) + goto end_it; + printk(KERN_ERR DEVICE_NAME "%d: request state error(A)\n", + (int)(mdev-drbd_conf)); + break; + case RQ_DRBD_WRITTEN: + if (nextstate == RQ_DRBD_SENT) + goto end_it; + printk(KERN_ERR DEVICE_NAME "%d: request state error(B)\n", + (int)(mdev-drbd_conf)); + break; + default: + printk(KERN_ERR DEVICE_NAME "%d: request state error(%X)\n", + (int)(mdev-drbd_conf),req->rq_status); + } + + spin_unlock_irqrestore(&mdev->req_lock,flags); + + return; + +/* We only report uptodate == TRUE if both operations (WRITE && SEND) + reported uptodate == TRUE + */ + + end_it: + spin_unlock_irqrestore(&mdev->req_lock,flags); + + end_it_unlocked: + + if(mdev->cstate >= Connected) { + /* If we are unconnected we may not call tl_dependece, since + then this call could be from tl_clear(). => spinlock deadlock! + */ + if(tl_dependence(mdev,req)) { + set_bit(ISSUE_BARRIER,&mdev->flags); + wake_asender=1; + } + } + + spin_lock_irqsave(&mdev->bb_lock,flags); + bb_done(mdev,req->bh->b_blocknr); + spin_unlock_irqrestore(&mdev->bb_lock,flags); + + if(!end_that_request_first(req, uptodate & req->rq_status,DEVICE_NAME)) + end_that_request_last(req); + + if( mdev->do_panic && !(uptodate & req->rq_status) ) { + panic(DEVICE_NAME": The lower-level device had an error.\n"); + } + + if(wake_asender) { + drbd_queue_signal(DRBD_SIG, mdev->asender.task); + } +} + +void drbd_dio_end(struct buffer_head *bh, int uptodate) +{ + struct request *req = bh->b_dev_id; + + // READs are sorted out in drbd_end_req(). + drbd_end_req(req, RQ_DRBD_WRITTEN, uptodate); + + kfree(bh); +} + +/* + We should _nerver_ sleep with the io_request_lock aquired. (See ll_rw_block) + Up to now I have considered these ways out: + * 1) unlock the io_request_lock for the time of the send + Not possible, because I do not have the flags for the unlock. + -> Forget the flags, look at the loop block device!! + + Non atomic things, that need to be done are: + sock_sendmsg(), kmalloc(,GFP_KERNEL) and ll_rw_block(). +*/ + +/*static */ void drbd_do_request() +{ + struct buffer_head *bh; + int size_kb; + int minor = 0; + struct request *req; + int sending; + unsigned long flags; + struct Drbd_Conf *mdev; + int sent_a_blk=0; + + minor = MINOR(CURRENT->rq_dev); + size_kb=1<<(drbd_conf[minor].blk_size_b-10); + mdev = &drbd_conf[minor]; + + if (blksize_size[MAJOR_NR][minor] != + (1 << drbd_conf[minor].blk_size_b)) { + /* If someone called set_blocksize() from fs/buffer.c ... */ + int new_blksize; + + spin_unlock_irq(&io_request_lock); + + new_blksize = blksize_size[MAJOR_NR][minor]; + set_blocksize(drbd_conf[minor].lo_device, new_blksize); + drbd_conf[minor].blk_size_b = drbd_log2(new_blksize); + + printk(KERN_INFO DEVICE_NAME "%d: blksize=%d B\n", + minor,new_blksize); + + spin_lock_irq(&io_request_lock); + } + while (TRUE) { + INIT_REQUEST; + req=CURRENT; + CURRENT=req->next; + +#if 0 + { + static const char *strs[2] = + { + "READ", + "WRITE" + }; + + /* if(req->cmd == WRITE) */ + printk(KERN_ERR DEVICE_NAME "%d: do_request(cmd=%s," + "sec=%ld,nr_sec=%ld,cnr_sec=%ld)\n", + minor, + strs[req->cmd == READ ? 0 : 1],req->sector, + req->nr_sectors, + req->current_nr_sectors); + } +#endif + + spin_unlock_irq(&io_request_lock); + + sending = 0; + + if (req->cmd == WRITE) { + if ( drbd_conf[minor].cstate >= Connected + && req->sector >= drbd_conf[minor].synced_to) { + sending = 1; + } + } + + bh = kmalloc(sizeof(struct buffer_head), GFP_DRBD); + if (!bh) { + printk(KERN_ERR DEVICE_NAME + "%d: could not kmalloc()\n",minor); + return; + } + + drbd_init_bh(bh, req->bh->b_size, drbd_dio_end); + bh->b_data = req->bh->b_data; // instead of set_bh_page() + + drbd_set_bh(bh, + req->bh->b_rsector / (req->bh->b_size >> 9), + drbd_conf[minor].lo_device); + + bh->b_dev_id = req; + bh->b_state = (1 << BH_Dirty); + + if(req->cmd == WRITE) + drbd_conf[minor].writ_cnt+=size_kb; + else drbd_conf[minor].read_cnt+=size_kb; + + if (sending) + req->rq_status = RQ_DRBD_NOTHING; + else if (req->cmd == WRITE) { + req->rq_status = RQ_DRBD_SENT | 0x0001; + bm_set_bit(drbd_conf[minor].mbds_id, + req->sector >> + (drbd_conf[minor].blk_size_b-9), + drbd_conf[minor].blk_size_b, + SS_OUT_OF_SYNC); + } else req->rq_status = RQ_DRBD_READ | 0x0001; + + + /* Send it out to the network */ + if (sending) { + int bnr; + int send_ok; + sent_a_blk=1; + bnr = req->sector >> (drbd_conf[minor].blk_size_b - 9); + + spin_lock_irqsave(&mdev->bb_lock,flags); + mdev->send_block=bnr; + if( ds_check_block(mdev,bnr) ) { + struct busy_block bl; + bb_wait_prepare(mdev,bnr,&bl); + spin_unlock_irqrestore(&mdev->bb_lock,flags); + bb_wait(&bl); + } else spin_unlock_irqrestore(&mdev->bb_lock,flags); + + send_ok=drbd_send_block(mdev,bh,(unsigned long)req); + mdev->send_block=-1; + + if(send_ok) { + drbd_conf[minor].send_cnt+= + req->current_nr_sectors<<1; + } + + if( drbd_conf[minor].conf.wire_protocol==DRBD_PROT_A || + (!send_ok) ) { + /* If sending failed, we can not expect + an ack packet. */ + drbd_end_req(req, RQ_DRBD_SENT, 1); + } + + } + + ll_rw_block(req->cmd, 1, &bh); + + spin_lock_irq(&io_request_lock); + } + + if(sent_a_blk) { + spin_unlock_irq(&io_request_lock); + drbd_send_cmd(mdev,WriteHint,0); + spin_lock_irq(&io_request_lock); + } +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_req-2.4.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_req-2.4.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_req-2.4.c 2003-05-03 02:33:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_req-2.4.c 2003-08-17 21:29:12.000000000 +0200 @@ -187,7 +187,7 @@ int drbd_make_request(request_queue_t *q mdev->writ_cnt+=size_kb; if( mdev->cstate < Connected || - bh->b_rsector < mdev->synced_to ) { + ( mdev->cstate == SyncingAll && bh->b_rsector > mdev->synced_to )){ bm_set_bit(mdev->mbds_id, bh->b_rsector>>(mdev->blk_size_b-9), mdev->blk_size_b,SS_OUT_OF_SYNC); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_syncer.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_syncer.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/drbd/drbd_syncer.c 2003-05-03 02:33:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/drbd/drbd_syncer.c 2003-08-17 21:29:12.000000000 +0200 @@ -91,6 +91,7 @@ STATIC void ds_end_dio(struct buffer_hea { mark_buffer_uptodate(bh, uptodate); clear_bit(BH_Lock, &bh->b_state); + smp_mb__after_clear_bit(); if (waitqueue_active(&bh->b_wait)) wake_up(&bh->b_wait); @@ -306,12 +307,16 @@ STATIC unsigned long ds_sync_all_get_blk { struct Drbd_Conf *mdev=(struct Drbd_Conf *)id; int shift=ln2_bs - 9; + int minor=(int)(mdev-drbd_conf); - if(mdev->synced_to == 0) { - return MBDS_DONE; + // truncate to full blocks; convert to sectors; + if(mdev->synced_to == + ((blk_size[MAJOR_NR][minor] >> (ln2_bs-10))-1) << (ln2_bs-9) ) { + return MBDS_DONE; } - mdev->synced_to -= (1L<synced_to += (1L<synced_to >> shift; } @@ -367,10 +372,8 @@ int drbd_syncer(struct Drbd_thread *thi) minor,amount_blks); if(drbd_conf[minor].cstate == SyncingAll) { - drbd_conf[minor].synced_to = - ( (blk_size[MAJOR_NR][minor] >> (ln2_bs-10)) - << (ln2_bs-9) ); - // truncate to full blocks; convert to sectors; + drbd_conf[minor].synced_to = -( 1UL << (ln2_bs-9)); + get_blk=&ds_sync_all_get_blk; id=drbd_conf+minor; } else if(drbd_conf[minor].cstate == SyncingQuick) { @@ -383,15 +386,6 @@ int drbd_syncer(struct Drbd_thread *thi) return 0; } - for (m = 0; m < SYNC_MARKS; m++) { - mark[m] = jiffies; - mark_cnt[m] = drbd_conf[minor].synced_to; - } - last_mark = 0; - drbd_conf[minor].resync_mark_start = mark[last_mark]; - drbd_conf[minor].resync_mark = mark[last_mark]; - drbd_conf[minor].resync_mark_cnt = mark_cnt[last_mark]; - ds_buffer_alloc(&buffers[0],minor); ds_buffer_alloc(&buffers[1],minor); disk_b=buffers; @@ -408,6 +402,15 @@ int drbd_syncer(struct Drbd_thread *thi) */ drbd_set_user_nice(current,mdev->conf.sync_nice); + for (m = 0; m < SYNC_MARKS; m++) { + mark[m] = jiffies; + mark_cnt[m] = drbd_conf[minor].synced_to; + } + last_mark = 0; + drbd_conf[minor].resync_mark_start = mark[last_mark]; + drbd_conf[minor].resync_mark = mark[last_mark]; + drbd_conf[minor].resync_mark_cnt = mark_cnt[last_mark]; + while (TRUE) { retry=0; retry: @@ -432,7 +435,7 @@ int drbd_syncer(struct Drbd_thread *thi) if (current->need_resched) schedule(); - currspeed = (mdev->resync_mark_cnt - mdev->synced_to)/2 + currspeed = -(mdev->resync_mark_cnt - mdev->synced_to)/2 / ((jiffies - mdev->resync_mark)/HZ +1) +1; if (currspeed >= SPEED_MIN) { @@ -506,8 +509,6 @@ int drbd_syncer(struct Drbd_thread *thi) ds_buffer_free(&buffers[0]); ds_buffer_free(&buffers[1]); - drbd_conf[minor].synced_to=0; /* this is ok. */ - return 0; } #undef SPEED_MIN diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/elevator.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/elevator.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/elevator.c 2003-08-04 23:06:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/elevator.c 2003-08-17 21:31:36.000000000 +0200 @@ -298,8 +298,12 @@ int blkelvset_ioctl(request_queue_t *q, printk("queue %d: low latency mode is now %s\n", elevator->queue_ID, q->low_latency ? "on" : "off"); input.max_bomb_segments &= ~MAX_BOMB_LATENCY_MASK; - if (input.max_bomb_segments) + if (input.max_bomb_segments) { q->max_queue_sectors = input.max_bomb_segments; + q->batch_sectors = q->max_queue_sectors / 4; + /* changing around these numbers might cause a missed wakeup */ + wake_up(&q->wait_for_requests); + } printk("queue %d: max queue sectors is now %d\n", elevator->queue_ID, q->max_queue_sectors); return 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/ll_rw_blk.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/ll_rw_blk.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/ll_rw_blk.c 2003-08-04 23:06:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/ll_rw_blk.c 2003-08-17 21:31:36.000000000 +0200 @@ -446,6 +446,11 @@ static inline void __generic_unplug_devi q->plugged = 0; if (!list_empty(&q->queue_head)) { + next = blkdev_entry_next_request(&q->queue_head); + + if (next == q->last_merge) + q->last_merge = NULL; + /* we don't want merges later on to come in * and significantly increase the amount of * work during an unplug, it can lead to high @@ -458,12 +463,6 @@ static inline void __generic_unplug_devi rq = blkdev_entry_prev_request(&q->queue_head), rq->elevator_sequence = 0; } - - next = blkdev_entry_next_request(&q->queue_head); - - if (next == q->last_merge) - q->last_merge = NULL; - q->request_fn(q); } } @@ -701,8 +700,8 @@ void blk_init_queue(request_queue_t * q, q->plugged = 0; q->full = 0; q->can_throttle = 0; - q->low_latency = 0; q->last_merge = NULL; + q->low_latency = 0; /* * These booleans describe the queue properties. We set the @@ -736,9 +735,9 @@ static struct request *__get_request(req * pending, bail out */ if ((rw == WRITE) || (rw == READ && rl->pending[READ] > rlim)) - return NULL; + goto full; if (blk_oversized_queue_reads(q)) - return NULL; + goto full; } if (!list_empty(&rl->free)) { @@ -750,8 +749,11 @@ static struct request *__get_request(req rq->cmd = rw; rq->special = NULL; rq->q = q; - } else if (q->low_latency) + } else { +full: q->full = 1; + } + return rq; } @@ -765,7 +767,7 @@ static inline struct request *get_reques return __get_request(q, rw); } -/* +/* * helper func to do memory barriers and wakeups when we finally decide * to clear the queue full condition */ @@ -845,7 +847,6 @@ static struct request *__get_request_wai } while (rq == NULL); remove_wait_queue(&q->wait_for_requests, &wait); current->state = TASK_RUNNING; - if (!waitqueue_active(&q->wait_for_requests)) clear_full_and_wake(q); @@ -1492,9 +1493,6 @@ void __submit_bh(int rw, struct buffer_h if (unlikely(!test_bit(BH_Lock, &bh->b_state))) BUG(); - if (buffer_delay(bh) || !buffer_mapped(bh)) - BUG(); - set_bit(BH_Req, &bh->b_state); set_bit(BH_Launder, &bh->b_state); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/block/nbd.c linux-2.4.20-wolk4.7-fullkernel/drivers/block/nbd.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/block/nbd.c 2003-05-03 02:37:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/block/nbd.c 2003-08-17 21:31:45.000000000 +0200 @@ -26,8 +26,8 @@ * reduce number of partial TCP segments sent. * 01-12-6 Fix deadlock condition by making queue locks independant of * the transmit lock. - * 03-04-12 Fix some possible ways to oops from the nbd-client closing the - * socket it gave us while we're still using that socket. + * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes. + * * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another @@ -103,9 +103,12 @@ static int nbd_xmit(int send, struct soc oldfs = get_fs(); set_fs(get_ds()); + /* Allow interception of SIGKILL only + * Don't allow other signals to interrupt the transmission */ spin_lock_irqsave(¤t->sigmask_lock, flags); oldset = current->blocked; sigfillset(¤t->blocked); + sigdelsetmask(¤t->blocked, sigmask(SIGKILL)); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); @@ -128,6 +131,17 @@ static int nbd_xmit(int send, struct soc else result = sock_recvmsg(sock, &msg, size, 0); + if (signal_pending(current)) { + siginfo_t info; + spin_lock_irqsave(¤t->sigmask_lock, flags); + printk(KERN_WARNING "NBD (pid %d: %s) got signal %d\n", + current->pid, current->comm, + dequeue_signal(¤t->blocked, &info)); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + result = -EINTR; + break; + } + if (result <= 0) { #ifdef PARANOIA printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n", @@ -152,10 +166,10 @@ static int nbd_xmit(int send, struct soc void nbd_send_req(struct nbd_device *lo, struct request *req) { - int result; + int result = -1; struct nbd_request request; unsigned long size = req->nr_sectors << 9; - struct socket *sock; + struct socket *sock = lo->sock; DEBUG("NBD: sending control, "); request.magic = htonl(NBD_REQUEST_MAGIC); @@ -165,8 +179,10 @@ void nbd_send_req(struct nbd_device *lo, memcpy(request.handle, &req, sizeof(req)); down(&lo->tx_lock); - sock = lo->sock; - if (!sock) goto error_out; /* we got cleared */ + + if (!sock || !lo->sock) { + FAIL("Attempted sendmsg to closed socket\n"); + } result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0); if (result <= 0) @@ -349,10 +365,28 @@ static void do_nbd_request(request_queue spin_unlock_irq(&io_request_lock); spin_lock(&lo->queue_lock); + if (!lo->file) { + spin_unlock(&lo->queue_lock); + printk(KERN_ERR "nbd: failed between accept and semaphore, file lost\n"); + req->errors++; + nbd_end_request(req); + spin_lock_irq(&io_request_lock); + continue; + } + list_add_tail(&req->queue, &lo->queue_head); spin_unlock(&lo->queue_lock); nbd_send_req(lo, req); + if (req->errors) { + printk(KERN_ERR "nbd: nbd_send_req failed\n"); + spin_lock(&lo->queue_lock); + list_del(&req->queue); + spin_unlock(&lo->queue_lock); + nbd_end_request(req); + spin_lock_irq(&io_request_lock); + continue; + } spin_lock_irq(&io_request_lock); continue; @@ -394,24 +428,24 @@ static int nbd_ioctl(struct inode *inode return 0 ; case NBD_CLEAR_SOCK: + error = 0; + down(&lo->tx_lock); + lo->sock = NULL; + up(&lo->tx_lock); + spin_lock(&lo->queue_lock); + file = lo->file; + lo->file = NULL; + spin_unlock(&lo->queue_lock); nbd_clear_que(lo); spin_lock(&lo->queue_lock); if (!list_empty(&lo->queue_head)) { - spin_unlock(&lo->queue_lock); - printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n"); - return -EBUSY; + printk(KERN_ERR "nbd: disconnect: some requests are in progress -> please try again.\n"); + error = -EBUSY; } spin_unlock(&lo->queue_lock); - file = lo->file; - if (!file) - return -EINVAL; - lo->file = NULL; - /* ensure we're not in critical section of nbd_send_req() */ - down(&lo->tx_lock); - lo->sock = NULL; - up(&lo->tx_lock); - fput(file); - return 0; + if (file) + fput(file); + return error; case NBD_SET_SOCK: if (lo->file) return -EBUSY; @@ -450,8 +484,38 @@ static int nbd_ioctl(struct inode *inode if (!lo->file) return -EINVAL; nbd_do_it(lo); + /* on return tidy up in case we have a signal */ + /* Forcibly shutdown the socket causing all listeners + * to error + * + * FIXME: This code is duplicated from sys_shutdown, but + * there should be a more generic interface rather than + * calling socket ops directly here */ + down(&lo->tx_lock); + if (lo->sock) { + printk(KERN_WARNING "nbd: shutting down socket\n"); + lo->sock->ops->shutdown(lo->sock, + SEND_SHUTDOWN|RCV_SHUTDOWN); + lo->sock = NULL; + } + up(&lo->tx_lock); + spin_lock(&lo->queue_lock); + file = lo->file; + lo->file = NULL; + spin_unlock(&lo->queue_lock); + nbd_clear_que(lo); + printk(KERN_WARNING "nbd: queue cleared\n"); + if (file) + fput(file); return lo->harderror; case NBD_CLEAR_QUE: + down(&lo->tx_lock); + if (lo->sock) { + up(&lo->tx_lock); + return 0; /* probably should be error, but that would + * break "nbd-client -d", so just return 0 */ + } + up(&lo->tx_lock); nbd_clear_que(lo); return 0; #ifdef PARANOIA @@ -530,7 +594,7 @@ static int __init nbd_init(void) init_MUTEX(&nbd_dev[i].tx_lock); nbd_blksizes[i] = 1024; nbd_blksize_bits[i] = 10; - nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ + nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */ nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS; register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops, nbd_bytesizes[i]>>9); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/char/Config.in linux-2.4.20-wolk4.7-fullkernel/drivers/char/Config.in --- linux-2.4.20-wolk4.6-fullkernel/drivers/char/Config.in 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/char/Config.in 2003-08-17 21:31:43.000000000 +0200 @@ -159,6 +159,8 @@ source drivers/i2c/Config.in source drivers/sensors/Config.in +bool 'PS/2 keyboard support' CONFIG_PSKEYBOARD $CONFIG_EXPERIMENTAL + mainmenu_option next_comment comment 'Mice' tristate 'Bus Mouse Support' CONFIG_BUSMOUSE @@ -263,6 +265,10 @@ fi if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI fi +if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o \ + "$CONFIG_X86_64" = "y" ]; then + dep_tristate 'Intel/AMD/VIA HW Random Number Generator support' CONFIG_HW_RANDOM $CONFIG_PCI +fi dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/char/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/char/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/char/Makefile 2003-08-04 23:06:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/char/Makefile 2003-08-17 21:31:43.000000000 +0200 @@ -245,6 +245,7 @@ obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o obj-$(CONFIG_AMD_RNG) += amd768_rng.o +obj-$(CONFIG_HW_RANDOM) += hw_random.o obj-$(CONFIG_AMD_PM768) += amd76x_pm.o obj-$(CONFIG_ITE_GPIO) += ite_gpio.o diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/char/hw_random.c linux-2.4.20-wolk4.7-fullkernel/drivers/char/hw_random.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/char/hw_random.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/char/hw_random.c 2003-08-17 21:31:43.000000000 +0200 @@ -0,0 +1,631 @@ +/* + Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) + (c) Copyright 2003 Red Hat Inc + + derived from + + Hardware driver for the AMD 768 Random Number Generator (RNG) + (c) Copyright 2001 Red Hat Inc + + derived from + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf + + Please read Documentation/hw_random.txt for details on use. + + ---------------------------------------------------------- + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __i386__ +#include +#include +#endif + +#include +#include + + +/* + * core module and version information + */ +#define RNG_VERSION "1.0.0" +#define RNG_MODULE_NAME "hw_random" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define RNG_NDEBUG /* define to disable lightweight runtime checks */ +#ifdef RNG_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +#define RNG_MISCDEV_MINOR 183 /* official */ + +static int rng_dev_open (struct inode *inode, struct file *filp); +static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, + loff_t * offp); + +static int __init intel_init (struct pci_dev *dev); +static void intel_cleanup(void); +static unsigned int intel_data_present (void); +static u32 intel_data_read (void); + +static int __init amd_init (struct pci_dev *dev); +static void amd_cleanup(void); +static unsigned int amd_data_present (void); +static u32 amd_data_read (void); + +static int __init via_init(struct pci_dev *dev); +static void via_cleanup(void); +static unsigned int via_data_present (void); +static u32 via_data_read (void); + +struct rng_operations { + int (*init) (struct pci_dev *dev); + void (*cleanup) (void); + unsigned int (*data_present) (void); + u32 (*data_read) (void); + unsigned int n_bytes; /* number of bytes per ->data_read */ +}; +static struct rng_operations *rng_ops; + +static struct file_operations rng_chrdev_ops = { + .owner = THIS_MODULE, + .open = rng_dev_open, + .read = rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + +enum { + rng_hw_none, + rng_hw_intel, + rng_hw_amd, + rng_hw_via, +}; + +static struct rng_operations rng_vendor_ops[] = { + /* rng_hw_none */ + { }, + + /* rng_hw_intel */ + { intel_init, intel_cleanup, intel_data_present, + intel_data_read, 1 }, + + /* rng_hw_amd */ + { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 }, + + /* rng_hw_via */ + { via_init, via_cleanup, via_data_present, via_data_read, 1 }, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id rng_pci_tbl[] __initdata = { + { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, + { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, + + { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + + { 0, }, /* terminate list */ +}; +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); + + +/*********************************************************************** + * + * Intel RNG operations + * + */ + +/* + * RNG registers (offsets from rng_mem) + */ +#define INTEL_RNG_HW_STATUS 0 +#define INTEL_RNG_PRESENT 0x40 +#define INTEL_RNG_ENABLED 0x01 +#define INTEL_RNG_STATUS 1 +#define INTEL_RNG_DATA_PRESENT 0x01 +#define INTEL_RNG_DATA 2 + +/* + * Magic address at which Intel PCI bridges locate the RNG + */ +#define INTEL_RNG_ADDR 0xFFBC015F +#define INTEL_RNG_ADDR_LEN 3 + +/* token to our ioremap'd RNG register area */ +static void *rng_mem; + +static inline u8 intel_hwstatus (void) +{ + assert (rng_mem != NULL); + return readb (rng_mem + INTEL_RNG_HW_STATUS); +} + +static inline u8 intel_hwstatus_set (u8 hw_status) +{ + assert (rng_mem != NULL); + writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS); + return intel_hwstatus (); +} + +static unsigned int intel_data_present(void) +{ + assert (rng_mem != NULL); + + return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ? + 1 : 0; +} + +static u32 intel_data_read(void) +{ + assert (rng_mem != NULL); + + return readb (rng_mem + INTEL_RNG_DATA); +} + +static int __init intel_init (struct pci_dev *dev) +{ + int rc; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); + if (rng_mem == NULL) { + printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); + rc = -EBUSY; + goto err_out; + } + + /* Check for Intel 82802 */ + hw_status = intel_hwstatus (); + if ((hw_status & INTEL_RNG_PRESENT) == 0) { + printk (KERN_ERR PFX "RNG not detected\n"); + rc = -ENODEV; + goto err_out_free_map; + } + + /* turn RNG h/w on, if it's off */ + if ((hw_status & INTEL_RNG_ENABLED) == 0) + hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED); + if ((hw_status & INTEL_RNG_ENABLED) == 0) { + printk (KERN_ERR PFX "cannot enable RNG, aborting\n"); + rc = -EIO; + goto err_out_free_map; + } + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out_free_map: + iounmap (rng_mem); + rng_mem = NULL; +err_out: + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + +static void intel_cleanup(void) +{ + u8 hw_status; + + hw_status = intel_hwstatus (); + if (hw_status & INTEL_RNG_ENABLED) + intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED); + else + printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); + iounmap(rng_mem); + rng_mem = NULL; +} + +/*********************************************************************** + * + * AMD RNG operations + * + */ + +static u32 pmbase; /* PMxx I/O base */ +static struct pci_dev *amd_dev; + +static unsigned int amd_data_present (void) +{ + return inl(pmbase + 0xF4) & 1; +} + + +static u32 amd_data_read (void) +{ + return inl(pmbase + 0xF0); +} + +static int __init amd_init (struct pci_dev *dev) +{ + int rc; + u8 rnen; + + DPRINTK ("ENTER\n"); + + pci_read_config_dword(dev, 0x58, &pmbase); + + pmbase &= 0x0000FF00; + + if (pmbase == 0) + { + printk (KERN_ERR PFX "power management base not set\n"); + rc = -EIO; + goto err_out; + } + + pci_read_config_byte(dev, 0x40, &rnen); + rnen |= (1 << 7); /* RNG on */ + pci_write_config_byte(dev, 0x40, rnen); + + pci_read_config_byte(dev, 0x41, &rnen); + rnen |= (1 << 7); /* PMIO enable */ + pci_write_config_byte(dev, 0x41, rnen); + + printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase); + + amd_dev = dev; + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out: + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + +static void amd_cleanup(void) +{ + u8 rnen; + + pci_read_config_byte(amd_dev, 0x40, &rnen); + rnen &= ~(1 << 7); /* RNG off */ + pci_write_config_byte(amd_dev, 0x40, rnen); + + /* FIXME: twiddle pmio, also? */ +} + +/*********************************************************************** + * + * VIA RNG operations + * + */ + +enum { + VIA_STRFILT_CNT_SHIFT = 16, + VIA_STRFILT_FAIL = (1 << 15), + VIA_STRFILT_ENABLE = (1 << 14), + VIA_RAWBITS_ENABLE = (1 << 13), + VIA_RNG_ENABLE = (1 << 6), + VIA_XSTORE_CNT_MASK = 0x0F, + + VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ + VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ + VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, + VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ + VIA_RNG_CHUNK_2_MASK = 0xFFFF, + VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ + VIA_RNG_CHUNK_1_MASK = 0xFF, +}; + +u32 via_rng_datum; + +/* + * Investigate using the 'rep' prefix to obtain 32 bits of random data + * in one insn. The upside is potentially better performance. The + * downside is that the instruction becomes no longer atomic. Due to + * this, just like familiar issues with /dev/random itself, the worst + * case of a 'rep xstore' could potentially pause a cpu for an + * unreasonably long time. In practice, this condition would likely + * only occur when the hardware is failing. (or so we hope :)) + * + * Another possible performance boost may come from simply buffering + * until we have 4 bytes, thus returning a u32 at a time, + * instead of the current u8-at-a-time. + */ + +static inline u32 xstore(u32 *addr, u32 edx_in) +{ + u32 eax_out; + + asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" + :"=m"(*addr), "=a"(eax_out) + :"D"(addr), "d"(edx_in)); + + return eax_out; +} + +static unsigned int via_data_present(void) +{ + u32 bytes_out; + + /* We choose the recommended 1-byte-per-instruction RNG rate, + * for greater randomness at the expense of speed. Larger + * values 2, 4, or 8 bytes-per-instruction yield greater + * speed at lesser randomness. + * + * If you change this to another VIA_CHUNK_n, you must also + * change the ->n_bytes values in rng_vendor_ops[] tables. + * VIA_CHUNK_8 requires further code changes. + * + * A copy of MSR_VIA_RNG is placed in eax_out when xstore + * completes. + */ + via_rng_datum = 0; /* paranoia, not really necessary */ + bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK; + if (bytes_out == 0) + return 0; + + return 1; +} + +static u32 via_data_read(void) +{ + return via_rng_datum; +} + +static int __init via_init(struct pci_dev *dev) +{ + u32 lo, hi, old_lo; + + /* Control the RNG via MSR. Tread lightly and pay very close + * close attention to values written, as the reserved fields + * are documented to be "undefined and unpredictable"; but it + * does not say to write them as zero, so I make a guess that + * we restore the values we find in the register. + */ + rdmsr(MSR_VIA_RNG, lo, hi); + + old_lo = lo; + lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); + lo &= ~VIA_XSTORE_CNT_MASK; + lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); + lo |= VIA_RNG_ENABLE; + + if (lo != old_lo) + wrmsr(MSR_VIA_RNG, lo, hi); + + /* perhaps-unnecessary sanity check; remove after testing if + unneeded */ + rdmsr(MSR_VIA_RNG, lo, hi); + if ((lo & VIA_RNG_ENABLE) == 0) { + printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); + return -ENODEV; + } + + return 0; +} + +static void via_cleanup(void) +{ + u32 lo, hi; + + rdmsr(MSR_VIA_RNG, lo, hi); + lo &= ~VIA_RNG_ENABLE; + wrmsr(MSR_VIA_RNG, lo, hi); +} + + +/*********************************************************************** + * + * /dev/hwrandom character device handling (major 10, minor 183) + * + */ + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + /* enforce read-only access to this chrdev */ + if ((filp->f_mode & FMODE_READ) == 0) + return -EINVAL; + if (filp->f_mode & FMODE_WRITE) + return -EINVAL; + + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, + loff_t * offp) +{ + static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; + unsigned int have_data; + u32 data = 0; + ssize_t ret = 0; + + while (size) { + spin_lock(&rng_lock); + + have_data = 0; + if (rng_ops->data_present()) { + data = rng_ops->data_read(); + have_data = rng_ops->n_bytes; + } + + spin_unlock (&rng_lock); + + while (have_data && size) { + if (put_user((u8)data, buf++)) { + ret = ret ? : -EFAULT; + break; + } + size--; + ret++; + have_data--; + data>>=8; + } + + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + if(need_resched()) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + else + udelay(200); /* FIXME: We could poll for 250uS ?? */ + + if (signal_pending (current)) + return ret ? : -ERESTARTSYS; + } + return ret; +} + + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev) +{ + int rc; + + DPRINTK ("ENTER\n"); + + assert(rng_ops != NULL); + + rc = rng_ops->init(dev); + if (rc) + goto err_out; + + rc = misc_register (&rng_miscdev); + if (rc) { + printk (KERN_ERR PFX "misc device register failed\n"); + goto err_out_cleanup_hw; + } + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out_cleanup_hw: + rng_ops->cleanup(); +err_out: + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + + + +MODULE_AUTHOR("The Linux Kernel team"); +MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL"); + + +/* + * rng_init - initialize RNG module + */ +static int __init rng_init (void) +{ + int rc; + struct pci_dev *pdev = NULL; + const struct pci_device_id *ent; + + DPRINTK ("ENTER\n"); + + /* Probe for Intel, AMD RNGs */ + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { + ent = pci_match_device (rng_pci_tbl, pdev); + if (ent) { + rng_ops = &rng_vendor_ops[ent->driver_data]; + goto match; + } + } + +#ifdef __i386__ + /* Probe for VIA RNG */ + if (cpu_has_xstore) { + rng_ops = &rng_vendor_ops[rng_hw_via]; + pdev = NULL; + goto match; + } +#endif + + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + +match: + rc = rng_init_one (pdev); + if (rc) + return rc; + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_init - shutdown RNG module + */ +static void __exit rng_cleanup (void) +{ + DPRINTK ("ENTER\n"); + + misc_deregister (&rng_miscdev); + + if (rng_ops->cleanup) + rng_ops->cleanup(); + + DPRINTK ("EXIT\n"); +} + + +module_init (rng_init); +module_exit (rng_cleanup); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/char/mem.c linux-2.4.20-wolk4.7-fullkernel/drivers/char/mem.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/char/mem.c 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/char/mem.c 2003-08-17 21:30:36.000000000 +0200 @@ -27,9 +27,6 @@ #include #include -#ifdef CONFIG_SENSORS -extern void sensors_init_all(void); -#endif #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif @@ -634,6 +631,11 @@ static int mmap_kmem(struct file * file, unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long size = vma->vm_end - vma->vm_start; +#ifdef CONFIG_GRKERNSEC_KMEM + if (gr_handle_mem_mmap(offset, vma)) + return -EPERM; +#endif + /* * If the user is not attempting to mmap a high memory address then * the standard mmap_mem mechanism will work. High memory addresses @@ -817,10 +819,6 @@ int __init chr_dev_init(void) #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) tapechar_init(); #endif -#ifdef CONFIG_SENSORS - sensors_init_all(); -#endif - return 0; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/char/serial.c linux-2.4.20-wolk4.7-fullkernel/drivers/char/serial.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/char/serial.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/char/serial.c 2003-08-17 21:31:13.000000000 +0200 @@ -6071,12 +6071,18 @@ static int __init serial_console_setup(s if (kdb_serial_line == -1) { kdb_serial_line = co->index; kdb_serial.io_type = info->io_type; - if (info->io_type == SERIAL_IO_MEM) { + switch (info->io_type) { + case SERIAL_IO_MEM: +#ifdef SERIAL_IO_MEM32 + case SERIAL_IO_MEM32: +#endif kdb_serial.iobase = (unsigned long)(info->iomem_base); kdb_serial.ioreg_shift = info->iomem_reg_shift; - } else { + break; + default: kdb_serial.iobase = state->port; kdb_serial.ioreg_shift = 0; + break; } } #endif /* CONFIG_SERIAL_CONSOLE && CONFIG_KDB */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/AIXlvm_vge.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/AIXlvm_vge.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/AIXlvm_vge.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/AIXlvm_vge.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,3681 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ -/* - * linux/drivers/evms/AIXlvm_vge.c - * - * EVMS AIX LVM Volume Group Emulator - * - * - */ - -#define EVMS_DEBUG 1 -#define EVMS_AIX_DEBUG 1 - -#define AIX_COMMON_SERVICES_MAJOR 0 // Required common services levels for the AIX kernel plugin -#define AIX_COMMON_SERVICES_MINOR 5 // These must be incremented if new function is added to common -#define AIX_COMMON_SERVICES_PATCHLEVEL 0 // services and the AIX kernel plugin uses the new function. -#define AIX_INCREMENT_REQUEST 1 -#define AIX_DECREMENT_REQUEST -1 -#define AIX_RESYNC_BLOCKSIZE 512 -#define AIX_SYNC_INCOMPLETE 0x01 -#define AIX_SYNC_COMPLETE 0x00 -#define AIX_MASTER 0 -#define AIX_SLAVE_1 1 -#define AIX_SLAVE_2 2 - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef EVMS_AIX_DEBUG -static int AIX_volume_group_dump(void); -#endif - -static struct aix_volume_group *AIXVolumeGroupList = NULL; -static struct evms_thread *AIX_mirror_read_retry_thread; -static struct evms_thread *AIX_mirror_resync_thread; -static struct evms_pool_mgmt *AIX_BH_list_pool = NULL; -static struct aix_mirror_bh *AIX_retry_list = NULL; -static struct aix_mirror_bh **AIX_retry_tail = NULL; -static spinlock_t AIX_retry_list_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t AIX_resync_list_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t AIX_resync_pp_lock = SPIN_LOCK_UNLOCKED; -static int AIXResyncInProgress = FALSE; -static struct aix_resync_struct *AIX_resync_list = NULL; - -// Plugin API prototypes - -static void AIXiod(void *data); -static void AIXresync(void *data); -static int discover_aix(struct evms_logical_node **evms_logical_disk_head); -static int discover_volume_groups(struct evms_logical_node **); -static int discover_logical_volumes(void); -static int end_discover_aix(struct evms_logical_node **evms_logical_disk_head); -static void read_aix(struct evms_logical_node *node, struct buffer_head *bh); -static void write_aix(struct evms_logical_node *node, struct buffer_head *bh); -static int ioctl_aix(struct evms_logical_node *logical_node, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg); - -static int aix_direct_ioctl(struct inode *inode, - struct file *file, - unsigned int cmd, unsigned long args); - -static int AIX_remap_sector(struct evms_logical_node *node, u64 org_sector, // logical sector to remap - u64 size, // size (in sectors) of request to remap - u64 * new_sector, // remapped sector - u64 * new_size, // new size (in sectors) - struct partition_list_entry **partition, // new node for which new_sector is relative - u32 * le, u32 * offset_in_le); - -static int validate_build_volume_group_disk_info(struct evms_logical_node - *logical_node, - struct AIXlvm_rec *AIXlvm); - -static int add_VG_data_to_VG_list(struct evms_logical_node *logical_node, - struct aix_volume_group *new_group, - short int pvNum); -static int add_PV_to_volume_group(struct aix_volume_group *group, - struct evms_logical_node *evms_partition, - int pvNum); -static struct aix_volume_group *AIX_create_volume_group(struct evms_logical_node - *logical_node, - struct AIXlvm_rec - *AIXlvm); - -static int AIX_update_volume_group(struct aix_volume_group *AIXVGLptr, - struct evms_logical_node *logical_node, - struct AIXlvm_rec *AIXlvm); - -static int AIX_evms_cs_notify_lv_io_error(struct evms_logical_node *node); - -static int AIX_pvh_data_posn(u32 vgda_psn, u32 * pvh_posn, struct partition_list_entry *partition, u32 numpvs); - -static int AIX_resync_lv_mirrors(struct aix_logical_volume *volume, int force); - -static int AIX_copy_on_read(struct aix_logical_volume *volume, - struct partition_list_entry *master_part, - struct partition_list_entry *slave1_part, - struct partition_list_entry *slave2_part, - u64 master_offset, - u64 slave1_offset, - u64 slave2_offset, u32 pe_size, int le); - -static int export_volumes(struct evms_logical_node **evms_logical_disk_head); -static int lvm_cleanup(void); -static int AIX_copy_header_info(struct vg_header *AIXvgh, - struct vg_header *AIXvgh2); -static int build_pe_maps(struct aix_volume_group *volume_group); - -static struct aix_logical_volume *new_logical_volume(struct lv_entries - *AIXlvent, - struct aix_volume_group - *group, char *lv_name, - u32 stripesize); - -static int check_log_volume_and_pe_maps(struct aix_volume_group *group); -static int check_volume_groups(void); -static int init_io_aix(struct evms_logical_node *node, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr); /* buffer address */ - -static int delete_logical_volume(struct aix_logical_volume *volume); -static int delete_aix_node(struct evms_logical_node *logical_node); -static int deallocate_volume_group(struct aix_volume_group *group); - -static void AIX_handle_read_mirror_drives(struct buffer_head *bh, int uptodate); - -static void AIX_handle_write_mirror_drives(struct buffer_head *bh, - int uptodate); - -static void aix_notify_cache_ctor(void *foo, kmem_cache_t * cachep, - unsigned long flags); - -static void AIX_schedule_resync(struct aix_logical_volume *resync_volume, - int force); -static struct aix_logical_volume *AIX_get_volume_data(char *object_name); - -static void AIX_sync_mirrored_partitions(struct buffer_head *bh, int uptodate); - -static int AIX_get_set_mirror_offset(struct aix_mirror_bh *tmp_bh, - int index, int offset); - -static struct aix_mirror_bh *AIX_alloc_rbh(struct evms_logical_node *node, - struct buffer_head *bh, - u32 mirror_copies, - u32 le, u64 org_sector, int cmd); - -static struct aix_mirror_bh *AIX_alloc_wbh(struct evms_logical_node *node, - struct evms_logical_node *node2, - struct evms_logical_node *node3, - struct buffer_head *bh, - u32 mirror_copies, - u32 le, - u64 new_sector2, u64 new_sector3); - -static struct aix_mirror_bh *AIX_alloc_sbh(struct aix_logical_volume *volume, - struct partition_list_entry - *master_part, - struct partition_list_entry - *slave1_part, - struct partition_list_entry - *slave2_part, u64 master_offset, - u64 slave1_offset, u64 slave2_offset, - u32 pe_size); - -static void AIX_free_headers(struct vg_header *AIXvgh, - struct vg_header *AIXvgh2, - struct vg_trailer *AIXvgt, - struct vg_trailer *AIXvgt2); - -static int remove_group_from_list(struct aix_volume_group *group); - -//**************************************************************************************************** - -/* END of PROTOTYES*/ - -#define GET_PHYSICAL_PART_SIZE(v1) (1 << v1) - -#define COMPARE_TIMESTAMPS(t1, t2) ( (t1).tv_sec == (t2).tv_sec && \ - (t1).tv_nsec == (t2).tv_nsec ) - -#define COMPARE_UNIQUE_IDS(id1, id2) ( (id1).word1 == (id2).word1 && \ - (id1).word2 == (id2).word2 && \ - (id1).word3 == (id2).word3 && \ - (id1).word4 == (id2).word4 ) - -#define SECTOR_IN_RANGE(s1, s2) ((s2 > s1) && (s2 < s1 + AIX_RESYNC_BLOCKSIZE)) - -#define AIX_PV_STATE_VALID 0 // Both VGDAs are valid and match. -#define AIX_PV_STATE_FIRST_VGDA 1 // Only the first VGDA is valid. -#define AIX_PV_STATE_SECOND_VGDA 2 // Only the second VGDA is valid. -#define AIX_PV_STATE_EITHER_VGDA -1 // Both VGDAs are valid, but do not match each other. -#define AIX_PV_STATE_INVALID -2 // We're in an invalid state but there's more PVs in this group - -#ifndef EVMS_AIX_DEBUG -#define AIX_VOLUME_GROUP_DUMP() -#else -#define AIX_VOLUME_GROUP_DUMP() LOG_DEBUG("Called line:%d \n",__LINE__); \ - AIX_volume_group_dump() -#endif - -// Global LVM data structures - -static struct evms_plugin_fops AIXlvm_fops = { - .discover = discover_aix, - .end_discover = end_discover_aix, - .delete = delete_aix_node, - .read = read_aix, - .write = write_aix, - .init_io = init_io_aix, - .ioctl = ioctl_aix, - .direct_ioctl = aix_direct_ioctl -}; - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_REGION_MANAGER, - EVMS_AIX_FEATURE_ID), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2}, - .required_services_version = { - .major = AIX_COMMON_SERVICES_MAJOR, - .minor = AIX_COMMON_SERVICES_MINOR, - .patchlevel = - AIX_COMMON_SERVICES_PATCHLEVEL}, - .fops = &AIXlvm_fops -}; - -/* - * Function: remap sector - * Common function to remap volume lba to partition lba in appropriate PE - */ -static int -AIX_remap_sector(struct evms_logical_node *node, u64 org_sector, // logical sector to remap - u64 size, // size (in sectors) of request to remap - u64 * new_sector, // remapped sector - u64 * new_size, // new size (in sectors) - struct partition_list_entry **partition, // new node for which new_sector is relative - u32 * le, u32 * offset_in_le) -{ - struct aix_logical_volume *volume; - - u32 sectors_per_stripe; - u32 partition_to_use; - u32 column; - u32 stripe_in_column; - - u32 org_sector32; // Until striping is 64-bit enabled. - - volume = (struct aix_logical_volume *) node->private; - -#ifdef EVMS_DEBUG - LOG_DEBUG("-- %s volume:%p lv:%d size:" PFU64 " Name:%s\n", - __FUNCTION__, volume, volume->lv_number, size, volume->name); - LOG_DEBUG(" node %p node_name [%s] org_sector:" PFU64 "\n", node, - node->name, org_sector); - LOG_DEBUG(" mirror_copies:%d volume->lv_size:" PFU64 "\n", - volume->mirror_copies, volume->lv_size); -#endif - - org_sector32 = org_sector; - - *(new_size) = size; - - // Check if volume is striped. Reset the size if the request - // crosses a stripe boundary. - if (volume->stripes > 1) { -#ifdef EVMS_DEBUG - LOG_DEBUG(" *** STRIPED ***\n"); - LOG_DEBUG(" ------- volume->stripe_size:%d org_sector:%d volume_stripes:%d\n", - volume->stripe_size, org_sector32, volume->stripes); -#endif - - *(le) = org_sector >> volume->pe_size_shift; // 64-bit safe - *(offset_in_le) = org_sector & (volume->pe_size - 1); // 64-bit safe - -#ifdef EVMS_DEBUG - LOG_DEBUG("OLD - le:%d -- offset_in_le:%d \n", *(le), - *(offset_in_le)); -#endif - - sectors_per_stripe = volume->stripe_size / AIX_SECTOR_SIZE; - partition_to_use = - (org_sector32 / sectors_per_stripe) % volume->stripes; - stripe_in_column = - ((((org_sector32 / volume->stripe_size) / volume->stripes) * - volume->stripe_size) + - (org_sector32 % sectors_per_stripe)); - column = - ((org_sector32 / sectors_per_stripe) / volume->stripes) * - sectors_per_stripe; - -#ifdef EVMS_DEBUG - LOG_DEBUG("offset_in_le:%d org_sector:" PFU64 - " pe_shift:%d stripe_shift:%d\n", *(offset_in_le), - org_sector, volume->pe_size_shift, - volume->stripe_size_shift); - - LOG_DEBUG(" org_sector:%d sectors_per_stripe:%d partition_to_use:%d stripe_in_column:%d column:%d\n", - org_sector32, sectors_per_stripe, partition_to_use, - stripe_in_column, column); - LOG_DEBUG(" offset_in_le + size:" PFU64 - " volume->pe_size:%d volume->lv_size:" PFU64 "\n", - (*(offset_in_le) + size), volume->pe_size, - volume->lv_size); -#endif - - if (*(offset_in_le) + size > volume->pe_size) { - *new_size = volume->pe_size - *(offset_in_le); - LOG_DEBUG(" new_size " PFU64 "\n", *new_size); - } - - } - // Non-striped volume. Just find LE and offset. Reset the size - // if the request crosses an LE boundary. - else { -#ifdef EVMS_DEBUG - LOG_DEBUG(" *** NON-STRIPED ***\n"); -#endif - - *(le) = org_sector >> volume->pe_size_shift; // 64-bit safe - *(offset_in_le) = org_sector & (volume->pe_size - 1); // 64-bit safe - - } - -#ifdef EVMS_DEBUG - LOG_DEBUG(" offset_in_le:%d org_sector:" PFU64 " shift:%d\n", - *(offset_in_le), org_sector, volume->pe_size_shift); - - if (*(le) >= volume->num_le) { - LOG_DEBUG(" le Memory Overwrite !! le:%d vs volume->num_le:%d\n", - *(le), volume->num_le); - return -EINVAL; - } -#endif - - *(new_sector) = volume->le_to_pe_map[*(le)].pe_sector_offset + *(offset_in_le); - *(partition) = volume->le_to_pe_map[*(le)].owning_pv; - -#ifdef EVMS_DEBUG - LOG_DEBUG(" new_sector:" PFU64 "\n", *(new_sector)); - LOG_DEBUG(" Owning Part %p\n", *(partition)); - LOG_DEBUG(" End %s\n", __FUNCTION__); -#endif - - return (0); -} - -/* - * Function: read_aix - */ -static void -read_aix(struct evms_logical_node *node, struct buffer_head *bh) -{ - struct partition_list_entry *partition; - u64 org_sector; - u64 new_sector; - u64 new_size; - struct aix_logical_volume *volume; - struct aix_mirror_bh *tmp_bh; - u32 le, offset_in_le, count; - int flags = 0; - - volume = (struct aix_logical_volume *) node->private; -//#ifdef EVMS_DEBUG -// LOG_DEBUG(" ***** %s ***** bh:%p volume->iter:%d\n", __FUNCTION__, bh, -// volume->mirror_iterations); -//#endif - -#ifdef EVMS_DEBUG - LOG_DEBUG(" node->total_vsectors:" PFU64 "\n", node->total_vsectors); - LOG_DEBUG(" rsector:%lu rsize:%u node_flags:%u\n", bh->b_rsector, - bh->b_size, node->flags); -#endif - - // Check if I/O goes past end of logical volume. - if (bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) > - node->total_vsectors) { - LOG_CRITICAL(" read_aix ERROR %d\n", __LINE__); - buffer_IO_error(bh); - return; - } - - // Logical-to-physical remapping. - if (AIX_remap_sector - (node, bh->b_rsector, (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT), - &new_sector, &new_size, &partition, &le, &offset_in_le) - || (!partition || !new_sector)) { - LOG_CRITICAL(" read_aix bh: ERROR %d\n", __LINE__); - buffer_IO_error(bh); - return; - } - - org_sector = bh->b_rsector; - bh->b_rsector = new_sector; - //bh->b_size = new_size; - -#ifdef EVMS_DEBUG - LOG_DEBUG(" read_aix Mirror_Copies:%d\n", volume->mirror_copies); -#endif - - if (volume->mirror_copies > AIX_DEFAULT_MIRRORING) { - - tmp_bh = - AIX_alloc_rbh(node, bh, 1, le, new_sector, AIX_LV_READ); - - if (!tmp_bh) { - buffer_IO_error(bh); - return; - } - - if (volume->le_to_pe_map_mir1) { - tmp_bh->mir_node1 = - volume->le_to_pe_map_mir1[le].owning_pv-> - logical_node; - tmp_bh->mir_sector1 = - volume->le_to_pe_map_mir1[le].pe_sector_offset + - offset_in_le; - } - - if (volume->mirror_copies == AIX_MAX_MIRRORS) { - tmp_bh->mir_node2 = - volume->le_to_pe_map_mir2[le].owning_pv-> - logical_node; - tmp_bh->mir_sector2 = - volume->le_to_pe_map_mir2[le].pe_sector_offset + - offset_in_le; - } - - if (evms_cs_volume_request_in_progress - (tmp_bh->bh_req.b_rdev, AIX_INCREMENT_REQUEST, &count)) { - buffer_IO_error(bh); - return; - } - - if (AIXResyncInProgress) { - if (SECTOR_IN_RANGE - (tmp_bh->bh_req.b_rsector, - AIX_resync_list->master_offset)) { - spin_lock_irqsave(&AIX_resync_list_lock, flags); - } - } - - R_IO(partition->logical_node, &tmp_bh->bh_req); - - if (AIXResyncInProgress) { - if (SECTOR_IN_RANGE - (tmp_bh->bh_req.b_rsector, - AIX_resync_list->master_offset)) { - spin_unlock_irqrestore(&AIX_resync_list_lock, - flags); - } - } - - } else { - - R_IO(partition->logical_node, bh); - } - -#ifdef EVMS_DEBUG - LOG_DEBUG(" ***** %s ***** returning\n", __FUNCTION__); -#endif - return; -} - -/* - * Function: write_aix - */ -static void -write_aix(struct evms_logical_node *node, struct buffer_head *bh) -{ - struct partition_list_entry *partition; - u64 new_sector, new_sector2 = 0, new_sector3 = 0; - u64 org_sector; - u64 new_size; - struct aix_logical_volume *volume; - struct aix_mirror_bh *tmp_bh; - struct evms_logical_node *node2 = NULL, *node3 = NULL; - u32 le, offset_in_le, count; - int flags = 0; - - volume = (struct aix_logical_volume *) node->private; - -#ifdef EVMS_DEBUG -// LOG_DEBUG(" ***** %s ***** bh:%p volume->iter:%d\n", __FUNCTION__, bh, -// volume->mirror_iterations); - LOG_DEBUG(" write_aix rsector:%lu rsize:%u\n", bh->b_rsector, - bh->b_size); - LOG_DEBUG(" write_aix total_sectors:" PFU64 "\n", node->total_vsectors); -#endif - - if (volume->lv_access & EVMS_LV_INCOMPLETE) { //No writes allowed on incomplete volumes - LOG_CRITICAL(" write_aix incomplete volume ERROR %d\n", - __LINE__); - buffer_IO_error(bh); - return; - } - - // Check if I/O goes past end of logical volume. - if (bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) > - node->total_vsectors) { - LOG_CRITICAL(" write_aix ERROR %d\n", __LINE__); - buffer_IO_error(bh); - return; - } - // Logical-to-Physical remapping - if (AIX_remap_sector - (node, bh->b_rsector, (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT), - &new_sector, &new_size, &partition, &le, &offset_in_le) - || (!new_sector || !partition)) { - LOG_CRITICAL(" write_aix ERROR %d\n", __LINE__); - buffer_IO_error(bh); - return; - } - - org_sector = bh->b_rsector; - bh->b_rsector = new_sector; - //bh->b_size = new_size; - -#ifdef EVMS_DEBUG - LOG_DEBUG(" write_aix Mirror_Copies:%d\n", volume->mirror_copies); -#endif - - if (volume->mirror_copies > AIX_DEFAULT_MIRRORING) { - - if (volume->le_to_pe_map_mir1) { - new_sector2 = - volume->le_to_pe_map_mir1[le].pe_sector_offset + - offset_in_le; - node2 = - volume->le_to_pe_map_mir1[le].owning_pv-> - logical_node; - } - - if (volume->mirror_copies == AIX_MAX_MIRRORS) { - - new_sector3 = - volume->le_to_pe_map_mir2[le].pe_sector_offset + - offset_in_le; - node3 = - volume->le_to_pe_map_mir2[le].owning_pv-> - logical_node; - } - - tmp_bh = - AIX_alloc_wbh(partition->logical_node, node2, node3, bh, le, - volume->mirror_copies, new_sector2, - new_sector3); - - if (!tmp_bh) { - buffer_IO_error(bh); - return; - } - tmp_bh->node = node; - - tmp_bh = tmp_bh->mirror_bh_list; - - if (evms_cs_volume_request_in_progress - (tmp_bh->bh_req.b_rdev, AIX_INCREMENT_REQUEST, &count)) { - buffer_IO_error(bh); - // free memory here - return; - } - - if (AIXResyncInProgress) { - if (SECTOR_IN_RANGE - (tmp_bh->bh_req.b_rsector, - AIX_resync_list->master_offset)) { - spin_lock_irqsave(&AIX_resync_list_lock, flags); - } - } - - W_IO(tmp_bh->node, &tmp_bh->bh_req); - - if (AIXResyncInProgress) { - if (SECTOR_IN_RANGE - (tmp_bh->bh_req.b_rsector, - AIX_resync_list->master_offset)) { - spin_unlock_irqrestore(&AIX_resync_list_lock, - flags); - } - } - - tmp_bh = tmp_bh->next_r1; - - if (tmp_bh) { - W_IO(tmp_bh->node, &tmp_bh->bh_req); - tmp_bh = tmp_bh->next_r1; - } - - if (tmp_bh) { - W_IO(tmp_bh->node, &tmp_bh->bh_req); - } - - } else { - - W_IO(partition->logical_node, bh); - } - -#ifdef EVMS_DEBUG - LOG_DEBUG(" ***** %s returning *****\n", __FUNCTION__); -#endif - return; -} - -/* - * Function: ioctl_aix - * - */ -static int -ioctl_aix(struct evms_logical_node *logical_node, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - struct aix_logical_volume *volume = - (struct aix_logical_volume *) (logical_node->private); - int rc = 0; - - LOG_EXTRA(" Ioctl %u\n", cmd); - - switch (cmd) { - - case HDIO_GETGEO: - { - // Fixed geomerty for all LVM volumes - unsigned char heads = 64; - unsigned char sectors = 32; - long start = 0; - struct hd_geometry *hd = (struct hd_geometry *) arg; - short cylinders; - cylinders = logical_node->total_vsectors; - cylinders = (cylinders / heads) / sectors; - - if (hd == NULL) { - return -EINVAL; - } - - if (copy_to_user - ((char *) (&hd->heads), &heads, sizeof (heads)) != 0 - || copy_to_user((char *) (&hd->sectors), §ors, - sizeof (sectors)) != 0 - || copy_to_user((short *) (&hd->cylinders), - &cylinders, sizeof (cylinders)) != 0 - || copy_to_user((long *) (&hd->start), &start, - sizeof (start)) != 0) { - return -EFAULT; - } - } - break; - - case EVMS_QUIESCE_VOLUME: - break; - - case EVMS_GET_DISK_LIST: - case EVMS_CHECK_MEDIA_CHANGE: - case EVMS_REVALIDATE_DISK: - case EVMS_OPEN_VOLUME: - case EVMS_CLOSE_VOLUME: - case EVMS_CHECK_DEVICE_STATUS: - { - // These five ioctl all need to be broadcast to all PVs. - struct aix_volume_group *group = volume->group; - struct partition_list_entry *partition; - for (partition = group->partition_list; partition; - partition = partition->next) { - rc |= - IOCTL(partition->logical_node, inode, file, - cmd, arg); - } - } - break; - - default: - // Currently the VGE does not send any ioctl's down to the - // partitions. Which partition would they go to? - rc = -ENOTTY; - } - - return rc; -} - -/* Function: aix_direct_ioctl - * - * This function provides a method for user-space to communicate directly - * with a plugin in the kernel. - */ -static int -aix_direct_ioctl(struct inode *inode, - struct file *file, unsigned int cmd, unsigned long args) -{ - struct aix_logical_volume *volume = NULL; - struct evms_plugin_ioctl_pkt argument; - int rc = 0; - - MOD_INC_USE_COUNT; - LOG_DEBUG(" Function:%s cmd:%d \n", __FUNCTION__, cmd); - - // Copy user's parameters to kernel space - if (copy_from_user - (&argument, (struct evms_plugin_ioctl *) args, sizeof (argument))) { - MOD_DEC_USE_COUNT; - return -EFAULT; - } - // Make sure this is supposed to be our ioctl. - if (argument.feature_id != plugin_header.id) { - MOD_DEC_USE_COUNT; - return -EINVAL; - } - - argument.feature_command = 1; - - switch (argument.feature_command) { - - case EVMS_AIX_RESYNC_MIRRORS: - { - struct aix_volume_resync_ioctl aix_lv_resync; - - if (copy_from_user - (&aix_lv_resync, - (struct aix_volume_resync_ioctl *) argument. - feature_ioctl_data, sizeof (aix_lv_resync))) { - rc = -EINVAL; - break; - } - - volume = AIX_get_volume_data(aix_lv_resync.object_name); - - if (volume) { - AIX_schedule_resync(volume, FALSE); - } else { - LOG_DEBUG - (" Function:%s object_name:%s -- no match found\n", - __FUNCTION__, aix_lv_resync.object_name); - rc = -EINVAL; - } - - } - break; - - default: - rc = -EINVAL; - break; - } - - argument.status = rc; - copy_to_user((struct evms_plugin_ioctl *) args, &argument, - sizeof (argument)); - MOD_DEC_USE_COUNT; - return rc; -} - -/* Function: aix_direct_ioctl - * - * This function provides a method for user-space to communicate directly - * with a plugin in the kernel. - */ -static struct aix_logical_volume * -AIX_get_volume_data(char *object_name) -{ - - struct aix_volume_group *VG_ptr; - struct aix_logical_volume *volume = NULL; - int i; - - LOG_DEBUG(" Function:%s object_name:%s \n", __FUNCTION__, object_name); - - if (!object_name || !strlen(object_name)) { - return NULL; - } - - for (VG_ptr = AIXVolumeGroupList; VG_ptr; VG_ptr = VG_ptr->next) { - for (i = 0; VG_ptr->volume_list[i]; i++) { - if (!strcmp(VG_ptr->volume_list[i]->name, object_name)) { - LOG_DEBUG - (" Function:%s FOUND!! volume_name:%s \n", - __FUNCTION__, - VG_ptr->volume_list[i]->name); - volume = VG_ptr->volume_list[i]; - break; - } - } - } - - if (!volume) { - LOG_DEBUG(" Function:%s object_name:%s NOT FOUND !! volume:%p \n", - __FUNCTION__, object_name, volume); - } - - return volume; -} - -/* - * Function: init_io_aix - * - */ -static int -init_io_aix(struct evms_logical_node *node, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr) -{ /* buffer address */ - struct partition_list_entry *partition; - u64 new_sector = 0; - u64 new_size = 0; - int rc = 0; - u32 le, offset; - - LOG_DEBUG(" ************ init_io_aix() num_sects:" PFU64 - " node:%p sect_nr:" PFU64 "\n", num_sects, node, sect_nr); - - // Init IO needs to deal with the possibility that a request can come - // in that spans PEs or stripes. This is possible because there is no - // limit on num_sects. To fix this, we loop through AIX_remap_sector and - // INIT_IO until num_sects reaches zero. - - while (num_sects > 0) { - - if (AIX_remap_sector(node, sect_nr, num_sects, &new_sector, &new_size, - &partition, &le, &offset) || (!new_sector || !partition)) { - LOG_CRITICAL("--- Error returned from AIX_remap_sector %d\n", - __LINE__); - return -EIO; - } - - LOG_DEBUG(" init_io_aix() line:%d logical_node:%p io_flag:%d new_sector:" - PFU64 " new_size:" PFU64 "\n", __LINE__, - partition->logical_node, io_flag, new_sector, new_size); - - rc = INIT_IO(partition->logical_node, io_flag, new_sector, - new_size, buf_addr); - num_sects -= new_size; - sect_nr += new_size; - buf_addr = (void *) (((unsigned long) buf_addr) + - (unsigned long) (new_size << EVMS_VSECTOR_SIZE_SHIFT)); - } - - return rc; -} - -/* - * Function: AIXlvm_vge_init - * - */ -int __init -AIXlvm_vge_init(void) -{ - - LOG_DEBUG(" %s --------\n", __FUNCTION__); - - MOD_INC_USE_COUNT; - return evms_cs_register_plugin(&plugin_header); /* register with EVMS */ -} - -module_init(AIXlvm_vge_init); - -/********** Required Plugin Functions **********/ - -/* - * Function: discover_aix - * - * This is the entry point into the LVM discovery process. - */ -static int -discover_aix(struct evms_logical_node **evms_logical_disk_head) -{ - int rc = 0, count = 0; - - MOD_INC_USE_COUNT; - LOG_DEBUG("[%s] discover_volume_groups\n", __FUNCTION__); - - rc = discover_volume_groups(evms_logical_disk_head); - - if (rc) { - LOG_ERROR("[%s] discover_volume_groups rc=%d\n", __FUNCTION__,rc); - } - - if (AIXVolumeGroupList && !rc) { - - LOG_DEBUG("[%s] discover_logical_volumes\n", __FUNCTION__); - - rc = discover_logical_volumes(); - - if (rc) { - LOG_ERROR("[%s] discover_logical_volumes rc=%d\n", - __FUNCTION__, rc); - } - - LOG_DEBUG("[%s] export_volumes\n", __FUNCTION__); - - count = export_volumes(evms_logical_disk_head); - - LOG_DEBUG("[%s] export_volumes count=%d\n", __FUNCTION__, - count); - } - - MOD_DEC_USE_COUNT; - return (count); -} - -static int -discover_volume_groups(struct evms_logical_node **evms_logical_disk_head) -{ - struct evms_logical_node *logical_node; - struct evms_logical_node *next_node; - struct aix_ipl_rec_area *AIXpv; - struct AIXlvm_rec *AIXlvm; // Temp holder for the LVM on disk rec - - LOG_DEBUG(" Begin %s\n", __FUNCTION__); - - AIXpv = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXpv) { - return -ENOMEM; - } - - // We'll create at least one volume entry, if we don't find any AIX volumes we'll clean it up later - - AIXlvm = kmalloc(sizeof (struct AIXlvm_rec), GFP_KERNEL); - if (!AIXlvm) { - kfree(AIXpv); - return -ENOMEM; - } - - for (logical_node = *evms_logical_disk_head; logical_node; - logical_node = next_node) { - - // Grab the next list item in case we remove this partition from the global list. - next_node = logical_node->next; - - // Read the first sector and see if it has a valid AIX PV signature. - - if (INIT_IO(logical_node, 0, 0, 1, AIXpv)) { - // On an I/O error, continue on to the next - // partition. The group that this partition - // belongs to will be incomplete, but we still - // need to discover any other groups. - - LOG_ERROR(" Error reading PV [%p]\n", logical_node); - continue; - } - - if (AIXpv->IPL_record_id == IPLRECID) { - - // This partition is definitely a PV, - // but is it part of a valid VG? - LOG_DEBUG(" DVG removing node from list logical_node %p\n", - logical_node); - - if (INIT_IO(logical_node, 0, PSN_LVM_REC, 1, AIXlvm)) { - LOG_ERROR(" Error reading PV [%p]\n",logical_node); - continue; - } - - if (AIXlvm->lvm_id == AIX_LVM_LVMID) { - - if (validate_build_volume_group_disk_info( - logical_node, AIXlvm)) { - // Again, continue on and we'll - // clean up later. - continue; - } - - evms_cs_remove_logical_node_from_list( - evms_logical_disk_head, logical_node); - - } else { - LOG_DEBUG(" Found an AIX PV with no parent LVM (LVM ID: %d)\n", - AIXlvm->lvm_id); - continue; - } - } else { - LOG_DEBUG(" Found a PV not belonging to AIX [%p]\n", - logical_node); - } - } - - AIX_VOLUME_GROUP_DUMP(); - - if (check_volume_groups()) { - return -EINVAL; - } - - kfree(AIXpv); - kfree(AIXlvm); - - return 0; -} - -/* - * Function: validate_build_volume_group_disk_info - * - * Creates and validates the volume groups found on the disk structures. - * - */ -static int -validate_build_volume_group_disk_info(struct evms_logical_node *logical_node, - struct AIXlvm_rec *AIXlvm) -{ - - struct aix_volume_group *AIXVGLptr = AIXVolumeGroupList; - - LOG_DEBUG(" VBVGDI pv_num:%d\n", AIXlvm->pv_num); - - while (AIXVGLptr) { - if (COMPARE_UNIQUE_IDS(AIXlvm->vg_id, AIXVGLptr->vg_id)) { - break; - } - AIXVGLptr = AIXVGLptr->next; // There is more than one so walk the list - } - - if (!AIXVGLptr) { - LOG_DEBUG(" VBVGDI AIXVGLptr:%p line:%d\n", AIXVGLptr,__LINE__); - AIXVGLptr = AIX_create_volume_group(logical_node, AIXlvm); - if (AIXVGLptr) { - AIXVGLptr->next = AIXVolumeGroupList; - AIXVolumeGroupList = AIXVGLptr; - } - } else { - LOG_DEBUG(" VBVGDI Rediscover AIXVGLptr:%p line:%d\n", - AIXVGLptr, __LINE__); - - if (AIX_update_volume_group(AIXVGLptr, logical_node, AIXlvm)) { - LOG_DEBUG - (" VBVGDI ERROR on Rediscover AIXVGLptr:%p line:%d\n", - AIXVGLptr, __LINE__); - } - } - - if (!AIXVGLptr) { - - LOG_DEBUG(" VBVGDI AIXVGLptr:%p line:%d\n", AIXVGLptr, - __LINE__); - LOG_DEBUG(" VBVGDI flags:%d\n", AIXVGLptr->flags); - LOG_CRITICAL("Unable to allocate volume group data struct Volume Group Corruption !!\n"); - return -EINVAL; - } else { - - LOG_DEBUG(" VBVGDI AIXVolumeGroupList:%p line:%d\n", - AIXVolumeGroupList, __LINE__); - LOG_DEBUG(" VBVGDI AIXVGLptr:%p line:%d\n", AIXVGLptr, - __LINE__); - LOG_DEBUG(" VBVGDI flags:%d\n", AIXVGLptr->flags); - - if (add_PV_to_volume_group(AIXVGLptr, logical_node, AIXlvm->pv_num)) { - return -EINVAL; - } - } - - return 0; -} - -/* - * Function: add_VG_data_to_VG_list - * - * Allocate space for a new LVM volume group and all of its sub-fields. - * Initialize the appropriate fields. - */ - -static int -add_VG_data_to_VG_list(struct evms_logical_node *logical_node, - struct aix_volume_group *new_group, short int pvNum) -{ -// int pvh_pos; - -// struct pv_header *AIXpvh; - - // The array of pointer to the logical volumes. - // Leave this allocation at the max permitted, the lv numbering may not be sequential so you may have gaps - // in the array allocation i.e. 1,2,3,4,5,6,7,8,11,15,21,33 etc. even though you only have 12 LVs. - - LOG_DEBUG(" AVGDVGL Entering pvNum:%d vgda_PSN:%d\n", pvNum, - new_group->vgda_psn); - -// pvh_pos = AIX_PVH_DATA_PSN(new_group->vgda_psn, pvNum); - -/* AIXpvh = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXpvh) { - return -ENOMEM; - } - - memset(AIXpvh, 0, AIX_SECTOR_SIZE); - - LOG_DEBUG(" AVGDVGL pvh_pos:%d\n", pvh_pos); - - if (INIT_IO(logical_node, 0, pvh_pos, 1, AIXpvh)) { - return -EIO; - } - - LOG_DEBUG(" AVGDVGL AIXpvh->pv_num:%d\n", pvNum); -*/ - if (!new_group->volume_list) { - new_group->volume_list = - kmalloc(LVM_MAXLVS * sizeof (struct aix_logical_volume *), - GFP_KERNEL); - if (!new_group->volume_list) { -// kfree(AIXpvh); - return -ENOMEM; - } - memset(new_group->volume_list, 0, - (LVM_MAXLVS * sizeof (struct aix_logical_volume *))); - } - - new_group->vg_id.word1 = new_group->AIXvgh->vg_id.word1; - new_group->vg_id.word2 = new_group->AIXvgh->vg_id.word2; - new_group->vg_id.word3 = new_group->AIXvgh->vg_id.word3; - new_group->vg_id.word4 = new_group->AIXvgh->vg_id.word4; -// new_group->numpvs = new_group->AIXvgh->numpvs; -// new_group->numlvs = new_group->AIXvgh->numlvs; -// new_group->lv_max = new_group->AIXvgh->maxlvs; - new_group->pe_size = GET_PHYSICAL_PART_SIZE(new_group->AIXvgh->pp_size) / - AIX_SECTOR_SIZE; - -// new_group->block_size = 0; -// new_group->hard_sect_size = 0; - new_group->flags |= AIX_VG_DIRTY; - -// kfree(AIXpvh); - - LOG_DEBUG(" AVGDVGL Vol Group ID %x\n", new_group->vg_id.word2); - - return 0; -} - -/* - * Function: add_PV_to_volume_group - * - * Create a new partition_list_entry for the specified volume group. - * Initialize the new partition with the evms node and lvm pv information, - * and add the new partition to the group's list. - */ - -static int -add_PV_to_volume_group(struct aix_volume_group *group, - struct evms_logical_node *evms_partition, int pvNum) -{ - struct partition_list_entry *new_partition; - - LOG_DEBUG(" APVVG Entering pvNum:%d\n", pvNum); - - group->flags |= AIX_VG_DIRTY; - - for (new_partition = group->partition_list; new_partition != NULL; - new_partition = new_partition->next) { - if (new_partition->logical_node == evms_partition) { - return 0; - } - } - - new_partition = - kmalloc(sizeof (struct partition_list_entry), GFP_KERNEL); - if (!new_partition) { - return -ENOMEM; - } - - memset(new_partition, 0, sizeof (struct partition_list_entry)); - - // Add this partition to this group's list. - new_partition->logical_node = evms_partition; - new_partition->pv_number = pvNum; - - if (evms_partition->hardsector_size > group->hard_sect_size) { - group->hard_sect_size = evms_partition->hardsector_size; - } - if (evms_partition->block_size > group->block_size) { - group->block_size = evms_partition->block_size; - } - - // Add this partition to the beginning of its group's list. - new_partition->next = group->partition_list; - group->partition_list = new_partition; - group->partition_count++; - - LOG_DEBUG(" APVVG partition_count:%d pv_num:%d\n", - group->partition_count, pvNum); - - return 0; -} - -/**************************************************** -* -* -* -*****************************************************/ -static struct aix_volume_group * -AIX_create_volume_group(struct evms_logical_node *logical_node, - struct AIXlvm_rec *AIXlvm) -{ - struct vg_header *AIXvgh = NULL, *AIXvgh2 = NULL; - struct vg_trailer *AIXvgt = NULL, *AIXvgt2 = NULL; - struct aix_volume_group *AIXVGLptr; - - AIXvgh = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgh) { - return NULL; - } - - AIXvgh2 = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgh2) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - AIXvgt = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgt) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - AIXvgt2 = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgt2) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - memset(AIXvgh, 0, AIX_SECTOR_SIZE); - memset(AIXvgh2, 0, AIX_SECTOR_SIZE); - memset(AIXvgt, 0, AIX_SECTOR_SIZE); - memset(AIXvgt2, 0, AIX_SECTOR_SIZE); - - // First time thru we want to read this in, we may only have one PV in this group, all others - // may be corrupt, etc. If the info is clean we shouldn't get here. - - if (INIT_IO(logical_node, 0, AIXlvm->vgda_psn[0], 1, AIXvgh)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - if (INIT_IO(logical_node, 0, AIXlvm->vgda_psn[1], 1, AIXvgh2)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - if (INIT_IO(logical_node, 0, (AIXlvm->vgda_psn[0] + AIXlvm->vgda_len - 1), 1, - AIXvgt)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - if (INIT_IO(logical_node, 0, (AIXlvm->vgda_psn[1] + AIXlvm->vgda_len - 1), 1, - AIXvgt2)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - LOG_DEBUG("CVG AIXvgh->vgda_psn[%d]:%d\n", 0, AIXlvm->vgda_psn[0]); - LOG_DEBUG("CVG AIXvgh->vgda_psn[%d]:%d\n", 1, AIXlvm->vgda_psn[1]); - LOG_DEBUG("CVG AIXvgt psn[%d]:%d\n", 0,(AIXlvm->vgda_psn[0] + AIXlvm->vgda_len - 1)); - LOG_DEBUG("CVG AIXvgt psn[%d]:%d\n", 1,(AIXlvm->vgda_psn[1] + AIXlvm->vgda_len - 1)); - LOG_DEBUG("CVG Allocating AIXVGLptr:size:%d \n",(int) sizeof (struct aix_volume_group)); - - AIXVGLptr = kmalloc(sizeof (struct aix_volume_group), GFP_KERNEL); - if (!AIXVGLptr) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - memset(AIXVGLptr, 0, sizeof (struct aix_volume_group)); - - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - AIXVGLptr->flags |= AIX_VG_DIRTY; - - LOG_DEBUG("CVG AIXVGLptr:%p line %d\n", AIXVGLptr, __LINE__); - - AIXVGLptr->AIXvgh = kmalloc(sizeof (struct vg_header), GFP_KERNEL); - if (!AIXVGLptr->AIXvgh) { - kfree(AIXVGLptr); - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - memset(AIXVGLptr->AIXvgh, 0, sizeof (struct vg_header)); - - LOG_DEBUG("CVG COMP TS AIXVGLptr->CleanVGInfo:%d \n", - AIXVGLptr->CleanVGInfo); - - if (AIXVGLptr->CleanVGInfo == AIX_PV_STATE_INVALID) { - if (COMPARE_TIMESTAMPS(AIXvgh->vg_timestamp, AIXvgt->timestamp)) { - if (COMPARE_TIMESTAMPS - (AIXvgh2->vg_timestamp, AIXvgt2->timestamp)) { - if (COMPARE_TIMESTAMPS - (AIXvgh->vg_timestamp, - AIXvgh2->vg_timestamp)) { - // All timestamps match. Yea! - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_VALID; - } else { - // Both VGDAs are good, but timestamps are - // different. Can't tell yet which one is - // correct. - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_EITHER_VGDA; - } - } else { - // First VGDA is good, second is bad. - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_FIRST_VGDA; - } - } else { - if (COMPARE_TIMESTAMPS - (AIXvgh2->vg_timestamp, AIXvgt2->timestamp)) { - // First VGDA is bad, second is good. - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_SECOND_VGDA; - } else if (AIXvgh->numpvs == 1) { // We only have 1 PV in this group, mismatch or not this will have to do - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_VALID; - } else { - // This should never happen. - LOG_DEBUG("All four VG timestamps for %d are different. What happened?!?\n", - AIXVGLptr->vg_id.word2); - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - - } - } - - LOG_DEBUG("CVG SWITCH TS AIXVGLptr->CleanVGInfo:%d \n", - AIXVGLptr->CleanVGInfo); - - switch (AIXVGLptr->CleanVGInfo) { - case AIX_PV_STATE_VALID: - case AIX_PV_STATE_FIRST_VGDA: - - LOG_DEBUG("CVG SWITCH VALID %d size:%d\n", - AIXVGLptr->CleanVGInfo, - (int) sizeof (struct vg_header)); - - AIX_copy_header_info(AIXVGLptr->AIXvgh, AIXvgh); // Get the info. we need - - AIXVGLptr->vgda_psn = AIXlvm->vgda_psn[0]; - AIXVGLptr->vgda_len = AIXlvm->vgda_len; - break; - - case AIX_PV_STATE_SECOND_VGDA: - LOG_DEBUG("CVG SWITCH SECOND VGDA %d size:%d\n", - AIXVGLptr->CleanVGInfo, - (int) sizeof (struct vg_header)); - - AIX_copy_header_info(AIXVGLptr->AIXvgh, AIXvgh2); // Get the info. we need - - AIXVGLptr->vgda_psn = AIXlvm->vgda_psn[1]; - AIXVGLptr->vgda_len = AIXlvm->vgda_len; - break; - - case AIX_PV_STATE_EITHER_VGDA: - LOG_DEBUG("CVG SWITCH EITHER VGDA %d size:%d\n", - AIXVGLptr->CleanVGInfo,(int) sizeof (struct vg_header)); - if (COMPARE_UNIQUE_IDS(AIXvgh->vg_id, AIXvgh2->vg_id)) { - - AIX_copy_header_info(AIXVGLptr->AIXvgh, AIXvgh); // Get the info. we need - - AIXVGLptr->vgda_psn = AIXlvm->vgda_psn[0]; - AIXVGLptr->vgda_len = AIXlvm->vgda_len; - } else { - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - // Not sure where this PV belongs. It thinks it is - // supposed to be in two different containers. We will - // probably need to put this on a separate, temporary - // list, and determine later which container is missing - // a PV. - } - break; - - default: - LOG_ERROR("Invalid PV state (%d) for %d\n", - AIXVGLptr->CleanVGInfo, - AIXVGLptr->vg_id.word2); - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - break; - } - - } - - // Currently AIX Big VGDA is not supported - cleanup and return NULL so this VG doesn't get added - - if (AIXVGLptr->AIXvgh->bigvg != 0) { - LOG_SERIOUS("Error creating Volume Group AIX Big VGDA is not currently supported\n"); - if (AIXVGLptr->AIXvgh) { - kfree(AIXVGLptr->AIXvgh); - AIXVGLptr->AIXvgh = NULL; - } - - if (AIXVGLptr) { - kfree(AIXVGLptr); - AIXVGLptr = NULL; - } - - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return NULL; - } - - add_VG_data_to_VG_list(logical_node, AIXVGLptr, AIXlvm->pv_num); - - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - - LOG_DEBUG("CVG Exiting CleanVGInfo:%d\n", AIXVGLptr->CleanVGInfo); - - return AIXVGLptr; -} - -/**************************************************** -* -* -* -*****************************************************/ -static int -AIX_update_volume_group(struct aix_volume_group *AIXVGLptr, - struct evms_logical_node *logical_node, - struct AIXlvm_rec *AIXlvm) -{ - struct vg_header *AIXvgh = NULL, *AIXvgh2 = NULL; - struct vg_trailer *AIXvgt = NULL, *AIXvgt2 = NULL; - - AIXvgh = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgh) { - return -ENOMEM; - } - - AIXvgh2 = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgh2) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - AIXvgt = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgt) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - AIXvgt2 = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXvgt2) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - // First time thru we want to read this in, we may only have one PV in this group, all others - // may be corrupt, etc. If the info is clean we shouldn't get here. - - if (INIT_IO(logical_node, 0, AIXlvm->vgda_psn[0], 1, AIXvgh)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - if (INIT_IO(logical_node, 0, AIXlvm->vgda_psn[1], 1, AIXvgh2)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - if (INIT_IO(logical_node, 0, (AIXlvm->vgda_psn[0] + AIXlvm->vgda_len - 1), 1, - AIXvgt)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - if (INIT_IO(logical_node, 0, (AIXlvm->vgda_psn[1] + AIXlvm->vgda_len - 1), 1, - AIXvgt2)) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - - LOG_DEBUG("UVG AIXvgh->vgda_psn[%d]:%d\n", 0, AIXlvm->vgda_psn[0]); - LOG_DEBUG("UVG AIXvgh->vgda_psn[%d]:%d\n", 1, AIXlvm->vgda_psn[1]); - LOG_DEBUG("UVG AIXvgt psn[%d]:%d\n", 0,(AIXlvm->vgda_psn[0] + AIXlvm->vgda_len - 1)); - LOG_DEBUG("UVG AIXvgt psn[%d]:%d\n", 1,(AIXlvm->vgda_psn[1] + AIXlvm->vgda_len - 1)); - - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - AIXVGLptr->flags |= AIX_VG_DIRTY; - - LOG_DEBUG("UVG AIXVGLptr:%p line %d\n", AIXVGLptr, __LINE__); - - AIXVGLptr->AIXvgh = kmalloc(sizeof (struct vg_header), GFP_KERNEL); - if (!AIXVGLptr->AIXvgh) { - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - return -ENOMEM; - } - memset(AIXVGLptr->AIXvgh, 0, sizeof (struct vg_header)); - - LOG_DEBUG("UVG COMP TS AIXVGLptr->CleanVGInfo:%d \n",AIXVGLptr->CleanVGInfo); - - if (AIXVGLptr->CleanVGInfo == AIX_PV_STATE_INVALID) { - if (COMPARE_TIMESTAMPS(AIXvgh->vg_timestamp, AIXvgt->timestamp)) { - if (COMPARE_TIMESTAMPS - (AIXvgh2->vg_timestamp, AIXvgt2->timestamp)) { - if (COMPARE_TIMESTAMPS - (AIXvgh->vg_timestamp, - AIXvgh2->vg_timestamp)) { - // All timestamps match. Yea! - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_VALID; - } else { - // Both VGDAs are good, but timestamps are - // different. Can't tell yet which one is - // correct. - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_EITHER_VGDA; - } - } else { - // First VGDA is good, second is bad. - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_FIRST_VGDA; - } - } else { - if (COMPARE_TIMESTAMPS - (AIXvgh2->vg_timestamp, AIXvgt2->timestamp)) { - // First VGDA is bad, second is good. - AIXVGLptr->CleanVGInfo = - AIX_PV_STATE_SECOND_VGDA; - } else if (AIXvgh->numpvs == 1) { // We only have 1 PV in this group, mismatch or not this will have to do - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_VALID; - } else { - // This should never happen. - LOG_DEBUG - ("All four VG timestamps for %d are different. What happened?!?\n", - AIXVGLptr->vg_id.word2); - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - - } - } - - LOG_DEBUG("UVG SWITCH TS AIXVGLptr->CleanVGInfo:%d \n", - AIXVGLptr->CleanVGInfo); - - switch (AIXVGLptr->CleanVGInfo) { - case AIX_PV_STATE_VALID: - case AIX_PV_STATE_FIRST_VGDA: - - LOG_DEBUG("UVG SWITCH VALID %d size:%d\n", - AIXVGLptr->CleanVGInfo, - (int) sizeof (struct vg_header)); - - AIX_copy_header_info(AIXVGLptr->AIXvgh, AIXvgh); // Get the info. we need - - AIXVGLptr->vgda_psn = AIXlvm->vgda_psn[0]; - AIXVGLptr->vgda_len = AIXlvm->vgda_len; - break; - - case AIX_PV_STATE_SECOND_VGDA: - LOG_DEBUG("UVG SWITCH SECOND VGDA %d size:%d\n", - AIXVGLptr->CleanVGInfo, - (int) sizeof (struct vg_header)); - - AIX_copy_header_info(AIXVGLptr->AIXvgh, AIXvgh2); // Get the info. we need - - AIXVGLptr->vgda_psn = AIXlvm->vgda_psn[1]; - AIXVGLptr->vgda_len = AIXlvm->vgda_len; - break; - - case AIX_PV_STATE_EITHER_VGDA: - LOG_DEBUG("UVG SWITCH EITHER VGDA %d size:%d\n", - AIXVGLptr->CleanVGInfo, - (int) sizeof (struct vg_header)); - if (COMPARE_UNIQUE_IDS(AIXvgh->vg_id, AIXvgh2->vg_id)) { - - AIX_copy_header_info(AIXVGLptr->AIXvgh, AIXvgh); // Get the info. we need - - AIXVGLptr->vgda_psn = AIXlvm->vgda_psn[0]; - AIXVGLptr->vgda_len = AIXlvm->vgda_len; - } else { - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - // Not sure where this PV belongs. It thinks it is - // supposed to be in two different containers. We will - // probably need to put this on a separate, temporary - // list, and determine later which container is missing - // a PV. - } - break; - - default: - LOG_ERROR("UVG Invalid PV state (%d) for %d\n", - AIXVGLptr->CleanVGInfo, - AIXVGLptr->vg_id.word2); - AIXVGLptr->CleanVGInfo = AIX_PV_STATE_INVALID; - break; - } - - } - -// add_VG_data_to_VG_list(logical_node, AIXVGLptr, AIXlvm->pv_num); - AIXVGLptr->flags |= AIX_VG_DIRTY; - - AIX_free_headers(AIXvgh, AIXvgh2, AIXvgt, AIXvgt2); - - LOG_DEBUG("UVG Exiting CleanVGInfo:%d\n", AIXVGLptr->CleanVGInfo); - - return 0; -} - -/**************************************************** -* Function: check_volume_groups -* -* We just want to make sure the volume groups have found -* all their drives. -* -* If not, we'll continue and build what we can -*****************************************************/ -static int -check_volume_groups(void) -{ - struct aix_volume_group *group; - struct aix_volume_group *next_group; -// struct partition_list_entry *partitions; -// int NumPVS = 0; - - LOG_DEBUG("CHVG Checking volume groups:\n"); - - - for (group = AIXVolumeGroupList; group; group = next_group) { - next_group = group->next; - - if (group->flags & AIX_VG_DIRTY){ - if (group->AIXvgh->numlvs == 0) { - remove_group_from_list(group); - deallocate_volume_group(group); - } else { - if (group->partition_count != group->AIXvgh->numpvs) { - group->flags |= AIX_VG_INCOMPLETE; - LOG_ERROR("CHVG Found incomplete VG !! flags:%x\n", - group->flags); - LOG_ERROR("CHVG Found %d PVs should have %d PVs\n", - group->partition_count, group->AIXvgh->numpvs); - } - } - } - } - - LOG_DEBUG("CHVG Finished Checking volume groups:\n"); - return 0; - -} - -/************************************************************************ - * Function: discover_logical_volumes - * - * After all PVs have been claimed and added to the appropriate VG list, - * the volumes for each VG must be constructed. - * - * - */ -static int -discover_logical_volumes(void) -{ - - struct aix_volume_group *AIXVGLPtr; - struct aix_logical_volume *new_LV; - struct partition_list_entry *partition; - struct evms_logical_node *node; - struct lv_entries *AIXlvent, *AIXlventHead; - int j, lv_found, all_lvs_found, rc; - struct namelist *AIXnamelist; - char *NameBuffer; - - AIXlventHead = - kmalloc(MAX_SECTORS_LV_ENTRIES * AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXlventHead) { - return -ENOMEM; - } - - memset(AIXlventHead, 0, (MAX_SECTORS_LV_ENTRIES * AIX_SECTOR_SIZE)); - - NameBuffer = - kmalloc(MAX_SECTORS_NAMELIST * AIX_SECTOR_SIZE, GFP_KERNEL); - if (!NameBuffer) { - kfree(AIXlventHead); - return -ENOMEM; - } - - memset(NameBuffer, 0, (MAX_SECTORS_NAMELIST * AIX_SECTOR_SIZE)); - - for (AIXVGLPtr = AIXVolumeGroupList; AIXVGLPtr; - AIXVGLPtr = AIXVGLPtr->next ) { - - partition = AIXVGLPtr->partition_list; - - if (!(AIXVGLPtr->flags & AIX_VG_DIRTY)) { - continue; - } - - if (partition == NULL) { - continue; - } - - node = partition->logical_node; - - if (node == NULL) { - continue; - } - - LOG_DEBUG("DLV INIT_IO AIXNameList position:%d\n", - ((AIXVGLPtr->vgda_psn + AIXVGLPtr->vgda_len) - 1 - - MAX_SECTORS_NAMELIST)); - LOG_DEBUG("AIXVGLPTR:%p partition:%p node:%p \n", AIXVGLPtr, - partition, node); - - if (INIT_IO(node, 0, - ((AIXVGLPtr->vgda_psn + AIXVGLPtr->vgda_len) - 1 - - MAX_SECTORS_NAMELIST), MAX_SECTORS_NAMELIST, - NameBuffer)) { - continue; - } - - LOG_DEBUG("DLV INIT_IO AIXNameList\n"); - - if (INIT_IO(node, 0, AIXVGLPtr->vgda_psn + PSN_LVE_REC, - MAX_SECTORS_LV_ENTRIES, AIXlventHead)) { - continue; - } - AIXlvent = AIXlventHead; - AIXnamelist = (struct namelist *) NameBuffer; - - LOG_DEBUG("DLV INIT_IO AIXlvent\n"); - // Search through the LV structs for valid LV entries - // We're just going to search until all valid LVs are found - // The max. allowable LVs is 256 and we want don't want to - // search for 255 if only 8 are defined 1-8 however, there - // could be gaps in the LV numbering. i.e 1,2,3,4,5,6,7,8, 27,43, etc. - - for (j = 0, lv_found = 0, all_lvs_found = FALSE; - !all_lvs_found && j < LVM_MAXLVS; j++, AIXlvent++) { - - LOG_DEBUG(" ** DVIG:lv_size:%d lvname:[%s] j:%d lv_number:%d ** \n", - AIXlvent->num_lps, AIXnamelist->name[j], j, - AIXlvent->lvname); - LOG_DEBUG(" DVIG:stripe_exp:%u stripesize:%u lv_status:%d\n", - AIXlvent->striping_width, - GET_PHYSICAL_PART_SIZE(AIXlvent->stripe_exp), - AIXlvent->lv_state); - LOG_DEBUG(" DVIG Group:%x.Access:%x\n", - (unsigned int) AIXVGLPtr->vg_id.word2, - AIXlvent->permissions); - LOG_DEBUG(" DVIG mirror:%d mirror_policy:%d mirwrt:%d \n", - AIXlvent->mirror, AIXlvent->mirror_policy, - AIXlvent->mirwrt_consist); - - // This is the same check we used in "diskedit" and "readdisk" - if (AIXlvent->lv_state == 0 || - AIXlvent->permissions > 0x10) { - continue; - } - - lv_found++; - if (lv_found == AIXVGLPtr->AIXvgh->numlvs) { - all_lvs_found = TRUE; - } - - LOG_DEBUG(" DVIG lv_found:%d all_lvs_found:%d \n", - lv_found, all_lvs_found); - - // Create a new logical volume and place it in the appropriate - // spot in this VG's volume list. For re-discovery, make sure - // this volume does not already exist. - if (!AIXVGLPtr->volume_list[AIXlvent->lvname]) { - new_LV = - new_logical_volume(AIXlvent, - AIXVGLPtr, - AIXnamelist-> - name[j], - GET_PHYSICAL_PART_SIZE - (AIXlvent-> - stripe_exp)); - if (!new_LV) { - continue; - } - LOG_DEBUG(" DVIG Adding new logical volume %d to group:%x \n", - new_LV->lv_number,AIXVGLPtr->vg_id.word2); - - AIXVGLPtr->volume_list[new_LV->lv_number] = new_LV; - } else { - LOG_DEBUG("DVIG Updating Vol Exists\n"); - } - } - - // Build the le_to_pe_map for each volume that was discovered above. - // This has to be done after all volumes in the group are discovered - if ((rc = build_pe_maps(AIXVGLPtr))) { - continue; - } - - check_log_volume_and_pe_maps(AIXVGLPtr); - } - - kfree(NameBuffer); - kfree(AIXlventHead); - - return 0; -} - -/* - * Function: new_logical_volume - * - * Allocate space for a new LVM logical volume, including space for the - * PE map - */ -static struct aix_logical_volume * -new_logical_volume(struct lv_entries *AIXlvent, - struct aix_volume_group *volume_group, - char *lv_name, u32 stripesize) -{ - - struct aix_logical_volume *new_volume; - const char *name = "evms_AIXiod"; - const char *resync_name = "evms_AIXresync"; - - LOG_DEBUG(" NLV: lv_number:%d lv_allocated_le:%d lv_size:%d\n", - AIXlvent->lvname, AIXlvent->num_lps, - AIXlvent->num_lps * volume_group->pe_size); - - // Allocate space for the new logical volume. - new_volume = kmalloc(sizeof (struct aix_logical_volume), GFP_KERNEL); - if (!new_volume) { - return NULL; - } - memset(new_volume, 0, sizeof (struct aix_logical_volume)); - - // Allocate space for the LE to PE mapping table - // We add 1 for the allocated le to ease mapping later on, all AIX le are 1 based - new_volume->le_to_pe_map = - kmalloc((AIXlvent->num_lps + 1) * sizeof (struct pe_table_entry), - GFP_KERNEL); - if (!new_volume->le_to_pe_map) { - delete_logical_volume(new_volume); - return NULL; - } - - memset(new_volume->le_to_pe_map, 0, - (AIXlvent->num_lps + 1) * sizeof (struct pe_table_entry)); - - if (AIXlvent->mirror > AIX_DEFAULT_MIRRORING) { - new_volume->le_to_pe_map_mir1 = - kmalloc((AIXlvent->num_lps + - 1) * sizeof (struct pe_table_entry), GFP_KERNEL); - if (!new_volume->le_to_pe_map_mir1) { - delete_logical_volume(new_volume); - return NULL; - } - memset(new_volume->le_to_pe_map_mir1, 0, - (AIXlvent->num_lps + - 1) * sizeof (struct pe_table_entry)); - } - - if (AIXlvent->mirror == AIX_MAX_MIRRORS) { - new_volume->le_to_pe_map_mir2 = - kmalloc((AIXlvent->num_lps + 1) - * sizeof (struct pe_table_entry), GFP_KERNEL); - if (!new_volume->le_to_pe_map_mir2) { - delete_logical_volume(new_volume); - return NULL; - } - memset(new_volume->le_to_pe_map_mir2, 0, - (AIXlvent->num_lps +1) - * sizeof (struct pe_table_entry)); - } - - // Initialize the rest of the new volume. - new_volume->lv_number = AIXlvent->lvname; - new_volume->lv_size = AIXlvent->num_lps * (volume_group->pe_size); - new_volume->lv_access = AIXlvent->permissions | EVMS_LV_NEW; // All volumes start new. - new_volume->lv_status = AIXlvent->lv_state; - //new_volume->lv_minor = MINOR(1); - new_volume->mirror_copies = AIXlvent->mirror; -// new_volume->mirror_iterations = AIX_DEFAULT_MIRRORING; - new_volume->stripes = AIXlvent->striping_width; - new_volume->stripe_size = stripesize; - new_volume->stripe_size_shift = evms_cs_log2(stripesize); - new_volume->pe_size = volume_group->pe_size; - new_volume->pe_size_shift = evms_cs_log2(volume_group->pe_size); - new_volume->num_le = AIXlvent->num_lps; -// new_volume->new_volume = TRUE; - new_volume->group = volume_group; - - volume_group->numlvs++; - - sprintf(new_volume->name, "aix/%s", lv_name); - - if (!AIX_BH_list_pool - && new_volume->mirror_copies > AIX_DEFAULT_MIRRORING) { - - // We only need the ReSync thread if we have at least one mirrored LV. - // You can't ReSync a non-mirrored drive - - AIX_BH_list_pool = - evms_cs_create_pool(sizeof (struct aix_mirror_bh), - "EVMS_AIX_BH", aix_notify_cache_ctor, - NULL); - if (!AIX_BH_list_pool) { - return NULL; - - AIX_mirror_read_retry_thread = - evms_cs_register_thread(AIXiod, NULL, name); - - AIX_mirror_resync_thread = - evms_cs_register_thread(AIXresync, NULL, - resync_name); - } - } - - LOG_DEBUG("NLV lv_number:%d name:%s lv_size " PFU64 " \n", - new_volume->lv_number, new_volume->name, new_volume->lv_size); - LOG_DEBUG("NLV stripe_size:%d stripe_size_shift:%d\n", - new_volume->stripe_size, new_volume->stripe_size_shift); - - return new_volume; -} - -/* - * Function: aix_notify_cache_ctor - * this function initializes the b_wait field in the buffer heads - * in our private buffer head pool. - */ -static void -aix_notify_cache_ctor(void *foo, kmem_cache_t * cachep, unsigned long flags) -{ - if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { - struct aix_mirror_bh *rbh = (struct aix_mirror_bh *) foo; - memset(rbh, 0, sizeof (struct aix_mirror_bh)); - atomic_set(&rbh->remaining, 0); - init_waitqueue_head(&rbh->bh_req.b_wait); - } -} - -/* - * Function: build_pe_maps - * - * After all logical volumes have been discovered, the mappings from - * logical extents to physical extents must be constructed. Each PV - * contains a map on-disk of its PEs. Each PE map entry contains the - * logical volume number and the logical extent number on that volume. - * Our internal map is the reverse of this map for each volume, listing - * the PV node and sector offset for every logical extent on the volume. - */ -static int - build_pe_maps(struct aix_volume_group *volume_group) -{ - struct partition_list_entry *partition; - struct partition_list_entry *mirror_partition; - struct pp_entries *AIXppent, *AIXppent_buff; - struct pv_header *AIXpvh; - u64 offset; - u32 le_number; - u32 j, pp_count, pvh_pos; - u32 MirrorFound; - u32 pvh_posn[LVM_MAXPVS]; - u32 rc; -#ifdef EVMS_DEBUG_MIRRORS - u32 lv_found, all_lvs_found; - u32 mirs = 0; -#endif - - LOG_DEBUG(" *** BPEM ***\n"); - // For every partition in this VG - - AIXppent_buff = kmalloc(AIX_SECTOR_SIZE * PHYS_VOL_OFFSET, GFP_KERNEL); - if (!AIXppent_buff) { - return -ENOMEM; - } - - memset(AIXppent_buff, 0, AIX_SECTOR_SIZE * PHYS_VOL_OFFSET); - memset(pvh_posn, 0, LVM_MAXPVS); - - AIXpvh = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXpvh) { - kfree(AIXppent_buff); - return -ENOMEM; - } - - memset(AIXpvh, 0, AIX_SECTOR_SIZE); - - LOG_DEBUG(" BPEM AIXppent_buff:%d \n", - (AIX_SECTOR_SIZE * PHYS_VOL_OFFSET)); - - // This next section is to calculate the sector spacing between PV info for the VG - // AIX doesn't always space the info. the same. It could be 17 or 34 sectors apart - // depending on the PE size selected. - - rc = AIX_pvh_data_posn(volume_group->vgda_psn, pvh_posn, volume_group->partition_list, volume_group->AIXvgh->numpvs); - - if (rc != 0) { - kfree(AIXppent_buff); - kfree(AIXpvh); - return (rc); - } - - for (partition = volume_group->partition_list; partition; - partition = partition->next) { - - LOG_DEBUG(" BPEM partition:%p next:%p\n", partition, - partition->next); - - pvh_pos = pvh_posn[partition->pv_number]; - - LOG_DEBUG(" BPEM pvh_pos:%d pv_number:%d\n", pvh_pos, partition->pv_number); - - if (INIT_IO(partition->logical_node, 0, pvh_pos, 1, AIXpvh)) { - kfree(AIXppent_buff); - kfree(AIXpvh); - return -EIO; - } - // For every entry in the PE map, calculate the PE's sector offset - // and update the correct LV's PE map. LV number of 0 marks an unused PE. - // For re-discovery, only compute entries for new volumes. - - if (INIT_IO(partition->logical_node, 0, pvh_pos, AIX_PVHPP_LENGTH, - AIXppent_buff)) { - kfree(AIXppent_buff); - kfree(AIXpvh); - return -EIO; - } - - AIXppent = AIXppent_buff; - AIXppent++; - - pp_count = AIXpvh->pp_count; - - LOG_DEBUG("BPEM AIXpvh data: pp_count:%d psn_part1:%d pv_id1:%d pv_id2:%d pv_id3:%d pv_id4:%d pv_num:%d pv_state:%d vgdas:%d res1:%d res2:%d\n", AIXpvh->pp_count, - AIXpvh->psn_part1, - AIXpvh->pv_id.word1, - AIXpvh->pv_id.word2, - AIXpvh->pv_id.word3, - AIXpvh->pv_id.word4, - AIXpvh->pv_num, - AIXpvh->pv_state, AIXpvh->pvnum_vgdas, AIXpvh->res1, AIXpvh->res2); - - LOG_DEBUG(" PE Map: volgrp:%x AIXpvh->pv_num:%d partition:%p next:%p lv_index:%d pp_count:%d\n", - volume_group->vg_id.word2, AIXpvh->pv_num, partition, - partition->next, AIXppent->lv_index, pp_count); - - for (j = 0; j < pp_count; j++,AIXppent++) { - if (!AIXppent->lv_index || AIXppent->pp_state == AIX_LVM_LVUNDEF) { - continue; - } - - LOG_EXTRA(" -- pv:%x pp:%d st:%d nm:%s lv:%d lp:%d cp:%d fst v:%d fst p:%d snd v:%d snd p:%d \n", - volume_group->vg_id.word2, j + 1, - AIXppent->pp_state, - volume_group->volume_list[AIXppent->lv_index -1]->name, - AIXppent->lv_index, AIXppent->lp_num, - AIXppent->copy, AIXppent->fst_alt_vol, - AIXppent->fst_alt_part, - AIXppent->snd_alt_vol, - AIXppent->snd_alt_part); - - le_number = AIXppent->lp_num - 1; // AIX lp's start @ 1, we want a 0 index - offset = ((j * (volume_group->pe_size)) + AIXpvh->psn_part1); - - LOG_DEBUG(" PE Map: le_number:%d partition:%p lv_index:%d lv_name:%s\n", - le_number, partition, AIXppent->lv_index, - volume_group->volume_list[AIXppent->lv_index -1]->name); - - if (!volume_group->volume_list[AIXppent->lv_index - 1]) { - LOG_SERIOUS("Failed attempt to access volume without memory allocation lv:%d\n", - AIXppent->lv_index - 1); - continue; - } - - if (volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map - && le_number <= volume_group->volume_list[AIXppent->lv_index - 1]->num_le) { - - volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map[le_number].owning_pv = partition; - volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map[le_number].pe_sector_offset = offset; - volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map[le_number].pp_state = AIXppent->pp_state; - } - - if (volume_group->volume_list[AIXppent->lv_index -1]->mirror_copies > - AIX_DEFAULT_MIRRORING) { - - LOG_EXTRA(" PE Map: Mirror found lv:%d -- \n", - AIXppent->lv_index); - - for (mirror_partition = volume_group->partition_list, - MirrorFound = FALSE; - mirror_partition && !MirrorFound; - mirror_partition = mirror_partition->next) { - - if (mirror_partition->pv_number == AIXppent->fst_alt_vol) { - - offset = (((AIXppent->fst_alt_part - 1) * (volume_group->pe_size)) + AIXpvh->psn_part1); - - volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map_mir1[le_number].owning_pv = mirror_partition; - volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map_mir1[le_number].pe_sector_offset = offset; - volume_group->volume_list[AIXppent->lv_index -1]->le_to_pe_map_mir1[le_number].pp_state = AIXppent->pp_state; - - LOG_EXTRA(" PE Map: mirror_partition:%p \n", - mirror_partition); - LOG_EXTRA(" PE Map: mirror_sector_offet:%d\n", - AIXppent->fst_alt_part); - - MirrorFound = TRUE; - } - } - - if (volume_group->volume_list[AIXppent->lv_index -1]->mirror_copies == AIX_MAX_MIRRORS) { - - for (mirror_partition = volume_group->partition_list, - MirrorFound = FALSE; - mirror_partition && !MirrorFound; - mirror_partition = mirror_partition->next) { - - if (mirror_partition->pv_number == AIXppent->snd_alt_vol) { - - offset = (((AIXppent->snd_alt_part - 1) * (volume_group->pe_size)) + AIXpvh->psn_part1); - - volume_group->volume_list[AIXppent->lv_index-1]->le_to_pe_map_mir2[le_number].owning_pv = mirror_partition; - volume_group->volume_list[AIXppent->lv_index-1]->le_to_pe_map_mir2[le_number].pe_sector_offset = offset; - volume_group->volume_list[AIXppent->lv_index-1]->le_to_pe_map_mir2[le_number].pp_state = AIXppent->pp_state; - - LOG_EXTRA(" PE Map: mirror_partition2:%p \n", - mirror_partition); - LOG_EXTRA(" PE Map: mirror_sector_offet2:%d\n", - AIXppent->snd_alt_part); - - MirrorFound = TRUE; - } - } - } - - } // End of if mirroring is enabled - } - } - -// LOG_EXTRA(" PE Map: PE maps:%d Mirror count:%d -- \n", lvs, mirs); - -#ifdef EVMS_DEBUG_MIRRORS - for (mirs = 0, lv_found = 0, all_lvs_found = FALSE; - !all_lvs_found && mirs < LVM_MAXLVS; mirs++) { - - if (volume_group->volume_list[mirs] != NULL) { - if (volume_group->volume_list[mirs]->lv_status == - LV_ACTIVE) { - - lv_found++; - - LOG_DEBUG(" PE Map: owning part lv %d -- %p\n", - mirs, - volume_group->volume_list[mirs]-> - le_to_pe_map[0].owning_pv); - if (volume_group->volume_list[mirs]-> - mirror_copies > AIX_DEFAULT_MIRRORING) { - LOG_DEBUG(" PE Map: mirror_partition lv %d -- %p \n", - mirs, - volume_group->volume_list[mirs]-> - le_to_pe_map_mir1[0].owning_pv); - } - if (volume_group->volume_list[mirs]-> - mirror_copies == AIX_MAX_MIRRORS) { - LOG_DEBUG(" PE Map: mirror_partition lv %d -- %p \n", - mirs, - volume_group->volume_list[mirs]-> - le_to_pe_map_mir2[0].owning_pv); - } - } - if (lv_found == volume_group->AIXvgh->numlvs) { - all_lvs_found = TRUE; - LOG_DEBUG(" PE Map: all_lvs_found\n"); - } - } - } -#endif - - kfree(AIXpvh); - kfree(AIXppent_buff); - - return 0; -} - -/* - * Function: check_log_volume_and_pe_maps - * - * Make sure all volumes in this group have valid LE-to-PE maps. - * Any volume that doesn't is deleted. This is safe for re-discovery - * because only new volumes could have corrupted PE maps. - */ -static int -check_log_volume_and_pe_maps(struct aix_volume_group *group) -{ - struct aix_logical_volume *volume; - int i, j, lv_found, all_lvs_found; - - LOG_DEBUG(" check_pe_map.\n"); - - for (i = 0, all_lvs_found = FALSE, lv_found = 0; - !all_lvs_found && i < LVM_MAXLVS; i++) { - if (!group->volume_list[i]) { - LOG_DEBUG(" CPEM No Volume %d found \n", i); - continue; - } - - volume = group->volume_list[i]; - if (!volume->le_to_pe_map) { - LOG_DEBUG(" CPEM Volume %s has no PE map.\n", - volume->name); - delete_logical_volume(volume); - continue; - } - - LOG_DEBUG(" CPEM volume %s num_le: %d \n", volume->name, - volume->num_le); - - lv_found++; - - if (lv_found == group->AIXvgh->numlvs) { - all_lvs_found = TRUE; - } - - for (j = 0; j < volume->num_le; j++) { - if (!volume->le_to_pe_map[j].owning_pv || - !volume->le_to_pe_map[j].pe_sector_offset) { - LOG_SERIOUS(" CPEM Volume (%s) incomplete PE map (LE %d) \n", - volume->name, j); - volume->lv_access |= EVMS_LV_INCOMPLETE; - } - - if (volume->mirror_copies > AIX_DEFAULT_MIRRORING) { - if (!volume->le_to_pe_map_mir1[j].owning_pv || - !volume->le_to_pe_map_mir1[j]. - pe_sector_offset) { - LOG_SERIOUS(" CPEM Volume (%s) incomplete PE mirror map 1 (LE %d) \n", - volume->name, j); - volume->lv_access |= EVMS_LV_INCOMPLETE; - } - - if (volume->mirror_copies == AIX_MAX_MIRRORS) { - if (!volume->le_to_pe_map_mir2[j]. - owning_pv - || !volume->le_to_pe_map_mir2[j]. - pe_sector_offset) { - LOG_SERIOUS(" CPEM Volume (%s) incomplete PE mirror map 2 (LE %d) \n", - volume->name, j); - volume->lv_access |= EVMS_LV_INCOMPLETE; - } - } - } - } - } - - LOG_EXTRA(" Leaving check_pe_map.\n"); - return 0; -} - -/* - * Function: export_volumes - * - * The last thing this VGE must do is take each constructed volume and - * place it back on the evms logical partition list. - */ -static int -export_volumes(struct evms_logical_node **evms_partition_list) -{ - struct aix_volume_group *AIXVGLPtr; - struct evms_logical_node *new_node; - struct aix_logical_volume *volume; - int j, lv_found, all_lvs_found; - int count = 0; - - for (AIXVGLPtr = AIXVolumeGroupList; AIXVGLPtr; AIXVGLPtr = AIXVGLPtr->next) { - - if (!(AIXVGLPtr->flags & AIX_VG_DIRTY)) { - LOG_DEBUG(" EV Existing group(%d), not dirty, skipping\n", - AIXVGLPtr->vg_id.word2); - continue; - } - LOG_DEBUG(" Exporting all new volumes numpvs:%d numlvs:%d \n", - AIXVGLPtr->AIXvgh->numpvs, AIXVGLPtr->numlvs); - - // Export every valid volume in the group. For re-discovery, - // make sure we are only exporting "new" volumes. - - for (j = 0, all_lvs_found = FALSE, lv_found = 0; - !all_lvs_found && j < LVM_MAXLVS; j++) { - if (AIXVGLPtr->volume_list[j] != NULL) { - if (AIXVGLPtr->volume_list[j]->lv_access & EVMS_LV_NEW) { - - LOG_DEBUG(" EV Checking LV:[%d] volume:%p\n", - j,AIXVGLPtr->volume_list[j]); - - volume = AIXVGLPtr->volume_list[j]; - lv_found++; - - if (lv_found == AIXVGLPtr->AIXvgh->numlvs) { - all_lvs_found = TRUE; - } - // For new volumes, create a new EVMS node and - // initialize the appropriate fields. - if (evms_cs_allocate_logical_node(&new_node)) { - LOG_DEBUG(" Export Vol Error allocating node !!\n"); - continue; - } else { - LOG_DEBUG(" EV Node allocated OK\n"); - } - -// volume->new_volume = 0; - volume->volume_node = new_node; - volume->lv_access &= (~EVMS_LV_NEW); - new_node->hardsector_size = AIXVGLPtr->hard_sect_size; - new_node->block_size = AIXVGLPtr->block_size; - new_node->plugin = &plugin_header; - new_node->private = volume; - new_node->total_vsectors = volume->lv_size; - - LOG_DEBUG(" EV volume->name:[%s]\n", - volume->name); - - strncpy(new_node->name,volume->name, - EVMS_VOLUME_NAME_SIZE + 1); - - // Is the volume read-only? - if (!(volume->lv_access & AIX_LV_WRITE) - || volume->lv_access & EVMS_LV_INCOMPLETE) - { - new_node->flags |= EVMS_VOLUME_SET_READ_ONLY; - LOG_DEBUG(" EV Read Only volume->lv_access:%d\n", - volume->lv_access); - } - - evms_cs_add_logical_node_to_list(evms_partition_list, - new_node); - count++; - - LOG_DEBUG(" Exporting LVM volume %p new_node:%p ESD->volume_name[%s]\n", - volume, new_node,new_node->name); - } else { - evms_cs_add_logical_node_to_list(evms_partition_list, - AIXVGLPtr->volume_list[j]->volume_node); - count++; - LOG_DEBUG(" ELV vol_list[%d]%p\n", j, - AIXVGLPtr->volume_list[j]); - } - } else { - LOG_DEBUG(" EV Checking LV:[%d] == NULL\n",j); - } - } // end checking all lvs - - AIXVGLPtr->flags &= ~AIX_VG_DIRTY; - } - - return count; -} - -/* - * Function: delete_logical_volume - * - * This function deletes the in-memory representation of a single LVM - * logical volume, including its PE map and any snapshot data. It does - * not alter the parent volume group, except to remove this volume from - * its volume list. - */ -static int -delete_logical_volume(struct aix_logical_volume *volume) -{ - struct aix_volume_group *group = volume->group; - - LOG_DEBUG(" Deleting volume %s\n", volume->name); - - // Now free up all the memory. This includes the LE-to-PE map, any - // mirror PEs, etc. - if (volume->le_to_pe_map) { - kfree(volume->le_to_pe_map); - volume->le_to_pe_map = NULL; - } - - if (volume->le_to_pe_map_mir1) { - kfree(volume->le_to_pe_map_mir1); - volume->le_to_pe_map_mir1 = NULL; - } - - if (volume->le_to_pe_map_mir2) { - kfree(volume->le_to_pe_map_mir2); - volume->le_to_pe_map_mir2 = NULL; - } - // Remove this volume from the volume-group's list. - if (group && group->volume_list[volume->lv_number] == volume) { - group->volume_list[volume->lv_number] = NULL; - group->numlvs--; - } - - kfree(volume); - - return 0; -} - -/* Function: remove_group_from_list - * - * Remove an LVM volume group from the global LVM list. - */ -static int -remove_group_from_list(struct aix_volume_group *group) -{ - struct aix_volume_group **p_group; - - for (p_group = &AIXVolumeGroupList; *p_group; - p_group = &(*p_group)->next) { - if (*p_group == group) { - *p_group = (*p_group)->next; - group->next = NULL; - break; - } - } - return 0; -} - -/* - * Function: delete_aix_node - * - * This function deletes the in-memory representation of an LVM - * logical volume. Right now it makes a lot of assumptions about - * the data in the group not being corrupted. It would be possible - * to put in a lot of consistency checks before deleting everything - * to indicate if problems have occurred during the lifetime of the - * volume and its volume group. - */ -static int -delete_aix_node(struct evms_logical_node *logical_node) -{ - struct aix_logical_volume *volume = - (struct aix_logical_volume *) (logical_node->private); - struct aix_volume_group *group = volume->group; - - if (delete_logical_volume(volume)) { - return -EINVAL; - } - // If we just removed the last volume from this group, the entire group - // can also be deleted. - if (group && group->numlvs == 0) { - remove_group_from_list(group); - deallocate_volume_group(group); - } - // Free the logical node. - evms_cs_deallocate_logical_node(logical_node); - - return 0; -} - -/* Function: deallocate_volume_group - * - * This function deletes the entire in-memory representation of an LVM - * volume group, including all partitions and logical volumes. If this - * group is on the VGE's volume group list, it is removed. - */ -static int -deallocate_volume_group(struct aix_volume_group *group) -{ - struct partition_list_entry *partition; - struct partition_list_entry *next_part; - int i; - - LOG_DEBUG(" Deleting volume group %x\n", group->vg_id.word2); - - // Delete all partitions from the group's list. - for (partition = group->partition_list; partition; - partition = next_part) { - - next_part = partition->next; - - if (partition->logical_node) { - // Send a delete command down to the partition manager. - LOG_DEBUG(" Deleting PV %d from group %x\n", - partition->pv_number, group->vg_id.word2); - DELETE(partition->logical_node); - } - kfree(partition); - } - - // Delete all logical volumes, and the array of pointers. - for (i = 0; i < LVM_MAXLVS; i++) { - if (group->volume_list[i]) { - delete_logical_volume(group->volume_list[i]); - } - } - - kfree(group); - - return 0; -} - -/* Function: end_discover_aix - * - * The discovery process at the region-manager level is now iterative, - * much like the EVMS feature level. To accomplish this correctly, and - * also to accomplish partial volume discovery, a second discover - * entry point is needed, so EVMS can tell the region managers that - * discovery is over, and to finish up any discovery that is not yet - * complete. When this function is called, it should be assumed that - * the node list has had nothing new added to it since the last call - * of the regular discover function. Therefore, when this function is - * called, we do not need to try to discovery any additional volume - * groups. We will, however, look for logical volumes once more. This - * gives us the ability to export (read-only) volumes that have - * partially corrupted LE maps due to missing PVs in their VG. - */ -static int -end_discover_aix(struct evms_logical_node **evms_logical_disk_head) -{ - - int rc; - - MOD_INC_USE_COUNT; - LOG_DEBUG("Final Discovery:\n"); - - rc = discover_logical_volumes(); - - if (!rc) { - rc = export_volumes(evms_logical_disk_head); - - lvm_cleanup(); - } - - MOD_DEC_USE_COUNT; - return rc; -} - -/**************************************************** -* Function: AIX_alloc_wbh -* -* Alloc any buffer heads from the pool and return a linked list -* -* -*****************************************************/ -static struct aix_mirror_bh * -AIX_alloc_wbh(struct evms_logical_node *node, - struct evms_logical_node *node2, - struct evms_logical_node *node3, - struct buffer_head *bh, - u32 mirror_copies, u32 le, u64 new_sector2, u64 new_sector3) -{ - struct aix_mirror_bh *tmp_bh = NULL, *head_bh = NULL; - int i; - - head_bh = evms_cs_allocate_from_pool(AIX_BH_list_pool, EVMS_BLOCKABLE); - - if (!head_bh) { - LOG_SERIOUS("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - - head_bh->master_bh = bh; - head_bh->mirror_bh_list = NULL; - atomic_set(&head_bh->remaining, 0); - - for (i = AIX_DEFAULT_MIRRORING; i <= mirror_copies; i++) { - - tmp_bh = - evms_cs_allocate_from_pool(AIX_BH_list_pool, - EVMS_BLOCKABLE); - if (!tmp_bh) { - LOG_SERIOUS("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - - tmp_bh->next_r1 = head_bh->mirror_bh_list; - head_bh->mirror_bh_list = tmp_bh; - atomic_inc(&head_bh->remaining); - - memcpy(&tmp_bh->bh_req, bh, sizeof (struct buffer_head)); - atomic_set(&tmp_bh->remaining, 0); - init_waitqueue_head(&tmp_bh->bh_req.b_wait); - //tmp_bh->bh_req.b_size = bh->b_size; - - switch (i) { - - case AIX_DEFAULT_MIRRORING: - tmp_bh->node = node; - tmp_bh->bh_req.b_rsector = bh->b_rsector; - break; - - case AIX_FIRST_MIRROR: - tmp_bh->node = node2; - tmp_bh->bh_req.b_rsector = new_sector2; - break; - - case AIX_MAX_MIRRORS: - tmp_bh->node = node3; - tmp_bh->bh_req.b_rsector = new_sector3; - break; - } - - tmp_bh->bh_req.b_end_io = AIX_handle_write_mirror_drives; //setup callback routine - tmp_bh->bh_req.b_private = (void *) head_bh; - - } - - return head_bh; - -} - -/**************************************************** -* Function: AIX_handle_write_mirror_drives -* -* Handles a write from a set of mirrored AIX LVs - -* -* -*****************************************************/ -static void -AIX_handle_write_mirror_drives(struct buffer_head *bh, int uptodate) -{ - struct aix_logical_volume *volume; - struct evms_logical_node *node; - struct aix_mirror_bh *tmp_bh = NULL, *tmp_bh2 = NULL; - kdev_t tmp_b_rdev; - u32 count, le = 0; - - tmp_bh = (struct aix_mirror_bh *) bh->b_private; - tmp_b_rdev = tmp_bh->master_bh->b_rdev; - node = tmp_bh->node; - volume = (struct aix_logical_volume *) node->private; - - LOG_DEBUG("AHWMD node:%p bh_flags:%lu uptodate:%d mirror_copies:%d \n", - node, bh->b_state, uptodate, volume->mirror_copies); - - if (!uptodate) { - le = tmp_bh->le; - - switch (tmp_bh->iteration) { - case AIX_DEFAULT_MIRRORING: - volume->le_to_pe_map[le].pp_state += AIX_LVM_LVSTALE; - break; - - case AIX_FIRST_MIRROR: - volume->le_to_pe_map_mir1[le].pp_state += - AIX_LVM_LVSTALE; - break; - - case AIX_MAX_MIRRORS: - volume->le_to_pe_map_mir2[le].pp_state += - AIX_LVM_LVSTALE; - break; - } - - AIX_evms_cs_notify_lv_io_error(node); - } - - if (atomic_dec_and_test(&tmp_bh->remaining)) { - tmp_bh->master_bh->b_end_io(tmp_bh->master_bh, uptodate); - tmp_bh2 = tmp_bh->mirror_bh_list; - evms_cs_deallocate_to_pool(AIX_BH_list_pool, tmp_bh); - - while (tmp_bh2) { - tmp_bh = tmp_bh2->next_r1; - evms_cs_deallocate_to_pool(AIX_BH_list_pool, tmp_bh2); - tmp_bh2 = tmp_bh; - } - - evms_cs_volume_request_in_progress(tmp_b_rdev, - AIX_DECREMENT_REQUEST, - &count); - } - - return; -} - -/**************************************************** -* Function: AIX_alloc_rbh -* -* Alloc any buffer heads from the pool and return a linked list -* -* -*****************************************************/ -static struct aix_mirror_bh * -AIX_alloc_rbh(struct evms_logical_node *node, - struct buffer_head *bh, - u32 mirror_copies, u32 le, u64 org_sector, int cmd) -{ - struct aix_mirror_bh *tmp_bh = NULL; - - tmp_bh = evms_cs_allocate_from_pool(AIX_BH_list_pool, EVMS_BLOCKABLE); - - if (!tmp_bh) { - LOG_SERIOUS - ("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - - memcpy(&tmp_bh->bh_req, bh, sizeof (struct buffer_head)); - atomic_set(&tmp_bh->remaining, 0); - tmp_bh->node = node; - tmp_bh->master_bh = bh; - tmp_bh->iteration = AIX_FIRST_MIRROR; - //tmp_bh->eio.rsector = eio->rsector; - //tmp_bh->eio.rsize = eio->rsize; - tmp_bh->le = le; - //tmp_bh->eio.bh = &tmp_bh->bh_req; - - if (cmd == AIX_LV_READ) { - tmp_bh->bh_req.b_end_io = AIX_handle_read_mirror_drives; //setup callback routine - } else { - tmp_bh->bh_req.b_end_io = AIX_sync_mirrored_partitions; //setup callback routine - } - - tmp_bh->bh_req.b_private = (void *) tmp_bh; - - tmp_bh->cmd = cmd; - tmp_bh->next_r1 = NULL; - tmp_bh->node = node; - - return tmp_bh; - -} - -/**************************************************** -* Function: AIX_reschedule_retry -* -* reschedule a read of one of our mirror copies -* -* -*****************************************************/ -static void -AIX_reschedule_retry(struct aix_mirror_bh *aix_bh) -{ - unsigned long flags; - - spin_lock_irqsave(&AIX_retry_list_lock, flags); - if (AIX_retry_list == NULL) - AIX_retry_tail = &AIX_retry_list; - *AIX_retry_tail = aix_bh; - AIX_retry_tail = &aix_bh->next_r1; - aix_bh->next_r1 = NULL; - spin_unlock_irqrestore(&AIX_retry_list_lock, flags); - evms_cs_wakeup_thread(AIX_mirror_read_retry_thread); -} - -/**************************************************** -* Function: AIX_handle_read_mirror_drives -* -* Handles a read from a set of mirrored AIX LVs - -* -* -*****************************************************/ -static void -AIX_handle_read_mirror_drives(struct buffer_head *bh, int uptodate) -{ - struct aix_logical_volume *volume; - struct evms_logical_node *node; - struct aix_mirror_bh *tmp_bh; - kdev_t tmp_b_rdev; - u32 count, le = 0; - - tmp_bh = (struct aix_mirror_bh *) bh->b_private; - tmp_b_rdev = tmp_bh->master_bh->b_rdev; - volume = (struct aix_logical_volume *) tmp_bh->node->private; - node = tmp_bh->node; - le = tmp_bh->le; - - LOG_DEBUG("AHRMD node:%p bh_flags:%lu uptodate:%d mirror_copies:%d \n", - node, bh->b_state, uptodate, volume->mirror_copies); - - switch (tmp_bh->iteration) { - case AIX_DEFAULT_MIRRORING: - count = volume->le_to_pe_map[le].pp_state; - break; - - case AIX_FIRST_MIRROR: - count = volume->le_to_pe_map[le].pp_state; - break; - - case AIX_MAX_MIRRORS: - count = volume->le_to_pe_map[le].pp_state; - break; - } - - if (count == (AIX_LVM_LVSTALE + AIX_LVM_LVDEFINED)) { - uptodate = 0; - count = 0; - } - - if (!uptodate && tmp_bh->iteration < volume->mirror_copies) { - AIX_evms_cs_notify_lv_io_error(node); - AIX_reschedule_retry(tmp_bh); - } else { - tmp_bh->master_bh->b_end_io(tmp_bh->master_bh, uptodate); - evms_cs_deallocate_to_pool(AIX_BH_list_pool, tmp_bh); - evms_cs_volume_request_in_progress(tmp_b_rdev, - AIX_DECREMENT_REQUEST, - &count); - - } - - return; -} - -/**************************************************** -* This is a temporary function until a common EVMS -* notification function can be created. -* -*****************************************************/ -static int -AIX_evms_cs_notify_lv_io_error(struct evms_logical_node *node) -{ - struct aix_logical_volume *volume; - - volume = (struct aix_logical_volume *) node->private; - - LOG_CRITICAL("Notify_ERROR !! node:%p volume->lv_status:%d volume->name:[%s]\n", - node, volume->lv_status, volume->name); - - return 0; -} - -/* Function: lvm_cleanup - * - * This function runs through the entire lvm data structure, removing - * all items that are not needed at runtime. Currently, this is just the - * vg_disk_t structure and the pv_disk_t structure for each PV. Also, any - * groups that don't contain any volumes are deleted. All of the other - * volume_group, logical_volume and evms_logical_node structures will be - * kept around at run-time. - */ -static int -lvm_cleanup(void) -{ - struct aix_volume_group *group; - - group = AIXVolumeGroupList; - - while (group) { - - if (group->AIXvgh) { - kfree(group->AIXvgh); - group->AIXvgh = NULL; - } - - group = group->next; - } - - return 0; -} - -/**************************************************** -* Function: AIX_copy_header_info -* -* Copy the disk header info into the volume struct -* so we can use it later. -* -* -* -*****************************************************/ -static int -AIX_copy_header_info(struct vg_header *AIXvgh, struct vg_header *AIXvgh2) -{ - - LOG_DEBUG("CHI AIXvgh:%p AIXvgh2:%p\n", AIXvgh, AIXvgh2); - - if (AIXvgh) { - - AIXvgh->vg_timestamp.tv_sec = AIXvgh2->vg_timestamp.tv_sec; - AIXvgh->vg_timestamp.tv_nsec = AIXvgh2->vg_timestamp.tv_nsec; - AIXvgh->vg_id.word1 = AIXvgh2->vg_id.word1; - AIXvgh->vg_id.word2 = AIXvgh2->vg_id.word2; - AIXvgh->vg_id.word3 = AIXvgh2->vg_id.word3; - AIXvgh->vg_id.word4 = AIXvgh2->vg_id.word4; - AIXvgh->numlvs = AIXvgh2->numlvs; - AIXvgh->maxlvs = AIXvgh2->maxlvs; - AIXvgh->pp_size = AIXvgh2->pp_size; - AIXvgh->numpvs = AIXvgh2->numpvs; - AIXvgh->total_vgdas = AIXvgh2->total_vgdas; - AIXvgh->vgda_size = AIXvgh2->vgda_size; - AIXvgh->bigvg = AIXvgh2->bigvg; - AIXvgh->quorum = AIXvgh2->quorum; - AIXvgh->auto_varyon = AIXvgh2->auto_varyon; - AIXvgh->checksum = AIXvgh2->checksum; - AIXvgh->bigda_size = AIXvgh2->bigda_size; - - } else { - return -ENOMEM; - } - - LOG_DEBUG("Returning CHI AIXvgh:%p AIXvgh2:%p\n", AIXvgh, AIXvgh2); - - return 0; -} - -/**************************************************** -* Function: AIX_free_header -* -* -* -* -* -*****************************************************/ -static void -AIX_free_headers(struct vg_header *AIXvgh, struct vg_header *AIXvgh2, - struct vg_trailer *AIXvgt, struct vg_trailer *AIXvgt2) -{ - - if (AIXvgh) { - kfree(AIXvgh); - AIXvgh = NULL; - } - - if (AIXvgh2) { - kfree(AIXvgh2); - AIXvgh2 = NULL; - } - - if (AIXvgt) { - kfree(AIXvgt); - AIXvgt = NULL; - } - - if (AIXvgt2) { - kfree(AIXvgt2); - AIXvgt2 = NULL; - } - -} - -/**************************************************** -* Function: AIXiod -* -* This is a kernel thread that handles read of mirrors -* This shouldn't ever run on a non-mirrored LV read -* -* -*****************************************************/ -static void -AIXiod(void *data) -{ - struct aix_mirror_bh *r1_bh; - struct evms_logical_node *node; - unsigned long flags; - - while (1) { - - spin_lock_irqsave(&AIX_retry_list_lock, flags); - if (AIX_retry_list == NULL) { - spin_unlock_irqrestore(&AIX_retry_list_lock, flags); - break; - } - r1_bh = AIX_retry_list; - AIX_retry_list = r1_bh->next_r1; - spin_unlock_irqrestore(&AIX_retry_list_lock, flags); - r1_bh->next_r1 = NULL; // for mark - - switch (r1_bh->cmd) { - case AIX_LV_READ: - - r1_bh->iteration++; - LOG_DEBUG("Report from thread AIXiod READ\n"); - - if (r1_bh->iteration == AIX_FIRST_MIRROR) { - node = r1_bh->mir_node1; - r1_bh->bh_req.b_rsector = r1_bh->mir_sector1; - } else { - node = r1_bh->mir_node2; - r1_bh->bh_req.b_rsector = r1_bh->mir_sector2; - } - - R_IO(node, &r1_bh->bh_req); - - break; - - default: - LOG_DEBUG("AIXiod unknown cmd passed to thread:%d\n", - r1_bh->cmd); - break; - } - - } - return; -} - -/**************************************************** -* Function: AIX_schedule_resync -* -* schedule a resync of one of our lv mirror copies -* -* -*****************************************************/ -static void -AIX_schedule_resync(struct aix_logical_volume *resync_volume, int force) -{ - unsigned long flags; - - LOG_DEBUG("Function %s volume: %s \n", __FUNCTION__, - resync_volume->name); - - spin_lock_irqsave(&AIX_resync_list_lock, flags); - - if (!AIX_resync_list) { - AIX_resync_list = - kmalloc(sizeof (struct aix_resync_struct), GFP_ATOMIC); - if (!AIX_resync_list) { - return; - } - memset(AIX_resync_list, 0, sizeof (struct aix_resync_struct)); - } - - AIX_resync_list->resync_vol = resync_volume; - AIX_resync_list->next_resync_vol = NULL; - - spin_unlock_irqrestore(&AIX_resync_list_lock, flags); - evms_cs_wakeup_thread(AIX_mirror_resync_thread); -} - -/**************************************************** -* Function: AIXresync -* -* This is a kernel thread that handles resync of mirrors -* This shouldn't ever run on a non-mirrored LV -* -* -*****************************************************/ -static void -AIXresync(void *data) -{ - - struct aix_logical_volume *volume = NULL; - int force = FALSE; // Currently we don't force a resync of non-stale pe's - - if (AIX_resync_list == NULL) { - LOG_ERROR("No Volumes on list to resync\n"); - return; - } - - volume = AIX_resync_list->resync_vol; - LOG_DEBUG("Function %s volume: %s \n", __FUNCTION__, volume->name); - - if (!volume) { - LOG_ERROR("Invalid volume passed to sync\n"); - return; - } - - if (AIXResyncInProgress) { - LOG_ERROR("Unable to resync multiple LVs concurrently %s\n", - volume->name); - return; - } - - if (volume->mirror_copies == AIX_DEFAULT_MIRRORING) { - LOG_ERROR("Unable to resync non-mirrored LV %s \n", - volume->name); - return; - } - - AIXResyncInProgress = TRUE; - - AIX_resync_lv_mirrors(volume, force); - - return; -} - -/**************************************************** -* Function: AIX_resync_lv_mirrors -* -* -* -* -* -*****************************************************/ -static int -AIX_resync_lv_mirrors(struct aix_logical_volume *volume, int force) -{ - - int i; - char pp_stale = FALSE; - - struct partition_list_entry *master_part = NULL; - struct partition_list_entry *slave1_part = NULL; - struct partition_list_entry *slave2_part = NULL; - - u64 master_offset = 0; - u64 slave1_offset = 0; - u64 slave2_offset = 0; - - LOG_DEBUG("Function %s volume: %s \n", __FUNCTION__, volume->name); - - for (i = 0; i < volume->num_le; i++, pp_stale = FALSE) { - - // We need to see which mirror has a valid non-stale copy. - // The first non-stale copy will be our master and we'll - // copy to the slave(s). - - if ((volume->le_to_pe_map[i].pp_state & AIX_LVM_LVSTALE)) { - pp_stale = TRUE; - } - - if (volume->le_to_pe_map_mir1 != NULL) { - if ((volume->le_to_pe_map_mir1[i]. - pp_state & AIX_LVM_LVSTALE)) { - pp_stale = TRUE; - } - } - - if (volume->le_to_pe_map_mir2 != NULL) { - if ((volume->le_to_pe_map_mir2[i]. - pp_state & AIX_LVM_LVSTALE)) { - pp_stale = TRUE; - } - } - - LOG_DEBUG("Function %s pp_stale:%d force:%d \n", __FUNCTION__, - pp_stale, force); - - if (pp_stale || force) { - if (!(volume->le_to_pe_map[i].pp_state & AIX_LVM_LVSTALE)) { - - master_part = volume->le_to_pe_map[i].owning_pv; - master_offset = volume->le_to_pe_map[i].pe_sector_offset; - - if (volume->le_to_pe_map_mir1 != NULL) { - slave1_part = volume->le_to_pe_map_mir1[i].owning_pv; - slave1_offset = volume->le_to_pe_map_mir1[i].pe_sector_offset; - } - - if (volume->le_to_pe_map_mir2 != NULL) { - slave2_part = volume->le_to_pe_map_mir2[i].owning_pv; - slave2_offset = volume->le_to_pe_map_mir2[i].pe_sector_offset; - } - } else - if (!(volume->le_to_pe_map_mir1[i].pp_state & AIX_LVM_LVSTALE)) { - master_part = volume->le_to_pe_map_mir1[i].owning_pv; - master_offset = volume->le_to_pe_map_mir1[i].pe_sector_offset; - - if (volume->le_to_pe_map != NULL) { - slave1_part = volume->le_to_pe_map[i].owning_pv; - slave1_offset = volume->le_to_pe_map[i].pe_sector_offset; - } - - if (volume->le_to_pe_map_mir2 != NULL) { - slave2_part = volume->le_to_pe_map_mir2[i].owning_pv; - slave2_offset = volume->le_to_pe_map_mir2[i].pe_sector_offset; - } - } else - if (!(volume->le_to_pe_map_mir2[i].pp_state & AIX_LVM_LVSTALE)) { - master_part = volume->le_to_pe_map_mir2[i].owning_pv; - master_offset = volume->le_to_pe_map_mir2[i].pe_sector_offset; - - if (volume->le_to_pe_map != NULL) { - slave1_part = volume->le_to_pe_map[i].owning_pv; - slave1_offset = volume->le_to_pe_map[i].pe_sector_offset; - } - - if (volume->le_to_pe_map_mir1 != NULL) { - slave2_part = volume->le_to_pe_map_mir1[i].owning_pv; - slave2_offset = volume->le_to_pe_map_mir1[i].pe_sector_offset; - } - } - - if (AIX_copy_on_read(volume, master_part, slave1_part, slave2_part, - master_offset, slave1_offset, slave2_offset, - volume->pe_size, i)) { - - LOG_CRITICAL("ReSync of logical Volume %s FAILED !!\n", - volume->name); - AIX_evms_cs_notify_lv_io_error(volume-> - volume_node); - break; - } - - } - - } - - return 0; -} - -/**************************************************** -* Function: AIX_copy_on_read -* -* -* -* -* -*****************************************************/ -static int -AIX_copy_on_read(struct aix_logical_volume *volume, - struct partition_list_entry *master_part, - struct partition_list_entry *slave1_part, - struct partition_list_entry *slave2_part, - u64 master_offset, - u64 slave1_offset, u64 slave2_offset, u32 pe_size, int le) -{ - unsigned long flags; - struct aix_mirror_bh *tmp_bh = NULL; - - // Check for valid partitions we need at least 2 good partitions so slave2 doesn't have to be valid - - if (!master_part || !slave1_part) { - LOG_ERROR("Invalid partitions for resync master part:%p slave1_part:%p slave2_part:%p\n", - master_part, slave1_part, slave2_part); - return -EINVAL; - } - - LOG_DEBUG("Function %s volume:%s master_part:%d, slave1_part:%d, slave2_part:%d master_offset:" - PFU64 ", slave1_offset:" PFU64 " slave2_offset:" PFU64 ", \n", - __FUNCTION__, volume->name, master_part->pv_number, - slave1_part->pv_number, slave2_part->pv_number, master_offset, - slave1_offset, slave2_offset); - - LOG_DEBUG("pe_size:%d le:%d\n", pe_size, le); - - tmp_bh = - AIX_alloc_sbh(volume, master_part, slave1_part, slave2_part, - master_offset, slave1_offset, slave2_offset, pe_size); - - if (!tmp_bh) { - buffer_IO_error(&tmp_bh->bh_req); - return -ENOMEM; - } - -/* if (evms_cs_volume_request_in_progress - (tmp_bh->bh_req.b_rdev, AIX_INCREMENT_REQUEST, &count)) { - buffer_IO_error(&tmp_bh->bh_req); - return -EIO; - } */ - - spin_lock_irqsave(&AIX_resync_pp_lock, flags); - - LOG_DEBUG("Function:%s kicking off read node:%p\n", __FUNCTION__, - master_part->logical_node); - - R_IO(master_part->logical_node, &tmp_bh->bh_req); - - spin_unlock_irqrestore(&AIX_resync_pp_lock, flags); - - return 0; -} - -/**************************************************** -* Function: AIX_alloc_sbh -* -* Alloc any buffer heads from the pool and return a linked list -* -* -*****************************************************/ -static struct aix_mirror_bh * -AIX_alloc_sbh(struct aix_logical_volume *volume, - struct partition_list_entry *master_part, - struct partition_list_entry *slave1_part, - struct partition_list_entry *slave2_part, - u64 master_offset, - u64 slave1_offset, u64 slave2_offset, u32 pe_size) -{ - struct aix_mirror_bh *tmp_bh = NULL, *head_bh = NULL; - unsigned long flags; - - LOG_DEBUG("Function:%s Enter\n", __FUNCTION__); - - head_bh = evms_cs_allocate_from_pool(AIX_BH_list_pool, EVMS_BLOCKABLE); - if (!head_bh) { - LOG_SERIOUS - ("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - // Update buffer so we block on a read/write on the normal IO path - // if we're trying to sync the same sector on the disk - // We don't want to block if it's different sectors - - spin_lock_irqsave(&AIX_resync_list_lock, flags); - - AIX_resync_list->master_part = master_part; - AIX_resync_list->slave1_part = slave1_part; - AIX_resync_list->slave2_part = slave2_part; - AIX_resync_list->master_offset = master_offset; - AIX_resync_list->slave1_offset = slave1_offset; - AIX_resync_list->slave2_offset = slave2_offset; - - head_bh->bh_req.b_data = kmalloc(AIX_RESYNC_BLOCKSIZE + 1, GFP_NOIO); - if (!head_bh->bh_req.b_data) { - evms_cs_deallocate_to_pool(AIX_BH_list_pool, head_bh); - LOG_SERIOUS - ("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - - memset(head_bh->bh_req.b_data, 0, AIX_RESYNC_BLOCKSIZE + 1); - - atomic_set(&head_bh->remaining, 0); - head_bh->bh_req.b_rsector = master_offset; - head_bh->bh_req.b_size = AIX_RESYNC_BLOCKSIZE; - head_bh->sync_flag = AIX_SYNC_INCOMPLETE; - head_bh->bh_req.b_end_io = AIX_sync_mirrored_partitions; - head_bh->bh_req.b_page = virt_to_page(head_bh->bh_req.b_data); - head_bh->bh_req.b_state = 0; - set_bit(BH_Dirty, &head_bh->bh_req.b_state); - set_bit(BH_Lock, &head_bh->bh_req.b_state); - set_bit(BH_Req, &head_bh->bh_req.b_state); - set_bit(BH_Mapped, &head_bh->bh_req.b_state); - head_bh->master_bh = NULL; - head_bh->mirror_bh_list = NULL; - - tmp_bh = evms_cs_allocate_from_pool(AIX_BH_list_pool, EVMS_BLOCKABLE); - if (!tmp_bh) { - LOG_SERIOUS - ("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - - head_bh->next_r1 = tmp_bh; - memcpy(&tmp_bh->bh_req, head_bh, sizeof (struct buffer_head)); - atomic_set(&tmp_bh->remaining, 0); - tmp_bh->bh_req.b_end_io = NULL; - - if (volume->mirror_copies == AIX_MAX_MIRRORS) { - tmp_bh->next_r1 = - evms_cs_allocate_from_pool(AIX_BH_list_pool, - EVMS_BLOCKABLE); - if (!tmp_bh->next_r1) { - LOG_SERIOUS - ("Unable to allocate memory for mirror pool line:%d\n", - __LINE__); - return NULL; - } - - memcpy(&tmp_bh->next_r1->bh_req, head_bh, - sizeof (struct buffer_head)); - tmp_bh->next_r1->bh_req.b_end_io = NULL; - atomic_set(&tmp_bh->next_r1->remaining, 0); - } - - init_waitqueue_head(&head_bh->bh_req.b_wait); - - spin_unlock_irqrestore(&AIX_resync_list_lock, flags); - - LOG_DEBUG("Function:%s Exit head_bh:%p\n", __FUNCTION__, head_bh); - - return head_bh; -} - -/**************************************************** -* Function: AIX_sync_mirrored_partitions -* -* -* -* -* -*****************************************************/ -static void -AIX_sync_mirrored_partitions(struct buffer_head *bh, int uptodate) -{ - struct aix_logical_volume *volume = NULL; - struct aix_mirror_bh *tmp_bh, *head_bh; - - head_bh = tmp_bh = (struct aix_mirror_bh *) bh->b_private; - volume = (struct aix_logical_volume *) tmp_bh->node->private; - - LOG_DEBUG("Function:%s Enter uptodate:%d\n", __FUNCTION__, uptodate); - - if (!uptodate) { - - AIX_evms_cs_notify_lv_io_error(tmp_bh->node); - } - - tmp_bh = head_bh->next_r1; - - LOG_DEBUG("Function:%s line:%d write to mirror:%p\n", __FUNCTION__, - __LINE__, tmp_bh); - - if (tmp_bh) { - W_IO(tmp_bh->node, &tmp_bh->bh_req); - AIX_get_set_mirror_offset(tmp_bh, AIX_SLAVE_1, - AIX_RESYNC_BLOCKSIZE); - } - - tmp_bh = tmp_bh->next_r1; - LOG_DEBUG("Function:%s line:%d write to mirror:%p\n", __FUNCTION__, - __LINE__, tmp_bh); - - if (tmp_bh) { - W_IO(tmp_bh->node, &tmp_bh->bh_req); - AIX_get_set_mirror_offset(tmp_bh, AIX_SLAVE_2, - AIX_RESYNC_BLOCKSIZE); - } - - LOG_DEBUG("Function:%s line:%d read from master:%p\n", __FUNCTION__, - __LINE__, head_bh); - - if (head_bh && head_bh->sync_flag) { - AIX_get_set_mirror_offset(head_bh, AIX_MASTER, - AIX_RESYNC_BLOCKSIZE); - if (head_bh->sync_flag == AIX_SYNC_INCOMPLETE) { - R_IO(head_bh->node, &head_bh->bh_req); - } - } - - LOG_DEBUG("Function:%s line:%d head_bh->sync_flag:%d\n", __FUNCTION__, - __LINE__, head_bh->sync_flag); - - if (!head_bh->sync_flag) { - tmp_bh = head_bh; - head_bh = head_bh->next_r1; - - while (tmp_bh != NULL) { - evms_cs_deallocate_to_pool(AIX_BH_list_pool, tmp_bh); - tmp_bh = head_bh; - } - - AIXResyncInProgress = FALSE; -/* evms_cs_volume_request_in_progress(tmp_bh->bh_req.b_rdev, - AIX_DECREMENT_REQUEST, - &count); */ - - if (AIX_resync_list) { - kfree(AIX_resync_list); - } - } - - return; -} - -/**************************************************** -* Function: AIX_get_set_mirror_offset -* -* -* -* -* -*****************************************************/ -static int -AIX_get_set_mirror_offset(struct aix_mirror_bh *tmp_bh, int index, int offset) -{ - int flags; - - if (!tmp_bh) { - return -EINVAL; - } - - LOG_DEBUG("Function:%s Enter offset:%d\n", __FUNCTION__, offset); - - tmp_bh->bh_req.b_rsector += tmp_bh->bh_req.b_rsector + offset; - - if (tmp_bh->bh_req.b_rsector > tmp_bh->node->total_vsectors) { - tmp_bh->sync_flag = AIX_SYNC_COMPLETE; - return -EIO; - } - // Update buffer so we block on a read/write on the normal IO path - // if we're trying to sync the same sector on the disk - // We don't want to block if it's different sectors - - spin_lock_irqsave(&AIX_resync_list_lock, flags); - - if (AIX_resync_list->master_part->logical_node == tmp_bh->node) { - AIX_resync_list->master_offset += offset; - } - - if (AIX_resync_list->slave1_part->logical_node == tmp_bh->node) { - AIX_resync_list->slave1_offset += offset; - } - - if (AIX_resync_list->slave2_part->logical_node == tmp_bh->node) { - AIX_resync_list->slave2_offset += offset; - } - - spin_unlock_irqrestore(&AIX_resync_list_lock, flags); - - return 0; - -} - -static int AIX_pvh_data_posn(u32 vgda_psn, u32 * pvh_posn, struct partition_list_entry *partition, u32 numpvs) -{ - struct partition_list_entry * pv; - struct pv_header * AIXpvh; - int posn = 0; - int num_pps; - int tmp,i; - - LOG_DEBUG("APDP - vgda_psn:%d numpvs:%d \n", vgda_psn, numpvs); - - AIXpvh = kmalloc(AIX_SECTOR_SIZE, GFP_KERNEL); - if (!AIXpvh) { - return -ENOMEM; - } - - memset(AIXpvh, 0 , sizeof(struct pv_header)); - - // Adjust this because when AIX VGs/Volumes are created on Intel platforms, the - // pp_count could be anything since we don't give up the entire physical drive. - // This is for calculation purposes only. - - pvh_posn[0] = 0; - pv = partition; - - for (i = 1; i <= numpvs; i++) { - for (pv = partition; pv->pv_number != i; pv = pv->next ); - - LOG_DEBUG("APDP line:%d pp_count:%d \n", __LINE__, AIXpvh->pp_count); - - num_pps = AIXpvh->pp_count; - num_pps++; // Account for the pv_header on the front - - while ((num_pps * sizeof(struct pp_entries)) % AIX_SECTOR_SIZE) { - LOG_EXTRA("num_pps:%d \n", num_pps); - num_pps++; - } - - tmp = (num_pps * sizeof(struct pp_entries)) / AIX_SECTOR_SIZE; - - LOG_DEBUG("APDP tmp:%d num_pps:%d \n", tmp,num_pps); - - posn = ((vgda_psn + PSN_PPH_OFFSET) + ((pv->pv_number -1) * tmp)); - - pvh_posn[pv->pv_number] = posn; - - if (INIT_IO(pv->logical_node, 0, posn, 1, AIXpvh)) { - kfree(AIXpvh); - return -EIO; - } - - pv = partition; - } - - kfree(AIXpvh); - - return 0; -} - -/**************************************************** -* Function: AIX_volume_group_dump -* -* This is for debug purposes and will walk the volume group list -* and LV's within the volume groups -* -* It can be called at anytime however the output to the display is large -* -*****************************************************/ -#ifdef EVMS_AIX_DEBUG -static int -AIX_volume_group_dump(void) -{ - struct aix_volume_group *AIXVGLDebugPtr; - struct partition_list_entry *DebugPartitionList; - struct aix_logical_volume *DebugLVList; - int i; - - AIXVGLDebugPtr = AIXVolumeGroupList; - - if (!AIXVGLDebugPtr) { - LOG_DEBUG("***********************************************\n"); - LOG_DEBUG("ERROR Nothing built in the list to check !!! \n"); - LOG_DEBUG("***********************************************\n"); - return 0; - } - - LOG_DEBUG("*********************************************** \n"); - LOG_DEBUG("Begin Volume Group Dump \n"); - LOG_DEBUG("*********************************************** \n"); - - while (AIXVGLDebugPtr) { - - LOG_DEBUG("vg_number %x\n", AIXVGLDebugPtr->vg_id.word2); - LOG_DEBUG("numpsrtitions %d\n", AIXVGLDebugPtr->partition_count); - LOG_DEBUG("numlvs %d\n", AIXVGLDebugPtr->numlvs); - LOG_DEBUG("hard_sect_size %d\n", AIXVGLDebugPtr->hard_sect_size); - LOG_DEBUG("block_size %d\n", AIXVGLDebugPtr->block_size); - LOG_DEBUG("flags %d\n", AIXVGLDebugPtr->flags); -// LOG_DEBUG("lv_max %d\n", AIXVGLDebugPtr->lv_max); - LOG_DEBUG("pe_size %d\n", AIXVGLDebugPtr->pe_size); - LOG_DEBUG("CleanVGInfo %d\n", AIXVGLDebugPtr->CleanVGInfo); - - DebugPartitionList = AIXVGLDebugPtr->partition_list; - - LOG_DEBUG("********* Begin Volume Partition Dump ********* \n"); - - if (!DebugPartitionList) { - LOG_DEBUG("No partitions to check !! \n"); - } - - while (DebugPartitionList) { - LOG_DEBUG("logical_node %p\n", - DebugPartitionList->logical_node); - LOG_DEBUG("pv_number %d\n", - DebugPartitionList->pv_number); - LOG_DEBUG("block_size %d\n", - DebugPartitionList->block_size); - LOG_DEBUG("hard_sect_size %d\n", - DebugPartitionList->hard_sect_size); - LOG_DEBUG("-------------------------------------------------------------\n"); - DebugPartitionList = DebugPartitionList->next; - } - - LOG_DEBUG("********* End Volume Partition Dump **********\n"); - - LOG_DEBUG("********** Begin Logical Volume Partition Dump **********\n"); - - DebugLVList = AIXVGLDebugPtr->volume_list[0]; - - if (!DebugLVList) { - LOG_DEBUG("No logical volumes to check !! \n"); - } - - for (i = 0; i < LVM_MAXLVS && DebugLVList; i++) { - - DebugLVList = AIXVGLDebugPtr->volume_list[i]; - - if (DebugLVList) { - LOG_DEBUG("volume_list # %d \n", i); - LOG_DEBUG("lv_number %d \n", - DebugLVList->lv_number); - LOG_DEBUG("LV name %s \n", - DebugLVList->name); - LOG_DEBUG("lv_size " PFU64 " \n", - DebugLVList->lv_size); - LOG_DEBUG("lv_access %d \n", - DebugLVList->lv_access); - LOG_DEBUG("lv_status %d \n", - DebugLVList->lv_status); -// LOG_DEBUG("lv_minor %d \n", -// DebugLVList->lv_minor); - LOG_DEBUG("mirror_copies %d \n", - DebugLVList->mirror_copies); -// LOG_DEBUG("mirror_number %d \n", -// DebugLVList->mirror_number); - LOG_DEBUG("stripes %d \n", - DebugLVList->stripes); - LOG_DEBUG("stripe_size %d \n", - DebugLVList->stripe_size); - LOG_DEBUG("stripe_size_shift%d \n", - DebugLVList->stripe_size_shift); - LOG_DEBUG("pe_size %d \n", - DebugLVList->pe_size); - LOG_DEBUG("pe_size_shift %d \n", - DebugLVList->pe_size_shift); - LOG_DEBUG("num_le %d \n", - DebugLVList->num_le); -// LOG_DEBUG("new_volume %d \n", -// DebugLVList->new_volume); - LOG_DEBUG("group %p \n", - DebugLVList->group); - } - - } - - AIXVGLDebugPtr = AIXVGLDebugPtr->next; - - LOG_DEBUG("********** End Logical Volume Partition Dump **********\n"); - - } - - LOG_DEBUG("***********************************************\n"); - LOG_DEBUG("End Volume Group Dump \n"); - LOG_DEBUG("***********************************************\n"); - - return 0; - -} -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/Config.in linux-2.4.20-wolk4.7-fullkernel/drivers/evms/Config.in --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/Config.in 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/Config.in 1970-01-01 01:00:00.000000000 +0100 @@ -1,62 +0,0 @@ -# -# Copyright (c) International Business Machines Corp., 2000 -# -# 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 -# -# -# EVMS driver configuration -# - -mainmenu_option next_comment -comment 'Enterprise Volume Management System (EVMS)' - -tristate 'EVMS Kernel Runtime' CONFIG_EVMS -dep_tristate ' EVMS Local Device Manager' CONFIG_EVMS_LOCAL_DEV_MGR $CONFIG_EVMS -dep_tristate ' EVMS DOS Segment Manager' CONFIG_EVMS_DOS_SEGMENT_MGR $CONFIG_EVMS -dep_tristate ' EVMS GPT Segment Manager' CONFIG_EVMS_GPT_SEGMENT_MGR $CONFIG_EVMS -if [ "$CONFIG_ARCH_S390" = "y" ]; then -dep_tristate ' EVMS S/390 Segment Manager' CONFIG_EVMS_S390_SEGMENT_MGR $CONFIG_EVMS -fi -dep_tristate ' EVMS SnapShot Feature' CONFIG_EVMS_SNAPSHOT $CONFIG_EVMS -dep_tristate ' EVMS DriveLink Feature' CONFIG_EVMS_DRIVELINK $CONFIG_EVMS -dep_tristate ' EVMS Bad Block Relocation (BBR) Feature' CONFIG_EVMS_BBR $CONFIG_EVMS -dep_tristate ' EVMS Linux LVM Package' CONFIG_EVMS_LVM $CONFIG_EVMS -dep_tristate ' EVMS Linux MD Package' CONFIG_EVMS_MD $CONFIG_EVMS -dep_tristate ' EVMS MD Linear (append) mode' CONFIG_EVMS_MD_LINEAR $CONFIG_EVMS_MD -dep_tristate ' EVMS MD RAID-0 (stripe) mode' CONFIG_EVMS_MD_RAID0 $CONFIG_EVMS_MD -dep_tristate ' EVMS MD RAID-1 (mirroring) mode' CONFIG_EVMS_MD_RAID1 $CONFIG_EVMS_MD -dep_tristate ' EVMS MD RAID-4/RAID-5 mode' CONFIG_EVMS_MD_RAID5 $CONFIG_EVMS_MD -dep_tristate ' EVMS AIX LVM Package' CONFIG_EVMS_AIX $CONFIG_EVMS -dep_tristate ' EVMS OS/2 LVM Package' CONFIG_EVMS_OS2 $CONFIG_EVMS - -if [ "$CONFIG_EVMS" != "n" ]; then - - define_bool CONFIG_MEMORYPOOL y - - choice ' EVMS Debug Level' \ - "Critical CONFIG_EVMS_INFO_CRITICAL \ - Serious CONFIG_EVMS_INFO_SERIOUS \ - Error CONFIG_EVMS_INFO_ERROR \ - Warning CONFIG_EVMS_INFO_WARNING \ - Default CONFIG_EVMS_INFO_DEFAULT \ - Details CONFIG_EVMS_INFO_DETAILS \ - Debug CONFIG_EVMS_INFO_DEBUG \ - Extra CONFIG_EVMS_INFO_EXTRA \ - Entry_Exit CONFIG_EVMS_INFO_ENTRY_EXIT \ - Everything CONFIG_EVMS_INFO_EVERYTHING" Default -fi - -endmenu - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/evms/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/Makefile 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/Makefile 1970-01-01 01:00:00.000000000 +0100 @@ -1,63 +0,0 @@ -# -# Makefile for the kernel EVMS driver and modules. -# -# 08 March 2001, Mark Peloquin -# - -O_TARGET := evmsdrvr.o - -export-objs := evms.o evms_passthru.o ldev_mgr.o dos_part.o lvm_vge.o \ - snapshot.o evms_drivelink.o evms_bbr.o AIXlvm_vge.o \ - os2lvm_vge.o md_core.o md_linear.o md_raid0.o \ - md_raid1.o md_raid5.o md_xor.o s390_part.o gpt_part.o - -# Link order is important! Plugins must come first, then the EVMS core. - -obj-$(CONFIG_EVMS_LOCAL_DEV_MGR) += ldev_mgr.o -obj-$(CONFIG_EVMS_DOS_SEGMENT_MGR) += dos_part.o -obj-$(CONFIG_EVMS_GPT_SEGMENT_MGR) += gpt_part.o -obj-$(CONFIG_EVMS_S390_SEGMENT_MGR) += s390_part.o -obj-$(CONFIG_EVMS_MD) += md_core.o -obj-$(CONFIG_EVMS_MD_LINEAR) += md_linear.o -obj-$(CONFIG_EVMS_MD_RAID0) += md_raid0.o -obj-$(CONFIG_EVMS_MD_RAID1) += md_raid1.o -obj-$(CONFIG_EVMS_MD_RAID5) += md_raid5.o md_xor.o -obj-$(CONFIG_EVMS_LVM) += lvm_vge.o -obj-$(CONFIG_EVMS_AIX) += AIXlvm_vge.o -obj-$(CONFIG_EVMS_OS2) += os2lvm_vge.o -obj-$(CONFIG_EVMS_DRIVELINK) += evms_drivelink.o -obj-$(CONFIG_EVMS_BBR) += evms_bbr.o -obj-$(CONFIG_EVMS_SNAPSHOT) += snapshot.o -obj-$(CONFIG_EVMS) += evms_passthru.o evms.o - -EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_DEFAULT -DO1_SCHEDULER -ifeq ($(CONFIG_EVMS_INFO_CRITICAL),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_CRITICAL -endif -ifeq ($(CONFIG_EVMS_INFO_SERIOUS),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_SERIOUS -endif -ifeq ($(CONFIG_EVMS_INFO_ERROR),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_ERROR -endif -ifeq ($(CONFIG_EVMS_INFO_WARNING),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_WARNING -endif -ifeq ($(CONFIG_EVMS_INFO_DETAILS),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_DETAILS -endif -ifeq ($(CONFIG_EVMS_INFO_DEBUG),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_DEBUG -endif -ifeq ($(CONFIG_EVMS_INFO_EXTRA),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_EXTRA -endif -ifeq ($(CONFIG_EVMS_INFO_ENTRY_EXIT),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_ENTRY_EXIT -endif -ifeq ($(CONFIG_EVMS_INFO_EVERYTHING),y) - EXTRA_CFLAGS=-DEVMS_INFO_LEVEL=EVMS_INFO_EVERYTHING -endif - -include $(TOPDIR)/Rules.make - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/dos_part.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/dos_part.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/dos_part.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/dos_part.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1445 +0,0 @@ -/* -*- linux-c -*- */ -/* - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ -/* - * linux/drivers/evms/dos_part.c - * - * EVMS DOS partition manager - * - * Partial code extracted from - * - * linux/fs/partitions/msdos.c - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for kiobuf stuffs */ - -#ifdef CONFIG_BLK_DEV_IDE -#include /* IDE xlate */ -#endif /* CONFIG_BLK_DEV_IDE */ - -#include -#include - -#include -#include - -/* prefix used in logging messages */ -#define LOG_PREFIX "dos_part: " - -/* #include "msdos.h" */ -#define MSDOS_LABEL_MAGIC 0xAA55 -#define GPT_ENTIRE_DISK_INDICATOR 0xEE -#define GPT_ESP_INDICATOR 0xEF - -/** - * struct mbr_ebr - Skeletal MBR/EBR structure useful for our purposes - * @unused1: skip IPL record code - * @partitions: partition table - * @signature: DOS magic - * - * skeletal access to parition table in MBR/EBR - **/ -struct mbr_ebr { - u8 unused1[0x1be]; - struct partition partitions[4]; - u16 signature; -}; - -/** - * struct dos_private - Private data structure for this plugin - * @source_object: object this IO will get remapped to - * @start_sect: source object relative starting address in 512 byte units - * @nr_sect: partition size in 512 bytes units - * @type: partition type or filesystem format indicator - * - * private copy of the just the fields we require to remap IO requests - * to the underlying object. - **/ -struct dos_private { - struct evms_logical_node *source_disk; - u64 start_sect; - u64 nr_sects; - unsigned char type; -}; - -/** - * struct extended_part - Structure used to track progress traversing an EBR chain - * @extended: partition table in the extended boot record - * @start_sect: address of the extended boot record in 512 byte units - * @next_ebr_start: address of next ebr in the chain - * @done: progress flag - * - * struct used to track extended boot record chain traversals. - **/ -struct extended_part { - struct partition *extended; - u64 start_sect; - u64 next_ebr_start; - int done; -}; - -/* Global variables */ -static int cur_comp_part_num; /* used to track non-primary - * partition numbers - */ -static int exported_nodes; /* total # of exported segments - * produced during this discovery. - */ - -/* External references */ -#if CONFIG_BLK_DEV_MD && CONFIG_AUTODETECT_RAID -extern void md_autodetect_dev(kdev_t dev); -#endif - -/* Prototypes */ -static int mbr_ebr_partition_discover(struct evms_logical_node **); -static int mbr_ebr_partition_delete(struct evms_logical_node *); -static void mbr_ebr_partition_read(struct evms_logical_node *, - struct buffer_head *); -static void mbr_ebr_partition_write(struct evms_logical_node *, - struct buffer_head *); -static int mbr_ebr_partition_ioctl(struct evms_logical_node *, struct inode *, - struct file *, unsigned int, unsigned long); -static int mbr_ebr_partition_init_io(struct evms_logical_node *, - int, u64, u64, void *); - -static struct evms_plugin_fops fops = { - .discover = mbr_ebr_partition_discover, - .delete = mbr_ebr_partition_delete, - .read = mbr_ebr_partition_read, - .write = mbr_ebr_partition_write, - .init_io = mbr_ebr_partition_init_io, - .ioctl = mbr_ebr_partition_ioctl -}; - -#define EVMS_MSDOS_PARTITION_MANAGER_ID 1 - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_SEGMENT_MANAGER, - EVMS_MSDOS_PARTITION_MANAGER_ID), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2 - }, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0 - }, - .fops = &fops -}; - -/* - * Many architectures don't like unaligned accesses, which is - * frequently the case with the nr_sects and start_sect partition - * table entries. - */ -#include - -#define SYS_IND(p) (get_unaligned(&p->sys_ind)) -#define NR_SECTS(p) (u64)({ __typeof__(p->nr_sects) __a = \ - get_unaligned(&p->nr_sects); \ - le32_to_cpu(__a); \ - }) - -#define START_SECT(p) (u64)({ __typeof__(p->start_sect) __a = \ - get_unaligned(&p->start_sect); \ - le32_to_cpu(__a); \ - }) - -/******************************************/ -/* List Support - Variables, & Functions */ -/******************************************/ - -/* Typedefs */ - -struct segment_list_node { - struct evms_logical_node *segment; - struct segment_list_node *next; -}; - -struct disk_list_node { - struct evms_logical_node *disk; - struct segment_list_node *segment_list; - struct disk_list_node *next; -}; - -/* Variables */ - -static struct disk_list_node *my_disk_list; - -/* Functions */ - -static struct disk_list_node ** -lookup_disk(struct evms_logical_node *disk) -{ - struct disk_list_node **ldln; - - ldln = &my_disk_list; - while (*ldln) { - if ((*ldln)->disk == disk) - break; - ldln = &(*ldln)->next; - } - return (ldln); -} - -static struct segment_list_node ** -lookup_segment(struct disk_list_node *disk, struct evms_logical_node *segment) -{ - struct segment_list_node **lsln; - - lsln = &disk->segment_list; - while (*lsln) { - if ((*lsln)->segment == segment) - break; - lsln = &(*lsln)->next; - } - return (lsln); -} - -static struct evms_logical_node * -find_segment_on_disk(struct evms_logical_node *disk, - u64 start_sect, u64 nr_sects) -{ - struct evms_logical_node *rc = NULL; - struct disk_list_node **ldln; - struct segment_list_node **lsln; - struct dos_private *dos_prv; - - ldln = lookup_disk(disk); - if (*ldln) { - /* disk found in list */ - /* attempt to find segment */ - - lsln = &(*ldln)->segment_list; - while (*lsln) { - dos_prv = (*lsln)->segment->private; - if (dos_prv->start_sect == start_sect) - if (dos_prv->nr_sects == nr_sects) - break; - lsln = &(*lsln)->next; - } - if (*lsln) - rc = (*lsln)->segment; - } - return (rc); -} - -/* function description: add_segment_to_disk - * - * this function attempts to add a segment to the segment - * list of a disk. if the specified disk is not found, it - * will be added to the global disk list. this function will - * return a pointer to the matching segment in the disk's - * segment list. the caller must compare the returned pointer - * to the specified segment to see if the - * specified segment was already present in the disk's segment - * list. if the return pointer matches the specified segment, - * then the specified segment was added to the list. if the - * return segment pointer to does not match the specified - * segment pointer, then the specified segment pointer was - * a duplicate and can be thrown away. - */ -static int -add_segment_to_disk(struct evms_logical_node *disk, - struct evms_logical_node *segment) -{ - int rc = 0; - struct disk_list_node **ldln, *new_disk; - struct segment_list_node **lsln, *new_segment; - - ldln = lookup_disk(disk); - if (*ldln == NULL) { - /* disk not in list, add disk */ - new_disk = kmalloc(sizeof (*new_disk), GFP_KERNEL); - if (new_disk) { - memset(new_disk, 0, sizeof (*new_disk)); - new_disk->disk = disk; - *ldln = new_disk; - } else { - rc = -ENOMEM; - } - } - if (!rc) { - /* attempt to add segment */ - lsln = lookup_segment(*ldln, segment); - if (*lsln == NULL) { - /* segment not in list, add segment */ - new_segment = - kmalloc(sizeof (*new_segment), GFP_KERNEL); - if (new_segment) { - memset(new_segment, 0, sizeof (*new_segment)); - new_segment->segment = segment; - *lsln = new_segment; - } else { - rc = -ENOMEM; - } - } else - rc = -1; - } - return (rc); -} - -static int -remove_segment_from_disk(struct evms_logical_node *disk, - struct evms_logical_node *segment, - struct evms_logical_node **empty_disk) -{ - int rc = 0; - struct disk_list_node **ldln, *tmp_disk_node; - struct segment_list_node **lsln, *tmp_segment_node; - - *empty_disk = NULL; - ldln = lookup_disk(disk); - if (*ldln == NULL) { - rc = -1; - } else { - /* disk found in list */ - /* attempt to add segment */ - lsln = lookup_segment(*ldln, segment); - if (*lsln == NULL) { - rc = -2; - } else { - tmp_segment_node = *lsln; - /* remove segment from list */ - *lsln = (*lsln)->next; - /* free the segment list node */ - kfree(tmp_segment_node); - - if ((*ldln)->segment_list == NULL) { - tmp_disk_node = *ldln; - *empty_disk = tmp_disk_node->disk; - /* remove disk from list */ - *ldln = (*ldln)->next; - /* free the disk list node */ - kfree(tmp_disk_node); - } - } - } - return (rc); -} - -static inline int -is_extended_partition(struct partition *p) -{ - return (SYS_IND(p) == DOS_EXTENDED_PARTITION || - SYS_IND(p) == WIN98_EXTENDED_PARTITION || - SYS_IND(p) == LINUX_EXTENDED_PARTITION); -} - -static inline u64 -part_start(struct partition *part, u64 ext_start, u64 ebr_start) -{ - u64 pstart = START_SECT(part); - pstart += (is_extended_partition(part)) ? ext_start : ebr_start; - return (pstart); -} - -static int -validate_mbr_ebr(struct evms_logical_node *node, - struct mbr_ebr *mbr_ebr, u64 ext_start, - u64 ebr_start) -{ - int valid_mbr_ebr, i, j, mbr_flag; - struct partition *pi, *pj; - u64 pi_start, pi_end, pj_start, pj_end; - - /* assume an MBR */ - mbr_flag = TRUE; - - /* assume its valid */ - valid_mbr_ebr = TRUE; - - /* check for valid signature */ - if (mbr_ebr->signature != cpu_to_le16(MSDOS_LABEL_MAGIC)) { - LOG_DEBUG("%s: invalid signature on '%s'!\n", - __FUNCTION__, node->name); - valid_mbr_ebr = FALSE; - } - - /* check for an AIX IPL signature */ -#define IPLRECID 0xc9c2d4c1 /* Value is EBCIDIC 'IBMA' */ - if (*(unsigned int *) mbr_ebr == IPLRECID) { - LOG_DEBUG("%s: found an AIX IPL signature on '%s'\n", - __FUNCTION__, node->name); - valid_mbr_ebr = FALSE; - } - - /* check for boot sector fields */ - -#if 0 //Remove checking of the first byte - - /* attempt to make some initial assumptions about - * what type of data structure this could be. we - * start by checking the 1st byte. we can tell a - * few things based on what is or isn't there. - */ - if (valid_mbr_ebr == TRUE) - switch (*(u_char *) mbr_ebr) { - /* check for JMP as 1st instruction - * if found, assume (for now), that - * this is a boot sector. - */ - /* Removed the JMP opcode check because it's not enough to determine - * that this sector does not have a valid MBR. - * Note: To avoid going thru validation process of partition table, - * it's necessary to have a better boot sector check - * (eg. JMP opcode && other conditions) */ - /* - case 0xEB: - LOG_DEBUG("%s: boot sector detected!\n", __FUNCTION__); - valid_mbr_ebr = FALSE; - */ - /* let this fall thru to pick up the - * mbr_flag == FALSE. - */ - - /* the MBR should contain boot strap - * code, so we don't expect the 1st - * byte to be a 0x0. If the 1st byte - * IS 0x0, its assumed (for now) to - * be an EBR. - */ - case 0: - mbr_flag = FALSE; - break; - } -#endif //Remove checking of the first byte - - if (valid_mbr_ebr == TRUE) { - /* dump the partition table entries in debug mode */ - LOG_DEBUG - ("%s: disk relative starts: ext_part("PFU64"), ebr("PFU64").\n", - __FUNCTION__, ext_start, ebr_start); - for (i = 0; i < 4; i++) { - pi = &mbr_ebr->partitions[i]; - LOG_DEBUG - ("%s: Partition: index(%d), start("PFU64"), size("PFU64"), sys(0x%x).\n", - __FUNCTION__, i, START_SECT(pi), NR_SECTS(pi), - SYS_IND(pi)); - } - - /* check for PMBR (Protected Master Boot Record) - * and skip this node if found - */ - for (i = 0; i < 4; i++) { - pi = &mbr_ebr->partitions[i]; - - if (SYS_IND(pi) == 0xEE) { - valid_mbr_ebr = FALSE; - LOG_DETAILS - ("%s: detected PMBR on '%s', skipping.\n", - __FUNCTION__, node->name); - break; - } - } - - /* check of this segment is marked as non-dividable - * and skip if found - */ - if (node->iflags & EVMS_TOP_SEGMENT) { - valid_mbr_ebr = FALSE; - } - } - - if (valid_mbr_ebr == TRUE) { - /* check for mbr/ebr partition table validity */ - for (i = 0; i < 4; i++) { - pi = &mbr_ebr->partitions[i]; - if (NR_SECTS(pi)) { - /* check for partition extending past end of node */ - pi_start = part_start(pi, ext_start, ebr_start); - pi_end = pi_start + NR_SECTS(pi) - 1; - if (pi_end >= node->total_vsectors) { - LOG_DEBUG - ("%s: partition(%d) ends("PFU64") beyond the end of the disk(%s,"PFU64")!\n", - __FUNCTION__, i, pi_end, - node->name, node->total_vsectors); - valid_mbr_ebr = FALSE; - } - if (valid_mbr_ebr == FALSE) - break; - - /* check for partition overlap */ - for (j = i + 1; j < 4; j++) { - pj = &mbr_ebr->partitions[j]; - if (NR_SECTS(pj)) { - pj_start = - part_start(pj, ext_start, - ebr_start); - pj_end = - pj_start + NR_SECTS(pj) - 1; - if (pi_start == pj_start) { - valid_mbr_ebr = FALSE; - } else if (pi_start < pj_start) { - if (pi_end >= pj_start) - valid_mbr_ebr = - FALSE; - } else if (pi_start <= pj_end) - valid_mbr_ebr = FALSE; - - if (valid_mbr_ebr == FALSE) { - LOG_DEBUG - ("%s: overlapping partitions(%d,%d) detected on '%s'!\n", - __FUNCTION__, i, j, - node->name); - break; - } - } - } - if (valid_mbr_ebr == FALSE) - break; - } - } - } - if (valid_mbr_ebr == TRUE) { - LOG_DEBUG("%s: valid %cBR detected on '%s'!\n", __FUNCTION__, - (mbr_flag == TRUE) ? 'M' : 'E', node->name); - } else { - LOG_DEBUG("%s: no valid MBR/EBR detected on '%s'!\n", - __FUNCTION__, node->name); - } - return (valid_mbr_ebr); -} - -/* - * Function: add_segment - */ -static int -mbr_ebr_process_segment(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - u64 start_sect, - u64 nr_sects, - unsigned char type, int part_num, char *partition_name) -{ - struct dos_private *dos_prv = NULL; - struct evms_logical_node *segment; - int rc = 0; - - segment = find_segment_on_disk(node, start_sect, nr_sects); - if (segment) { - LOG_DETAILS("exporting segment '%s'.\n", segment->name); - } else { - dos_prv = kmalloc(sizeof (*dos_prv), GFP_KERNEL); - if (dos_prv) { - memset(dos_prv, 0, sizeof (*dos_prv)); - dos_prv->source_disk = node; - dos_prv->start_sect = start_sect; - dos_prv->nr_sects = nr_sects; - dos_prv->type = type; - rc = evms_cs_allocate_logical_node(&segment); - } else { - rc = -ENOMEM; - } - if (!rc) { - segment->plugin = &plugin_header; - segment->system_id = (unsigned int) type; - segment->total_vsectors = nr_sects; - segment->block_size = node->block_size; - segment->hardsector_size = node->hardsector_size; - segment->private = dos_prv; - segment->flags = node->flags; - if (partition_name) - strcpy(segment->name, partition_name); - else { - strcpy(segment->name, node->name); - if (GetPluginType(node->plugin->id) == - EVMS_SEGMENT_MANAGER) { - strcat(segment->name, "."); - } - sprintf(segment->name + strlen(segment->name), - "%d", part_num); - } - /* watch for super floppy format gpt system partition - * and dont let it be sub divided - */ - if (segment->system_id == GPT_ESP_INDICATOR) { - node->iflags |= EVMS_TOP_SEGMENT; - } - LOG_DETAILS("creating segment '%s'.\n", segment->name); - rc = add_segment_to_disk(node, segment); - if (rc) { - LOG_ERROR - ("%s: error(%d) adding segment '%s'!\n", - __FUNCTION__, rc, segment->name); - rc = 0; - } else { - MOD_INC_USE_COUNT; - } - } - if (rc) { - if (dos_prv) - kfree(dos_prv); - if (segment) - evms_cs_deallocate_logical_node(segment); - } - } - if (!rc) { - evms_cs_add_logical_node_to_list(discover_list, segment); - exported_nodes++; - } - return rc; -} - -static inline void -print_partition_info(char *leading_comment, struct partition *p) -{ - LOG_EXTRA("%s: boot_ind(0x%02x), sys_ind(0x%02x), startCHS(%u,%u,%u), endCHS(%u,%u,%u), startLBA("PFU64"), sizeLBA("PFU64")\n", - leading_comment, p->boot_ind, p->sys_ind, p->cyl, p->head, - p->sector, p->end_cyl, p->end_head, p->end_sector, - START_SECT(p), NR_SECTS(p)); -} - -#ifdef CONFIG_BSD_DISKLABEL -#define BSD_DISKLABEL_PART_TABLE_SECTOR_OFFSET 1 -static inline void -print_bsd_partition_info(char *leading_comment, struct bsd_partition *p) -{ - LOG_EXTRA("%s: p_size(%u), p_offset(%u), p_fsize(%u), p_fstype(0x%02X), p_frag(0x%02X), p_cpg(%u)\n", - leading_comment, p->p_size, p->p_offset, p->p_fsize, p->p_fstype, p->p_frag, p->p_cpg); -} - -/* - * bsd_disklabel_partition - * - * Return: - * - 0 for 0 partition - * - (positive) number for number of BSD partitions found - * - (negative) error code - */ -static int -bsd_disklabel_partition(struct evms_logical_node **discover_list, - struct evms_logical_node *node, struct partition *bsd) -{ - struct bsd_disklabel *l; - struct bsd_partition *p; - int max_partitions; - char *data; - int rc = 0; - int count = 0; - - data = kmalloc(node->hardsector_size, GFP_KERNEL); - if (data) - rc = INIT_IO(node, - 0, - START_SECT(bsd) + - BSD_DISKLABEL_PART_TABLE_SECTOR_OFFSET, 1, data); - else - rc = -ENOMEM; - if (!rc) { - - l = (struct bsd_disklabel *) data; - if (l->d_magic == BSD_DISKMAGIC) { - - max_partitions = - ((SYS_IND(bsd) == - OPENBSD_PARTITION) ? OPENBSD_MAXPARTITIONS : - BSD_MAXPARTITIONS); - if (l->d_npartitions < max_partitions) - max_partitions = l->d_npartitions; - for (p = l->d_partitions; - p - l->d_partitions < max_partitions; p++) { - if (p->p_fstype != BSD_FS_UNUSED) { - print_bsd_partition_info(__FUNCTION__, p); - rc = mbr_ebr_process_segment - (discover_list, node, - (u64) p->p_offset, - (u64) p->p_size, p->p_fstype, - cur_comp_part_num++, NULL); - if (rc) - break; - count++; - } - } - } - } - if (data) - kfree(data); - if (!rc) - rc = count; - LOG_DETAILS("%s: exported (%d) partitions\n", __FUNCTION__, rc); - return rc; -} -#endif - -#ifdef CONFIG_UNIXWARE_DISKLABEL -#define UNIXWARE_PART_TABLE_SECTOR_OFFSET 29 - -/* - * unixware_partition - * - * Return: - * - 0 for 0 partition - * - (positive) number for number of UNIXWARE partitions found - * - (negative) error code - */ -static int -unixware_partition(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - struct partition *unixware_part) -{ - struct unixware_disklabel *l; - struct unixware_slice *p; - char *data = NULL; - int rc = 0; - int count = 0; - - data = kmalloc(node->hardsector_size, GFP_KERNEL); - if (data) - rc = INIT_IO(node, - 0, - START_SECT(unixware_part) + - UNIXWARE_PART_TABLE_SECTOR_OFFSET, 1, data); - else - rc = -ENOMEM; - if (!rc) { - l = (struct unixware_disklabel *) data; - if (le32_to_cpu(l->d_magic) == UNIXWARE_DISKMAGIC && - le32_to_cpu(l->vtoc.v_magic) == UNIXWARE_DISKMAGIC2) { - p = &l->vtoc.v_slice[1]; /* The 0th slice is the same as whole disk. */ - while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { - if (p->s_label != UNIXWARE_FS_UNUSED) { - rc = mbr_ebr_process_segment - (discover_list, node, START_SECT(p), - NR_SECTS(p), UNIXWARE_PARTITION, - cur_comp_part_num++, NULL); - if (rc) - break; - count++; - } - p++; - } - } - } - if (data) - kfree(data); - if (!rc) - rc = count; - LOG_DETAILS("%s: exported (%d) partitions\n", __FUNCTION__, rc); - return rc; -} -#endif - -#ifdef CONFIG_SOLARIS_X86_PARTITION -#define SOLARIS_X86_PART_TABLE_SECTOR_OFFSET 1 -/* - * solaris_x86_partition - * - * Return: - * - 0 for 0 partition - * - (positive) number for number of solaris partitions found - * - (negative) error code - */ -static int -solaris_x86_partition(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - struct partition *solaris_x86, int probe_only) -{ /* if TRUE, do not add segments */ - long offset = START_SECT(solaris_x86); - struct solaris_x86_vtoc *v; - struct solaris_x86_slice *s; - int i; - char *data = NULL; - int rc = 0; - int count = 0; - - data = kmalloc(node->hardsector_size, GFP_KERNEL); - if (data) - rc = INIT_IO(node, - 0, - START_SECT(solaris_x86) + - SOLARIS_X86_PART_TABLE_SECTOR_OFFSET, 1, data); - else - rc = -ENOMEM; - if (!rc) { - - v = (struct solaris_x86_vtoc *) data; - - if (v->v_sanity == SOLARIS_X86_VTOC_SANE) { - if (v->v_version != 1) { - LOG_WARNING - ("%s: cannot handle version %d vtoc>\n", - __FUNCTION__, v->v_version); - } else { - for (i = 0; i < v->v_nparts; i++) { - s = &v->v_slice[i]; - LOG_EXTRA - ("s[%d] s_tag(%u), s_flag(%u), s_start(%u), s_size(%u), last_sector(%u)\n", - i, s->s_tag, s->s_flag, s->s_start, - s->s_size, - s->s_start + s->s_size - 1); - - if ((s->s_size == 0) - || (s->s_tag == 0x05)) - continue; - if (!probe_only) { - rc = mbr_ebr_process_segment - (discover_list, node, - (u64) (s->s_start + - offset), - (u64) s->s_size, - SOLARIS_X86_PARTITION, - cur_comp_part_num++, NULL); - if (rc) - break; - } - count++; - } - } - } - } - if (data) - kfree(data); - if (!rc) - rc = count; - LOG_DETAILS("%s: %s (%d) partitions\n", - __FUNCTION__, probe_only ? " " : "exported", rc); - return rc; -} -#endif - -/* - * os2lvm_partition() looks for DLAT at last sector of the track containing MBR/EBR - * - * Returns: 1 - os2 DLAT was found - * 0 otherwise - * - */ -static int -os2lvm_partition(u64 MBR_EBR_sect, - struct evms_logical_node *node, struct dla_table_sector *dlat) -{ - struct hd_geometry geometry; - int rc; - u32 crc_hold; - - rc = evms_cs_kernel_ioctl(node, HDIO_GETGEO, (unsigned long) &geometry); - if (rc) { - LOG_SERIOUS("%s: ioctl failed(%u) on '%s'\n", - __FUNCTION__, rc, node->name); - } else - if (!INIT_IO(node, 0, MBR_EBR_sect + geometry.sectors - 1, 1, dlat)) - { - if ((dlat->DLA_Signature1 == cpu_to_le32(DLA_TABLE_SIGNATURE1)) - && (dlat->DLA_Signature2 == - cpu_to_le32(DLA_TABLE_SIGNATURE2))) { - crc_hold = le32_to_cpu(dlat->DLA_CRC); - dlat->DLA_CRC = 0; - if (evms_cs_calculate_crc - (EVMS_INITIAL_CRC, (void *) dlat, - node->hardsector_size) == crc_hold) - return 1; - } - } - return 0; -} - -static int -mbr_ebr_process_logical_drive(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - struct extended_part *ext_info, - int i, - struct partition *p, - int os2lvm, struct dla_table_sector *dlat) -{ - int rc = 0; - char tmp_buf[EVMS_VOLUME_NAME_SIZE], *partition_name; - - LOG_EXTRA("%s: PartitionTableIndex(%i), Start("PFU64"), Size("PFU64")\n", - __FUNCTION__, i, START_SECT(p), NR_SECTS(p)); - - if (NR_SECTS(p)) { - if (is_extended_partition(p)) { - ext_info->next_ebr_start = - (u64) (START_SECT(p) + - START_SECT(ext_info->extended)); - ext_info->done = FALSE; /* not done yet */ - } else { - partition_name = NULL; - if (os2lvm && p->sys_ind != LVM_PARTITION_INDICATOR && - le32_to_cpu(dlat->DLA_Array[i].Partition_Start) == - (ext_info->start_sect + START_SECT(p)) - && le32_to_cpu(dlat->DLA_Array[i].Partition_Size) == - NR_SECTS(p) - && dlat->DLA_Array[i].Drive_Letter != '\0') { - sprintf(tmp_buf, "os2/%c", - dlat->DLA_Array[i].Drive_Letter); - partition_name = tmp_buf; - } - print_partition_info(__FUNCTION__, p); - - rc = mbr_ebr_process_segment(discover_list, - node, - ext_info->start_sect + - START_SECT(p), NR_SECTS(p), - p->sys_ind, - cur_comp_part_num++, - partition_name); - } - } - return (rc); -} - -static int -mbr_ebr_process_ebr(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - struct extended_part *ext_info, struct mbr_ebr *ebr) -{ - int rc = 0, i, os2lvm; - struct partition *p; - struct dla_table_sector *dlat = NULL; - - /* allocate space for the OS2 DLAT info */ - dlat = kmalloc(node->hardsector_size, GFP_KERNEL); - if (dlat) { - /* read the dlat for this mbr */ - os2lvm = os2lvm_partition(ext_info->start_sect, node, dlat); - - /* walk thru the partition table in the mbr - * processing each partition record. - */ - for (i = 0; i < 4; i++) { - p = &ebr->partitions[i]; - rc = mbr_ebr_process_logical_drive(discover_list, - node, - ext_info, - i, p, os2lvm, dlat); - } - } else { - rc = -ENOMEM; - } - - /* free the space used for OS2 DLAT info */ - if (dlat) - kfree(dlat); - - return (rc); -} - -static int -mbr_ebr_probe_for_ebr(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - struct extended_part *ext_info) -{ - int rc = 0; - u_char *sector_buffer = NULL; - struct mbr_ebr *ebr = NULL; - - /* allocate a sector size buffer */ - sector_buffer = kmalloc(node->hardsector_size, GFP_KERNEL); - if (sector_buffer) - /* read the location of the mbr sector */ - rc = INIT_IO(node, 0, ext_info->start_sect, 1, sector_buffer); - else - rc = -ENOMEM; - - if (!rc) { - ebr = (struct mbr_ebr *) sector_buffer; - if (validate_mbr_ebr(node, ebr, - START_SECT(ext_info->extended), - ext_info->start_sect) == TRUE) - rc = mbr_ebr_process_ebr(discover_list, - node, ext_info, ebr); - } - - if (sector_buffer) - kfree(sector_buffer); - - return (rc); -} - -static int -mbr_ebr_process_extended_partition(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - struct partition *p) -{ - int rc = 0; - struct extended_part ext_info; - - memset(&ext_info, 0, sizeof (ext_info)); - ext_info.done = FALSE; - ext_info.extended = p; - ext_info.next_ebr_start = START_SECT(p); - while (ext_info.done == FALSE) { - ext_info.done = TRUE; /* assume done, unless we find another EBR */ - ext_info.start_sect = ext_info.next_ebr_start; - rc = mbr_ebr_probe_for_ebr(discover_list, node, &ext_info); - } - return rc; -} - -/* - * is_non_dos_extended - * - * This function returns TRUE if the partition entry represents a non-DOS - * extended partition such as UnixWare, Solaris x86 and BSD - */ -static int -is_non_dos_extended(struct evms_logical_node **discover_list, - struct evms_logical_node *node, struct partition *p) -{ - if (NR_SECTS(p)) { -#ifdef CONFIG_BSD_DISKLABEL - if (SYS_IND(p) == BSD_PARTITION || - SYS_IND(p) == NETBSD_PARTITION || - SYS_IND(p) == OPENBSD_PARTITION) - return TRUE; -#endif - -#ifdef CONFIG_UNIXWARE_DISKLABEL - if (SYS_IND(p) == UNIXWARE_PARTITION) - return TRUE; -#endif - -#ifdef CONFIG_SOLARIS_X86_PARTITION - if ((SYS_IND(p) == SOLARIS_X86_PARTITION) && - (solaris_x86_partition(discover_list, node, p, TRUE) > 0)) - return TRUE; -#endif - } - return (FALSE); -} - -/* - * mbr_ebr_process_other_primary_partition - * This function processes other (non-DOS) primary partitions such as - * UnixWare, Solaris x86 and BSD - */ -static int -mbr_ebr_process_other_primary_partition(struct evms_logical_node - **discover_list, - struct evms_logical_node *node, - struct partition *p) -{ - if (NR_SECTS(p)) { -#ifdef CONFIG_BSD_DISKLABEL - if (SYS_IND(p) == BSD_PARTITION || - SYS_IND(p) == NETBSD_PARTITION || - SYS_IND(p) == OPENBSD_PARTITION) - return bsd_disklabel_partition(discover_list, node, p); -#endif - -#ifdef CONFIG_UNIXWARE_DISKLABEL - if (SYS_IND(p) == UNIXWARE_PARTITION) - return unixware_partition(discover_list, node, p); -#endif - -#ifdef CONFIG_SOLARIS_X86_PARTITION - if (SYS_IND(p) == SOLARIS_X86_PARTITION) - return solaris_x86_partition(discover_list, node, p, - FALSE); -#endif - } - return (0); -} - -static int -mbr_ebr_process_dos_primary_partition(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - int i, - struct partition *p, - int os2lvm, struct dla_table_sector *dlat) -{ - int rc = 0; - char tmp_buf[EVMS_VOLUME_NAME_SIZE], *partition_name; - - LOG_EVERYTHING("%s: PartitionTableIndex(%i), Start("PFU64"), Size("PFU64")\n", - __FUNCTION__, i, START_SECT(p), NR_SECTS(p)); - - if (NR_SECTS(p)) { - - if (is_extended_partition(p)) - rc = mbr_ebr_process_extended_partition(discover_list, - node, p); - - else { - partition_name = NULL; - if (os2lvm && p->sys_ind != LVM_PARTITION_INDICATOR && - le32_to_cpu(dlat->DLA_Array[i].Partition_Start) == - START_SECT(p) - && le32_to_cpu(dlat->DLA_Array[i].Partition_Size) == - NR_SECTS(p) - && dlat->DLA_Array[i].Drive_Letter != '\0') { - sprintf(tmp_buf, "os2/%c", - dlat->DLA_Array[i].Drive_Letter); - partition_name = tmp_buf; - } - print_partition_info(__FUNCTION__, p); - - rc = mbr_ebr_process_segment(discover_list, - node, - START_SECT(p), - NR_SECTS(p), - p->sys_ind, - i + 1, partition_name); - } - } - return (rc); -} - -static int -mbr_ebr_process_mbr(struct evms_logical_node **discover_list, - struct evms_logical_node *node, struct mbr_ebr *mbr) -{ - int rc = 0, i, os2lvm; - struct partition *p; - struct dla_table_sector *dlat = NULL; - - cur_comp_part_num = 5; /* set this value for each disk */ - - /* allocate space for the OS2 DLAT info */ - dlat = kmalloc(node->hardsector_size, GFP_KERNEL); - if (dlat) { - /* read the dlat for this mbr */ - os2lvm = os2lvm_partition(0, node, dlat); - - /* Pass 1: walk thru the partition table in the mbr - * processing each partition record. - */ - for (i = 0; i < 4; i++) { - p = &mbr->partitions[i]; - if (is_non_dos_extended(discover_list, node, p)) { - LOG_DETAILS - (" Found and skip a non-dos extended partition.\n"); - continue; - } - - mbr_ebr_process_dos_primary_partition(discover_list, - node, - i, - p, os2lvm, dlat); - } - - /* Pass 2: walk thru the partition table in the mbr - * processing each partition record for non-DOS extended partitions - */ - for (i = 0; i < 4; i++) { - p = &mbr->partitions[i]; - mbr_ebr_process_other_primary_partition(discover_list, - node, p); - } - - } else { - rc = -ENOMEM; - } - - /* free the space used for OS2 DLAT info */ - if (dlat) - kfree(dlat); - - return (rc); -} - -static int -mbr_ebr_probe_for_mbr(struct evms_logical_node **discover_list, - struct evms_logical_node *node) -{ - int rc = 0; - u_char *sector_buffer = NULL; - struct mbr_ebr *mbr = NULL; - - LOG_DEBUG("%s: probing (%s).\n", __FUNCTION__, node->name); - - /* allocate a sector size buffer */ - sector_buffer = kmalloc(node->hardsector_size, GFP_KERNEL); - if (sector_buffer) - /* read the location of the mbr sector */ - rc = INIT_IO(node, 0, 0, 1, sector_buffer); - else - rc = -ENOMEM; - if (rc) { - LOG_ERROR("%s: read error(%d) on '%s'.\n", - __FUNCTION__, rc, node->name); - } else { - mbr = (struct mbr_ebr *) sector_buffer; - if (validate_mbr_ebr(node, mbr, 0, 0) == TRUE) { - /* since it looks like this disk has a - * valid MBR, remove the disk node from - * the discover list. it may already be - * on the global list, or it will be - * added to it. in the case of an mbr - * with no partitions, it is simply - * removed and forgotten. when one or - * more partitions are created, the - * disk will be examined and handled - * properly during the following - * rediscover operation. - */ - evms_cs_remove_logical_node_from_list(discover_list, - node); - - rc = mbr_ebr_process_mbr(discover_list, node, mbr); - } - } - - if (sector_buffer) - kfree(sector_buffer); - - return (rc); -} - -/* - * Function: mbr_ebr_partition_discover - * - */ -static int -mbr_ebr_partition_discover(struct evms_logical_node **discover_list) -{ - int rc = 0; - struct evms_logical_node *node, *next_node; - - MOD_INC_USE_COUNT; - LOG_ENTRY_EXIT("%s: ENTRY\n", __FUNCTION__); - - /* initialize global variable */ - exported_nodes = 0; - - /* examine each node on the discover list */ - next_node = *discover_list; - while (next_node) { - node = next_node; - next_node = node->next; - if (node->plugin->id == plugin_header.id) - /* don't recurse into our own objects - */ - continue; - mbr_ebr_probe_for_mbr(discover_list, node); - } - - LOG_ENTRY_EXIT("%s: EXIT(exported nodes:%d, error code:%d)\n", - __FUNCTION__, exported_nodes, rc); - if (exported_nodes) - rc = exported_nodes; - MOD_DEC_USE_COUNT; - return (rc); -} - -/* - * Function: mbr_ebr_partition_delete - * - */ -static int -mbr_ebr_partition_delete(struct evms_logical_node *segment) -{ - int rc = 0; - struct dos_private *dos_prv; - struct evms_logical_node *empty_disk = NULL; - - LOG_DETAILS("deleting segment '%s'.\n", segment->name); - - if (!segment) { - rc = -ENODEV; - } else { - dos_prv = segment->private; - if (dos_prv) { - /* remove the segment from the - * disk's segment list - */ - rc = remove_segment_from_disk(dos_prv->source_disk, - segment, &empty_disk); - /* free the local instance data */ - kfree(dos_prv); - } - /* free the segment node */ - evms_cs_deallocate_logical_node(segment); - MOD_DEC_USE_COUNT; - /* if the last segment on the disk was - * deleted, delete the disk node too - */ - if (empty_disk) - DELETE(empty_disk); - } - return (rc); -} - -/* - * function: mbr_ebr_partition_io_error - * - * this function was primarily created because the function - * buffer_IO_error is inline and kgdb doesn't allow breakpoints - * to be set on inline functions. Since this was an error path - * and not mainline, I decided to add a trace statement to help - * report on the failing condition. - * - */ -static void -mbr_ebr_partition_io_error(struct evms_logical_node *node, - int io_flag, struct buffer_head *bh) -{ - LOG_SERIOUS - ("attempt to %s beyond partition boundary("PFU64") on (%s), rsector("PFU64").\n", - (io_flag) ? "WRITE" : "READ", node->total_vsectors - 1, node->name, - (u64) bh->b_rsector); - - bh->b_end_io(bh, 0); -} - -/* - * Function: mbr_ebr_partition_read - * - */ -static void -mbr_ebr_partition_read(struct evms_logical_node *partition, - struct buffer_head *bh) -{ - struct dos_private *dos_prv = partition->private; - - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) <= - partition->total_vsectors) { - bh->b_rsector += dos_prv->start_sect; - R_IO(dos_prv->source_disk, bh); - } else - mbr_ebr_partition_io_error(partition, READ, bh); -} - -/* - * Function: mbr_ebr_partition_write - * - */ -static void -mbr_ebr_partition_write(struct evms_logical_node *partition, - struct buffer_head *bh) -{ - struct dos_private *dos_prv = partition->private; - - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) <= - partition->total_vsectors) { - bh->b_rsector += dos_prv->start_sect; - W_IO(dos_prv->source_disk, bh); - } else - mbr_ebr_partition_io_error(partition, WRITE, bh); -} - -/* - * Function: mbr_ebr_partition_init_io - * - */ -static int -mbr_ebr_partition_init_io(struct evms_logical_node *partition, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr) -{ /* buffer address */ - int rc; - struct dos_private *dos_prv = partition->private; - - if ((sect_nr + num_sects) <= partition->total_vsectors) { - rc = INIT_IO(dos_prv->source_disk, io_flag, - sect_nr + dos_prv->start_sect, num_sects, - buf_addr); - } else { - LOG_SERIOUS - ("init_io: attempt to %s beyond partition(%s) boundary("PFU64") at sector("PFU64") for count("PFU64").\n", - (io_flag) ? "WRITE" : "READ", partition->name, - (dos_prv->nr_sects - 1), sect_nr, num_sects); - rc = -EINVAL; - } - - return (rc); -} - -/* - * Function: mbr_ebr_partition_ioctl - * - */ -static int -mbr_ebr_partition_ioctl(struct evms_logical_node *partition, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - struct dos_private *dos_prv; - struct hd_geometry hd_geo; - int rc; - - rc = 0; - dos_prv = partition->private; - if (!inode) - return -EINVAL; - switch (cmd) { - case HDIO_GETGEO: - { - rc = IOCTL(dos_prv->source_disk, inode, file, cmd, arg); - if (rc) - break; - if (copy_from_user - (&hd_geo, (void *) arg, - sizeof (struct hd_geometry))) - rc = -EFAULT; - if (rc) - break; - hd_geo.start = dos_prv->start_sect; - if (copy_to_user - ((void *) arg, &hd_geo, - sizeof (struct hd_geometry))) - rc = -EFAULT; - } - break; - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = - (struct evms_get_bmap_pkt *) arg; - bmap->rsector += dos_prv->start_sect; - /* intentionally fall thru to - * default ioctl down to device - * manager. - */ - } - default: - rc = IOCTL(dos_prv->source_disk, inode, file, cmd, arg); - } - return rc; -} - -/* - * Function: dos_part_init - * - */ -static int __init -dos_part_init(void) -{ - return evms_cs_register_plugin(&plugin_header); /* register with EVMS */ -} - -static void __exit -dos_part_exit(void) -{ - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(dos_part_init); -module_exit(dos_part_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,5736 +0,0 @@ -/* -*- linux-c -*- */ -/* - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ -/* - * - * linux/drivers/evms/evms.c - * - * EVMS Base and Common Services - * - */ - -//#define LOCAL_DEBUG 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VFS_PATCH_PRESENT - -/* prefix used in logging messages */ -#define LOG_PREFIX - -struct evms_registered_plugin { - struct evms_plugin_header *plugin; - struct evms_registered_plugin *next; -}; -static struct evms_registered_plugin *registered_plugin_head = NULL; - -static struct evms_list_node *evms_global_device_list = NULL; -static struct evms_list_node *evms_global_feature_node_list = NULL; -static struct evms_list_node *evms_global_notify_list = NULL; - -int evms_info_level = EVMS_INFO_LEVEL; -struct proc_dir_entry *evms_proc_dir = NULL; -EXPORT_SYMBOL(evms_info_level); -static struct evms_logical_volume *evms_logical_volumes; -static int evms_volumes = 0; -/* a few variables to aid in detecting memory leaks. - * these variables are always in use, regardless of - * the state of EVMS_MEM_DEBUG. - */ -static atomic_t evms_allocs = (atomic_t) ATOMIC_INIT(0); -static atomic_t evms_logical_nodes = (atomic_t) ATOMIC_INIT(0); - -u8 *evms_primary_string = "primary"; -EXPORT_SYMBOL(evms_primary_string); -u8 *evms_secondary_string = "secondary"; -EXPORT_SYMBOL(evms_secondary_string); - -static struct evms_version evms_svc_version = { - .major = EVMS_COMMON_SERVICES_MAJOR, - .minor = EVMS_COMMON_SERVICES_MINOR, - .patchlevel = EVMS_COMMON_SERVICES_PATCHLEVEL -}; - -/* Handles for "private" EVMS object pools */ -static struct evms_pool_mgmt *evms_io_notify_pool; - -/* Handles for "public" EVMS object pools */ -struct evms_pool_mgmt *evms_bh_pool; -EXPORT_SYMBOL(evms_bh_pool); - -/* Handle for the devfs directory entry */ -devfs_handle_t evms_dir_devfs_handle; -devfs_handle_t evms_blk_devfs_handle; - -/**********************************************************/ -/* SYSCTL - EVMS folder */ -/**********************************************************/ - -#ifdef CONFIG_PROC_FS -static struct ctl_table_header *evms_table_header; -static int evms_info_level_min = EVMS_INFO_CRITICAL; -static int evms_info_level_max = EVMS_INFO_EVERYTHING; - -static ctl_table evms_table[] = { - {DEV_EVMS_INFO_LEVEL, "evms_info_level", - &evms_info_level, sizeof (int), 0644, NULL, - &proc_dointvec_minmax, &sysctl_intvec, - NULL, &evms_info_level_min, &evms_info_level_max}, - {0} -}; - -static ctl_table evms_dir_table[] = { - {DEV_EVMS, "evms", NULL, 0, 0555, evms_table}, - {0} -}; - -static ctl_table dev_dir_table[] = { - {CTL_DEV, "dev", NULL, 0, 0555, evms_dir_table}, - {0} -}; -#endif - -/**********************************************************/ -/* START -- arch ioctl32 support */ -/**********************************************************/ -#if defined(CONFIG_PPC64) || defined(CONFIG_SPARC64) || defined(CONFIG_X86_64) -#include -#include - -extern asmlinkage long -sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); - -extern int -register_ioctl32_conversion(unsigned int cmd, void *handler); - -extern int -unregister_ioctl32_conversion(unsigned int cmd); - -#define uvirt_to_kernel(__x) ((unsigned long)(__x)) -typedef unsigned int __uvirt_addr; - -struct evms_sector_io32 { - u64 disk_handle; - u64 starting_sector; - u64 sector_count; - s32 io_flag; - s32 status; - __uvirt_addr buffer_address; -}; - -struct evms_rediscover32 { - s32 status; - u32 drive_count; - __uvirt_addr drive_array; -}; - -struct evms_compute_csum32 { - __uvirt_addr buffer_address; - s32 buffer_size; - u32 insum; - u32 outsum; - s32 status; -}; - -struct evms_plugin_ioctl32 { - u32 feature_id; - s32 feature_command; - s32 status; - u32 data_size; - __uvirt_addr feature_ioctl_data; -}; - -struct evms_notify_bbr32 { - char object_name[EVMS_VOLUME_NAME_SIZE+1]; - u64 count; - u64 start_sect; - u64 nr_sect; - __uvirt_addr buffer; - s32 rw; -}; - -#define EVMS_MD_ID 4 -#define EVMS_MD_PERS_IOCTL_CMD 1 -#define EVMS_MD_ADD 2 -#define EVMS_MD_REMOVE 3 -#define EVMS_MD_ACTIVATE 4 -#define EVMS_MD_DEACTIVATE 5 -#define EVMS_MD_GET_ARRAY_INFO 6 -#define EVMS_MD_RAID5_INIT_IO 1 - -struct evms_md_ioctl { - int mddev_idx; - int cmd; - void *arg; -}; - -struct evms_md_ioctl32 { - u32 mddev_idx; - u32 cmd; - __uvirt_addr arg; -}; - -struct evms_md_array_info { - unsigned long state; - mdp_super_t *sb; -}; - -struct evms_md_array_info32 { - u32 state; - __uvirt_addr sb; -}; - -struct raid5_ioctl_init_io { - int rw; - u64 lsn; - u64 nr_sects; - void *data; -}; - -struct raid5_ioctl_init_io32 { - s32 rw; - u64 lsn; - u64 nr_sects; - __uvirt_addr data; -}; - -#define EVMS_MD_PLUGIN_ID ((IBM_OEM_ID << 16) | \ - (EVMS_REGION_MANAGER << 12) | EVMS_MD_ID) -#define EVMS_BBR_PLUGIN_ID ((IBM_OEM_ID << 16) | \ - (EVMS_FEATURE << 12) | EVMS_BBR_FEATURE_ID) - -#define EVMS_SECTOR_IO_32 _IOWR(EVMS_MAJOR, \ - EVMS_SECTOR_IO_NUMBER, \ - struct evms_sector_io32) -#define EVMS_REDISCOVER_VOLUMES_32 _IOWR(EVMS_MAJOR, \ - EVMS_REDISCOVER_VOLUMES_NUMBER, \ - struct evms_rediscover32) -#define EVMS_COMPUTE_CSUM_32 _IOWR(EVMS_MAJOR, \ - EVMS_COMPUTE_CSUM_NUMBER, \ - struct evms_compute_csum32) -#define EVMS_PLUGIN_IOCTL_32 _IOR(EVMS_MAJOR, \ - EVMS_PLUGIN_IOCTL_NUMBER, \ - struct evms_plugin_ioctl32) - -static int evms_sector_io(unsigned int fd, - unsigned int cmd, - unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct evms_sector_io32 parms32; - struct evms_sector_io_pkt parms; - unsigned int kcmd; - void *karg; - int rc = 0; - - if (copy_from_user(&parms32, (struct evms_sector_io32 *)arg, - sizeof(struct evms_sector_io32))) - return -EFAULT; - - parms.disk_handle = parms32.disk_handle; - parms.io_flag = parms32.io_flag; - parms.starting_sector = parms32.starting_sector; - parms.sector_count = parms32.sector_count; - parms.buffer_address = (u8 *)uvirt_to_kernel(parms32.buffer_address); - parms.status = 0; - - kcmd = EVMS_SECTOR_IO; - karg = &parms; - - set_fs(KERNEL_DS); - rc = sys_ioctl(fd, kcmd, (unsigned long)karg); - set_fs(old_fs); - - parms32.status = parms.status; - - if (copy_to_user((struct evms_sector_io32 *)arg, &parms32, - sizeof(struct evms_sector_io32))) - return -EFAULT; - - return rc; -} - -static int evms_rediscover(unsigned int fd, - unsigned int cmd, - unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct evms_rediscover32 parms32; - struct evms_rediscover_pkt parms; - unsigned int kcmd; - void *karg; - int rc = 0; - - if (copy_from_user(&parms32, (struct evms_rediscover32 *)arg, - sizeof(struct evms_rediscover32))) - return -EFAULT; - - parms.drive_count = parms32.drive_count; - parms.drive_array = (void *)uvirt_to_kernel(parms32.drive_array); - parms.status = 0; - - kcmd = EVMS_REDISCOVER_VOLUMES; - karg = &parms; - - set_fs(KERNEL_DS); - rc = sys_ioctl(fd, kcmd, (unsigned long)karg); - set_fs(old_fs); - - parms32.status = parms.status; - - if (copy_to_user((struct evms_rediscover32 *)arg, &parms32, - sizeof(struct evms_rediscover32))) - return -EFAULT; - - return rc; -} - -static int evms_compute_csum(unsigned int fd, - unsigned int cmd, - unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct evms_compute_csum32 parms32; - struct evms_compute_csum_pkt parms; - unsigned int kcmd; - void *karg; - int rc = 0; - - if (copy_from_user(&parms32, (struct evms_compute_csum32 *)arg, - sizeof(struct evms_compute_csum32))) - return -EFAULT; - - parms.insum = parms32.insum; - parms.outsum = parms32.outsum; - parms.buffer_size = parms32.buffer_size; - parms.buffer_address = (void *)uvirt_to_kernel(parms32.buffer_address); - parms.status = 0; - - kcmd = EVMS_COMPUTE_CSUM; - karg = &parms; - - set_fs(KERNEL_DS); - rc = sys_ioctl(fd, kcmd, (unsigned long)karg); - set_fs(old_fs); - - parms32.status = parms.status; - parms32.outsum = parms.outsum; - - if (copy_to_user((struct evms_compute_csum32 *)arg, &parms32, - sizeof(struct evms_compute_csum32))) - return -EFAULT; - - return rc; -} - -static int evms_bbr_plugin_ioctl(unsigned int fd, - unsigned int cmd, - unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct evms_notify_bbr32 bbr_parms32; - struct evms_notify_bbr bbr_parms; - struct evms_plugin_ioctl_pkt *parms = - (struct evms_plugin_ioctl_pkt *)arg; - void *old_ptr = NULL; - int rc; - - if (copy_from_user(&bbr_parms32, - (struct evms_notify_bbr32 *)parms->feature_ioctl_data, - sizeof(struct evms_notify_bbr32))) - return -EFAULT; - - memcpy(&bbr_parms, &bbr_parms32, sizeof(struct evms_notify_bbr32)); - bbr_parms.buffer = (void *)uvirt_to_kernel(bbr_parms32.buffer); - bbr_parms.rw = bbr_parms32.rw; - old_ptr = parms->feature_ioctl_data; - parms->feature_ioctl_data = &bbr_parms; - - set_fs(KERNEL_DS); - rc = sys_ioctl(fd, cmd, arg); - set_fs(old_fs); - - parms->feature_ioctl_data = old_ptr; - - if (!rc) { - bbr_parms32.nr_sect = bbr_parms.nr_sect; - rc = copy_to_user((struct evms_notify_bbr32 *)parms->feature_ioctl_data, - &bbr_parms32, - sizeof(struct evms_notify_bbr32)); - } - - return rc; -} - -static int evms_md_plugin_ioctl(unsigned int fd, - unsigned int cmd, - unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - void *old_ptr = NULL; - void *old_md_ptr = NULL; - struct evms_md_ioctl32 md_parms32; - struct evms_md_ioctl md_parms; - struct evms_md_array_info32 md_array_parms32; - struct evms_md_array_info md_array_parms; - struct raid5_ioctl_init_io32 r5_init_io_parms32; - struct raid5_ioctl_init_io r5_init_io_parms; - struct evms_plugin_ioctl_pkt *parms = - (struct evms_plugin_ioctl_pkt *)arg; - int rc; - - if (copy_from_user(&md_parms32, - (struct evms_md_ioctl*)parms->feature_ioctl_data, - sizeof(struct evms_md_ioctl32))) - return -EFAULT; - - md_parms.mddev_idx = md_parms32.mddev_idx; - md_parms.cmd = md_parms32.cmd; - md_parms.arg = (void *)uvirt_to_kernel(md_parms32.arg); - old_ptr = parms->feature_ioctl_data; - parms->feature_ioctl_data = &md_parms; - - if (parms->feature_command == EVMS_MD_GET_ARRAY_INFO) { - if (copy_from_user(&md_array_parms32, - (struct evms_md_array_info32*)md_parms.arg, - sizeof(struct evms_md_array_info32))) - return -EFAULT; - - md_array_parms.state = md_array_parms32.state; - md_array_parms.sb = - (void *)uvirt_to_kernel(md_array_parms32.sb); - old_md_ptr = (void *)md_parms.arg; - md_parms.arg = &md_array_parms; - } else if (parms->feature_command == EVMS_MD_PERS_IOCTL_CMD) { - if (md_parms.cmd == EVMS_MD_RAID5_INIT_IO) { - if (copy_from_user(&r5_init_io_parms32, - (struct raid5_ioctl_init_io32*)md_parms.arg, - sizeof(struct raid5_ioctl_init_io32))) - return -EFAULT; - - r5_init_io_parms.rw = r5_init_io_parms32.rw; - r5_init_io_parms.lsn = r5_init_io_parms32.lsn; - r5_init_io_parms.nr_sects = r5_init_io_parms32.nr_sects; - r5_init_io_parms.data = - (void *)uvirt_to_kernel(r5_init_io_parms32.data); - old_md_ptr = (void *)md_parms.arg; - md_parms.arg = &r5_init_io_parms; - } - } - - set_fs(KERNEL_DS); - rc = sys_ioctl(fd, cmd, arg); - set_fs(old_fs); - - parms->feature_ioctl_data = old_ptr; - md_parms.arg = old_md_ptr; - - if (!rc) { - if (parms->feature_command == EVMS_MD_GET_ARRAY_INFO) { - md_array_parms32.state = md_array_parms.state; - rc = copy_to_user((struct evms_md_array_info32 *)md_parms.arg, - &md_array_parms32, - sizeof(struct evms_md_array_info32)); - } - if (!rc) { - md_parms32.mddev_idx = md_parms.mddev_idx; - rc = copy_to_user((struct evms_md_ioctl*)parms->feature_ioctl_data, - &md_parms32, - sizeof(struct evms_md_ioctl32)); - } - } - - return rc; -} - -static int evms_plugin_ioctl(unsigned int fd, - unsigned int cmd, - unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct evms_plugin_ioctl32 parms32; - struct evms_plugin_ioctl_pkt parms; - unsigned int kcmd; - void *karg; - int rc; - - if (copy_from_user(&parms32, (struct evms_plugin_ioctl32 *)arg, - sizeof(struct evms_plugin_ioctl32))) - return -EFAULT; - - parms.feature_id = parms32.feature_id; - parms.feature_command = parms32.feature_command; - parms.status = parms32.status; - parms.feature_ioctl_data = - (void *)uvirt_to_kernel(parms32.feature_ioctl_data); - - kcmd = EVMS_PLUGIN_IOCTL; - karg = &parms; - - switch (parms.feature_id) { - case EVMS_MD_PLUGIN_ID: - rc = evms_md_plugin_ioctl(fd, kcmd, (unsigned long)karg); - break; - case EVMS_BBR_PLUGIN_ID: - rc = evms_bbr_plugin_ioctl(fd, kcmd, (unsigned long)karg); - break; - default: - set_fs(KERNEL_DS); - rc = sys_ioctl(fd, kcmd, (unsigned long)karg); - set_fs(old_fs); - } - - if (!rc) { - parms32.status = parms.status; - rc = copy_to_user((struct evms_plugin_ioctl32 *)arg, &parms32, - sizeof(struct evms_plugin_ioctl32)); - } - - return rc; -} -#endif - -/**********************************************************/ -/* START -- exported functions/Common Services */ -/**********************************************************/ - -int -evms_cs_check_version(struct evms_version *required, - struct evms_version *actual) -{ - if (required->major != actual->major) - return -EINVAL; - else if (required->minor > actual->minor) - return -EINVAL; - else if (required->minor == actual->minor) - if (required->patchlevel > actual->patchlevel) - return -EINVAL; - return 0; -} - -EXPORT_SYMBOL(evms_cs_check_version); - -int -evms_cs_allocate_logical_node(struct evms_logical_node **pp) -{ - *pp = kmalloc(sizeof (struct evms_logical_node), GFP_KERNEL); - if (*pp) { - memset(*pp, 0, sizeof (struct evms_logical_node)); - atomic_inc(&evms_logical_nodes); - return 0; - } - return -ENOMEM; -} - -EXPORT_SYMBOL(evms_cs_allocate_logical_node); - -void -evms_cs_deallocate_volume_info(struct evms_logical_node *p) -{ - if (p->iflags & EVMS_FEATURE_BOTTOM) { - evms_cs_remove_item_from_list(&evms_global_feature_node_list,p); - kfree(p->volume_info); - p->volume_info = NULL; - p->iflags &= ~EVMS_FEATURE_BOTTOM; - } -} - -EXPORT_SYMBOL(evms_cs_deallocate_volume_info); - -void -evms_cs_deallocate_logical_node(struct evms_logical_node *p) -{ - if (p->next) { - LOG_SERIOUS("Deallocating object whose NEXT ptr is not null!!\n"); - } - evms_cs_deallocate_volume_info(p); - if (p->feature_header) { - kfree(p->feature_header); - p->feature_header = NULL; - } - kfree(p); - atomic_dec(&evms_logical_nodes); -} - -EXPORT_SYMBOL(evms_cs_deallocate_logical_node); - -/* - * Function: evms_cs_register_plugin - * Description: This function is exported so that all plugins can register with EVMS - */ -int -evms_cs_register_plugin(struct evms_plugin_header *plugin) -{ - int rc = 0; - struct evms_registered_plugin *reg_record, **pp; - struct evms_version *ver; - - ver = &plugin->required_services_version; - - LOG_EXTRA("registering plugin (plugin.id=%d.%d.%d, " - "plugin.ver=%d.%d.%d, req.svc.ver=%d.%d.%d)\n", - GetPluginOEM(plugin->id), GetPluginType(plugin->id), - GetPluginID(plugin->id), plugin->version.major, - plugin->version.minor, plugin->version.patchlevel, - ver->major, ver->minor, ver->patchlevel); - - /* check common services requirements */ - rc = evms_cs_check_version(ver, &evms_svc_version); - if (rc) { - LOG_SERIOUS("plugin failed to load: common services " - "(vers:%d,%d,%d) incompatibility!\n", - EVMS_COMMON_SERVICES_MAJOR, - EVMS_COMMON_SERVICES_MINOR, - EVMS_COMMON_SERVICES_PATCHLEVEL); - } - if (!rc) { - /* ensure a plugin with this feature id is - * not already loaded. - */ - for (pp = ®istered_plugin_head; *pp; pp = &(*pp)->next) { - if ((*pp)->plugin->id == plugin->id) { - rc = -EBUSY; - LOG_ERROR("error(%d) attempting to load another " - "plugin with id(%x).\n", rc, plugin->id); - } - } - } - if (!rc) { - /* ensure the plugin has provided functions for - * the mandatory entry points. - */ - if (!plugin->fops->discover) { - rc = -EINVAL; - } else if (!plugin->fops->init_io) { - rc = -EINVAL; - } else if (!plugin->fops->ioctl) { - rc = -EINVAL; - } else if (!plugin->fops->read) { - rc = -EINVAL; - } else if (!plugin->fops->write) { - rc = -EINVAL; - } else if (!plugin->fops->delete) { - rc = -EINVAL; - } - } - if (!rc) { - /* allocate a new plugin registration record */ - reg_record = - kmalloc(sizeof (struct evms_registered_plugin), GFP_KERNEL); - if (!reg_record) { - rc = -ENOMEM; - } - } - if (!rc) { - memset(reg_record, 0, sizeof (struct evms_registered_plugin)); - /* store ptr to plugin header in new registration record */ - reg_record->plugin = plugin; - - /* terminate the record */ - reg_record->next = NULL; - - /* find end of the plugin registration list */ - for (pp = ®istered_plugin_head; *pp; pp = &(*pp)->next) ; - /* add registration record to list */ - *pp = reg_record; - - /* increment the usage count */ - MOD_INC_USE_COUNT; - } - - return rc; -} - -EXPORT_SYMBOL(evms_cs_register_plugin); - -/* - * Function: evms_cs_unregister_plugin - * Description: This function is exported so that all plugins can - * unregister with EVMS - */ -int -evms_cs_unregister_plugin(struct evms_plugin_header *plugin) -{ - int rc = 0, found = FALSE; - struct evms_registered_plugin **pp; - struct evms_version *ver; - - ver = &plugin->required_services_version; - - LOG_EXTRA("unregistering plugin (plugin.id=%d.%d.%d, " - "plugin.ver=%d.%d.%d, req.svc.ver=%d.%d.%d)\n", - GetPluginOEM(plugin->id), GetPluginType(plugin->id), - GetPluginID(plugin->id), plugin->version.major, - plugin->version.minor, plugin->version.patchlevel, - ver->major, ver->minor, ver->patchlevel); - /* ensure a plugin with this feature id is - * currently loaded. - */ - for (pp = ®istered_plugin_head; *pp; pp = &(*pp)->next) { - if ((*pp)->plugin->id == plugin->id) { - found = TRUE; - break; - } - } - if (!found) { - rc = -ENOPKG; - LOG_ERROR("error(%d) attempt to unload a non-loaded plugin " - "with id(%x).\n", rc, plugin->id); - } - /* actually unload the plugin now */ - if (!rc) { - struct evms_registered_plugin *tmp = *pp; - - /* remove the plugin record from our - * internal plugin list - */ - *pp = (*pp)->next; - /* deallocate the plugin registration record - */ - kfree(tmp); - - /* decrement the usage count */ - MOD_DEC_USE_COUNT; - } - return rc; -} - -EXPORT_SYMBOL(evms_cs_unregister_plugin); - -/* function: evms_cs_add_logical_node_to_list - * - * This functions adds a new logical node to the end of a - * node list. - * - * NOTE: This function is only expected to be called at - * discovery time, which is singled threaded by nature, - * and therefore doesn't need to be made SMP safe. - */ -int -evms_cs_add_logical_node_to_list(struct evms_logical_node **list_head, - struct evms_logical_node *node) -{ - int rc = 0; - struct evms_logical_node **pp = NULL; - - /* check to make sure node is not already on a list */ - if (node->next) - rc = 1; - else - /* check to make sure node being added is not already in the list */ - for (pp = list_head; *pp; pp = &(*pp)->next) - if (*pp == node) { - rc = 2; - break; - } - - /* add node to the end of the list */ - if (!rc) - *pp = node; - - return rc; -} - -EXPORT_SYMBOL(evms_cs_add_logical_node_to_list); - -/* function: evms_cs_remove_logical_node_from_list - * - * This functions removes a new logical node from a node list. - * - * NOTE: This function is only expected to be called at - * discovery time, which is singled threaded by nature, - * and therefore doesn't need to be made SMP safe. - */ -int -evms_cs_remove_logical_node_from_list(struct evms_logical_node **list_head, - struct evms_logical_node *node) -{ - /* remove this node from the head of the list */ - int rc = 1; /* assume failure until target node is found */ - struct evms_logical_node **pp; - for (pp = list_head; *pp; pp = &(*pp)->next) - if (*pp == node) { - *pp = (*pp)->next; - node->next = NULL; - rc = 0; - break; - } - return rc; -} - -EXPORT_SYMBOL(evms_cs_remove_logical_node_from_list); - -int -evms_cs_kernel_ioctl(struct evms_logical_node *node, unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - struct inode tmp_inode; - mm_segment_t fs; - - lock_kernel(); - fs = get_fs(); - set_fs(get_ds()); - rc = IOCTL(node, &tmp_inode, NULL, cmd, arg); - set_fs(fs); - unlock_kernel(); - - return rc; - -} - -EXPORT_SYMBOL(evms_cs_kernel_ioctl); - -/* - * function: evms_cs_size_in_vsectors - * - * In EVMS a V(irtual)Sector is 512 bytes in size. - * This function computes the number of VSECTORs an specified - * item size would require. - * - * NOTE: This function has been coded to work with 64 bit values. - */ -unsigned long -evms_cs_size_in_vsectors(long long item_size) -{ - long long sectors; - - sectors = item_size >> EVMS_VSECTOR_SIZE_SHIFT; - if (item_size & (EVMS_VSECTOR_SIZE - 1)) - sectors++; - - return sectors; -} - -EXPORT_SYMBOL(evms_cs_size_in_vsectors); - -/* - * function: evms_cs_log2 - * - * this function computes the power of the 2 of specified - * value. If the value is 0, a -1 is returned. If the value - * is NOT a power of 2, a -2 is return. Otherwise the power - * of 2 is returned. - */ -int -evms_cs_log2(long long value) -{ - int result = -1; - long long tmp; - - if (value) { - tmp = value; - result++; - while (!(tmp & 1)) { - result++; - tmp >>= 1; - } - if (tmp != 1) { - result = -2; - } - } - return result; -} - -EXPORT_SYMBOL(evms_cs_log2); - -/* - * Functions: - * - * build_crc_table() - * calculate_crc() - * - * - * Description: The functions in this module provide a means of calculating - * the 32 bit CRC for a block of data. build_crc_table must - * be called to initialize this module. calculate_crc must - * NOT be used until after build_crc_table has been called. - * Once build_crc_table has been called, calculate_crc can - * be used to calculate the crc of the data residing in a - * user specified buffer. - * - */ - -#define CRC_POLYNOMIAL 0xEDB88320L - -static u32 crc_table[256]; -static u32 crc_table_built = FALSE; - -/** - * Function Name: build_crc_table - * - * Description: This module implements the crc function using - * a table driven method. The required table - * must be setup before the calculate_crc - * function can be used. This table only needs - * to be set up once. This function sets up the - * crc table needed by calculate_crc. - **/ -static void -build_crc_table(void) -{ - u32 i, j, crc; - - for (i = 0; i <= 255; i++) { - crc = i; - for (j = 8; j > 0; j--) { - if (crc & 1) - crc = (crc >> 1) ^ CRC_POLYNOMIAL; - else - crc >>= 1; - } - crc_table[i] = crc; - } - crc_table_built = TRUE; -} - -/** - * Function Name: calculate_crc - * - * Description: This function calculates the crc value for - * the data in the buffer specified by Buffer. - * - * Input: u32 crc : This is the starting crc. If you are - * starting a new crc calculation, then - * this should be set to 0xFFFFFFFF. If - * you are continuing a crc calculation - * (i.e. all of the data did not fit in - * the buffer so you could not calculate - * the crc in a single operation), then - * this is the crc output by the last - * calculate_crc call. - * - * Output: The crc for the data in the buffer, based upon the value - * of the input parameter crc. - **/ -u32 -evms_cs_calculate_crc(u32 crc, void *buffer, u32 buffersize) -{ - unsigned char *current_byte; - u32 temp1, temp2, i; - - current_byte = (unsigned char *) buffer; - /* Make sure the crc table is available */ - if (crc_table_built == FALSE) - build_crc_table(); - /* Process each byte in the buffer. */ - for (i = 0; i < buffersize; i++) { - temp1 = (crc >> 8) & 0x00FFFFFF; - temp2 = - crc_table[(crc ^ (u32) * - current_byte) & (u32) 0xff]; - current_byte++; - crc = temp1 ^ temp2; - } - return crc; -} - -EXPORT_SYMBOL(evms_cs_calculate_crc); - -#define EVMS_ORIGINAL_CALLBACK_FLAG 1<<0 -typedef struct io_notify_s { - unsigned int flags; - void *private; - struct buffer_head *bh; - u64 rsector; - kdev_t rdev; - void *b_private; - void (*callback_function) (struct evms_logical_node * node, - struct buffer_head * bh, - int uptodate, int *redrive); - struct io_notify_s *next; -} io_notify_t; - -struct evms_pool_mgmt * -evms_cs_create_pool(int objsize, - u8 * pool_name, - void (*ctor) (void *, kmem_cache_t *, unsigned long), - void (*dtor) (void *, kmem_cache_t *, unsigned long)) -{ - struct evms_pool_mgmt *pool; - - /* create the pool management structure */ - pool = kmalloc(sizeof (struct evms_pool_mgmt), GFP_KERNEL); - if (!pool) { - LOG_CRITICAL("Cannot create %s pool mgmt structure", - pool_name); - return NULL; - } - /* initialize various field in pool mgmt structure */ - memset(pool, 0, sizeof (struct evms_pool_mgmt)); - pool->member_size = objsize; - pool->name = pool_name; - atomic_set(&pool->waiters, 0); - init_waitqueue_head(&pool->wait_queue); - /* go create the pool */ - pool->cachep = kmem_cache_create(pool->name, - pool->member_size, - 0, SLAB_HWCACHE_ALIGN, ctor, dtor); - if (!pool->cachep) { - LOG_CRITICAL("Cannot create %s SLAB cache", pool->name); - kfree(pool); - pool = NULL; - } - return pool; -} - -EXPORT_SYMBOL(evms_cs_create_pool); - -void * -evms_cs_allocate_from_pool(struct evms_pool_mgmt *pool, int blockable) -{ - void *objp; - - while (1) { - objp = kmem_cache_alloc(pool->cachep, SLAB_NOIO); - if (objp || !blockable) { - return objp; - } else { - /* block and wait for an object to - * be returned to the pool - */ - atomic_inc(&pool->waiters); - wait_event(pool->wait_queue, - (!atomic_read(&pool->waiters))); - } - } - return objp; -} - -EXPORT_SYMBOL(evms_cs_allocate_from_pool); - -void -evms_cs_deallocate_to_pool(struct evms_pool_mgmt *pool, void *objp) -{ - kmem_cache_free(pool->cachep, objp); - atomic_set(&pool->waiters, 0); - if (waitqueue_active(&pool->wait_queue)) { - wake_up(&pool->wait_queue); - } -} - -EXPORT_SYMBOL(evms_cs_deallocate_to_pool); - -void -evms_cs_destroy_pool(struct evms_pool_mgmt *pool) -{ - kmem_cache_destroy(pool->cachep); - kfree(pool); -} - -EXPORT_SYMBOL(evms_cs_destroy_pool); - -/* - * function: evms_end_io - * - * This is a support function for - * evms_cs_register_for_end_io_notification. - * This function is called during I/O completion on any buffer - * head that was registered by a plugin. Control is passed here - * and this routine will, thru the use of the I/O notify entry - * stored in the b_private field of the buffer head, restore - * the b_rsector value the buffer head had at the time of - * registration and pass control to the registered callback - * address, with pointers to the buffer head and an optional - * plugin private data. Upon completion of the callback, - * control is returned back here. The io notify list entry - * is deleted. This process repeats until this routine - * detects that all registered plugins have been called back - * and the buffer head's original end_io function has been - * called. At this point the DONE flag is set, and we terminate - * callback loop and exit. - * - * Plugins may desire to break or interrupt the callback - * sequence or chain. This may be useful to redrive I/O or - * to wait for other buffer heads to complete before - * allowing the original buffer head callback to occur. - * To interrupt the callback "chain", a registered - * plugin's callback must return with the DONE flag set. - * - * NOTE: If a plugin set the DONE flag, and wishes to redrive - * a buffer head, the plugin MUST reregister the buffer head - * to receive another callback on this buffer head. Also, the - * plugin MUST ensure that the original buffer head end_io - * function get called at some point, either by reregistering - * this buffer head and receiving another callback, or by - * means of buffer head aggregation triggered by the callbacks - * of other buffer heads. - * - */ -static void -evms_end_io(struct buffer_head *bh, int uptodate) -{ - io_notify_t *entry; - int done; - - done = FALSE; - while (!done) { - /* retrieve the io_notify_entry ptr from - * the b_private field in the buffer head. - */ - entry = (io_notify_t *) bh->b_private; - - /* restore the b_private value to - * the previous b_private value (which - * should be a previous io_notify_entry - * or the original b_private pointer). - */ - bh->b_private = entry->b_private; - - /* check for original callback for this bh */ - if (entry->flags & EVMS_ORIGINAL_CALLBACK_FLAG) { - /* this is the original for bh */ - - /* turn off flag marking this as the original */ - entry->flags &= ~EVMS_ORIGINAL_CALLBACK_FLAG; - - /* decrement volume's requests_in_progress var */ - atomic_dec(&evms_logical_volumes[MINOR(bh->b_rdev)]. - requests_in_progress); - - /* restore b_end_io to original value */ - bh->b_end_io = (void *) entry->callback_function; - if (bh->b_end_io) { - /* invoke original callback function - * if it exists. - */ - bh->b_end_io(bh, uptodate); - } - done = TRUE; - } else { - /* this is a plugin callback */ - - /* restore the rsector value to the - * value at the time of callback - * registration. - */ - bh->b_rsector = entry->rsector; - bh->b_rdev = entry->rdev; - /* invoke plugin callback function */ - entry->callback_function(entry->private, bh, uptodate, - &done); - } - /* free the io notify entry */ - evms_cs_deallocate_to_pool(evms_io_notify_pool, entry); - } -} - -/* - * function: evms_cs_register_for_end_io_notification - * - * This function is an evms common service. - * This routine allows a (plugin) function to register to - * participate in the io completion notification process. - * This is useful for plugins which alter data after it - * has been read from the disk (i.e. encryption or - * compression). - * - * This routine also records the rsector value at the time - * of registration, so that it can be restored to that value - * prior to the callback to a plugin, thus allowing that - * plugin to work with the value it had seen during the - * initiating I/O request. - * - * This routine also records a private data pointer at the - * time of registration, and is returned to the plugin - * at callback time. This private data pointer was designed - * to contain context/callback/buffer_head specific data, and - * frees the plugin from having to store and find associated - * data at the time of the callback. This field is not used - * by this function and is optional (NULL if unused). It is - * recorded and returned as a convenience for the plugins. - * - * DANGER!!! - WILL ROBINSON - DANGER!!! - * This routine uses the b_private field in the - * buffer_head structure. If any lower level driver uses this - * field and do NOT restore it, the I/O callback will fail!! - * - * Any plugins writers requiring a field for private storage - * should instead use the private field parameter in this - * function to store their private data. - * - */ - -int -evms_cs_register_for_end_io_notification(void *private, - struct buffer_head *bh, - void *callback_function) -{ - int rc = 0, done; - io_notify_t *new_entry; - - done = FALSE; - while (!done) { - /* allocate a notify entry */ - new_entry = - evms_cs_allocate_from_pool(evms_io_notify_pool, - EVMS_BLOCKABLE); - if (!new_entry) { - schedule(); - continue; - } - - /* initialize notify entry */ - new_entry->private = private; - new_entry->bh = bh; - new_entry->rsector = bh->b_rsector; - new_entry->rdev = bh->b_rdev; - new_entry->b_private = bh->b_private; - new_entry->flags = 0; - - /* is this the first callback for this bh? */ - if (bh->b_end_io != evms_end_io) { - /* yes, first callback */ - new_entry->flags |= EVMS_ORIGINAL_CALLBACK_FLAG; - new_entry->callback_function = (void *) bh->b_end_io; - - /* increment volume's requests_in_progress var */ - atomic_inc(&evms_logical_volumes[MINOR(bh->b_rdev)]. - requests_in_progress); - - /* set b_end_io so we get control */ - bh->b_end_io = evms_end_io; - } else { - /* no, not first callback */ - new_entry->callback_function = callback_function; - done = TRUE; - } - /* set b_private to aid in quick lookup */ - bh->b_private = new_entry; - } - return rc; -} - -EXPORT_SYMBOL(evms_cs_register_for_end_io_notification); - -/* function description: evms_cs_lookup_item_in_list - * - * this function searches for the specified item in the - * specified node list. it returns the address of the - * evms_list_node containing the specified item. - */ -struct evms_list_node ** -evms_cs_lookup_item_in_list(struct evms_list_node **node_list, void *item) -{ - struct evms_list_node **list_node; - - list_node = node_list; - while (*list_node) { - if ((*list_node)->item == item) - break; - list_node = &(*list_node)->next; - } - return list_node; -} - -EXPORT_SYMBOL(evms_cs_lookup_item_in_list); - -/* function description: evms_add_item_to_list - * - * this function adds an item to the list. the - * node for the new item is added to the end - * of the list. the list is traversed to find the end. - * while the traversal occurs, the list is checked - * for the presence of the specified item. if already - * present in the list, and error code is returned. - */ -/* function description: evms_cs_add_item_to_list - * - * this function adds an item to an item list. - * - * RC == 0 is returned for: - * a successful add of a new item - * - * RC == 1 is returned when: - * the item is already on the list - * - * RC < 0 is returned for an error attempting to add the item. - */ -int -evms_cs_add_item_to_list(struct evms_list_node **list, void *item) -{ - int rc = 0; - struct evms_list_node **list_node, *new_node; - - list_node = evms_cs_lookup_item_in_list(list, item); - if (*list_node == NULL) { - new_node = kmalloc(sizeof (struct evms_list_node), GFP_NOIO); - if (new_node) { - memset(new_node, 0, sizeof (struct evms_list_node)); - new_node->item = item; - *list_node = new_node; - } else { - rc = -ENOMEM; - } - } else { - rc = 1; - LOG_DEBUG("warning: attempt to add duplicate item(%p) to " - "list(%p).\n", item, list); - } - return rc; -} - -EXPORT_SYMBOL(evms_cs_add_item_to_list); - -/* function description: evms_remove_item_from_list - * - * this function removes a specified item from the - * specified list. if the specified item is not - * found in the list, and error is returned. - */ -int -evms_cs_remove_item_from_list(struct evms_list_node **list, void *item) -{ - int rc = 0; - struct evms_list_node **list_node; - - /* check to see if item is in the list */ - list_node = evms_cs_lookup_item_in_list(list, item); - - /* was the node found in the list? */ - if (*list_node) { - /* yes, it was found */ - struct evms_list_node *tmp_node; - - /* save ptr to node being removed */ - tmp_node = *list_node; - /* remove it from the global list */ - *list_node = tmp_node->next; - /* delete removed node */ - kfree(tmp_node); - } else { - /* no, it was not found */ - rc = -1; - LOG_ERROR("error(%d): attempt to remove nonexistant node(%p) " - "from list(%p).\n", rc, item, list); - } - return rc; -} - -EXPORT_SYMBOL(evms_cs_remove_item_from_list); - -/* function description: evms_cs_register_device - * - * this function adds a device to the EVMS global device list. - * - * RC == 0 is returned for: - * a successful add of a new device - * - * RC == 1 is returned when: - * the device is already on the list - * - * RC < 0 is returned for an error attempting to add the device. - */ -int -evms_cs_register_device(struct evms_logical_node *device) -{ - return evms_cs_add_item_to_list(&evms_global_device_list, device); -} - -EXPORT_SYMBOL(evms_cs_register_device); - -/* function description: evms_cs_unregister_device - * - * this function removes a device from the EVMS global device list. - * - * RC == 0 is returned for: - * a successful removal of the specified device - * - * RC < 0 is returned for an error attempting to add the device. - * -ENODATA is returned if specified device is not found. - */ -int -evms_cs_unregister_device(struct evms_logical_node *device) -{ - return evms_cs_remove_item_from_list(&evms_global_device_list, - device); -} - -EXPORT_SYMBOL(evms_cs_unregister_device); - -static struct evms_list_node *find_first_next_list_node = NULL; -int -evms_cs_find_next_device(struct evms_logical_node *in_device, - struct evms_logical_node **out_device) -{ - int rc = 0; - struct evms_list_node **list_node; - - if (in_device == NULL) - find_first_next_list_node = evms_global_device_list; - else { - list_node = - evms_cs_lookup_item_in_list(&evms_global_device_list, - in_device); - find_first_next_list_node = *list_node; - if (find_first_next_list_node == NULL) - rc = -ENODATA; - else - find_first_next_list_node = - find_first_next_list_node->next; - } - - if (find_first_next_list_node == NULL) - *out_device = NULL; - else - *out_device = (struct evms_logical_node *) - find_first_next_list_node->item; - - return rc; -} - -EXPORT_SYMBOL(evms_cs_find_next_device); - -void -evms_cs_signal_event(int eventid) -{ - int rc; - struct evms_list_node **list_node; - - /* signal PID(s) of specified event */ - list_node = &evms_global_notify_list; - while (*list_node) { - struct evms_event *event; - - event = (*list_node)->item; - if (event->eventid == eventid) { - struct task_struct *tsk; - - tsk = find_task_by_pid(event->pid); - if (tsk) { - struct siginfo siginfo; - - siginfo.si_signo = event->signo; - siginfo.si_errno = 0; - siginfo.si_code = 0; - rc = send_sig_info(event->signo, &siginfo, tsk); - } else { - /* TODO: - * unregister this stale - * notification record - */ - } - } - list_node = &(*list_node)->next; - } -} - -EXPORT_SYMBOL(evms_cs_signal_event); - -static inline void -evms_flush_signals(void) -{ - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); -} - -static inline void -evms_init_signals(void) -{ - current->exit_signal = SIGCHLD; - siginitsetinv(¤t->blocked, sigmask(SIGKILL)); -} - -static int -evms_thread(void *arg) -{ - struct evms_thread *thread = arg; - lock_kernel(); - - /* - * Detach thread - */ - - daemonize(); - - sprintf(current->comm, thread->name); - evms_init_signals(); - evms_flush_signals(); - thread->tsk = current; - - current->policy = SCHED_OTHER; - set_user_nice(current, -20); - unlock_kernel(); - - complete(thread->event); - while (thread->run) { - void (*run) (void *data); - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&thread->wqueue, &wait); - set_current_state(TASK_INTERRUPTIBLE); - if (!test_bit(EVMS_THREAD_WAKEUP, &thread->flags)) { - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&thread->wqueue, &wait); - clear_bit(EVMS_THREAD_WAKEUP, &thread->flags); - - run = thread->run; - if (run) { - run(thread->data); - run_task_queue(&tq_disk); - } - if (signal_pending(current)) { - evms_flush_signals(); - } - } - complete(thread->event); - return 0; -} - -struct evms_thread * -evms_cs_register_thread(void (*run) (void *), void *data, const u8 * name) -{ - struct evms_thread *thread; - int ret; - struct completion event; - - thread = kmalloc(sizeof (struct evms_thread), GFP_KERNEL); - if (!thread) { - return NULL; - } - memset(thread, 0, sizeof (struct evms_thread)); - init_waitqueue_head(&thread->wqueue); - - init_completion(&event); - thread->event = &event; - thread->run = run; - thread->data = data; - thread->name = name; - ret = kernel_thread(evms_thread, thread, 0); - if (ret < 0) { - kfree(thread); - return NULL; - } - wait_for_completion(&event); - return thread; -} - -EXPORT_SYMBOL(evms_cs_register_thread); - -void -evms_cs_unregister_thread(struct evms_thread *thread) -{ - struct completion event; - - init_completion(&event); - - thread->event = &event; - thread->run = NULL; - thread->name = NULL; - evms_cs_interrupt_thread(thread); - wait_for_completion(&event); - kfree(thread); -} - -EXPORT_SYMBOL(evms_cs_unregister_thread); - -void -evms_cs_wakeup_thread(struct evms_thread *thread) -{ - set_bit(EVMS_THREAD_WAKEUP, &thread->flags); - wake_up(&thread->wqueue); -} - -EXPORT_SYMBOL(evms_cs_wakeup_thread); - -void -evms_cs_interrupt_thread(struct evms_thread *thread) -{ - if (!thread->tsk) { - LOG_ERROR("error: attempted to interrupt an invalid thread!\n"); - return; - } - send_sig(SIGKILL, thread->tsk, 1); -} - -EXPORT_SYMBOL(evms_cs_interrupt_thread); - -struct proc_dir_entry * -evms_cs_get_evms_proc_dir(void) -{ -#ifdef CONFIG_PROC_FS - if (!evms_proc_dir) { - evms_proc_dir = create_proc_entry("evms", S_IFDIR, &proc_root); - } -#endif - return evms_proc_dir; -} - -EXPORT_SYMBOL(evms_cs_get_evms_proc_dir); - -int -evms_cs_volume_request_in_progress(kdev_t dev, - int operation, int *current_count) -{ - int rc = 0; - struct evms_logical_volume *volume; - - volume = &evms_logical_volumes[MINOR(dev)]; - if (volume->node) { - if (operation > 0) { - atomic_inc(&volume->requests_in_progress); - } else if (operation < 0) { - atomic_dec(&volume->requests_in_progress); - } - if (current_count) { - *current_count = - atomic_read(&volume->requests_in_progress); - } - } else { - rc = -ENODEV; - } - return rc; -} - -EXPORT_SYMBOL(evms_cs_volume_request_in_progress); - -void -evms_cs_invalidate_volume(struct evms_logical_node *node) -{ - int i; - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - if (evms_logical_volumes[i].node && node->name) { - if (! - (strcmp - (evms_logical_volumes[i].node->name, - node->name))) { - LOG_DETAILS("Invalidating EVMS device %s minor " - "%d\n", node->name, i); - invalidate_device(MKDEV(EVMS_MAJOR, i), 0); - break; - } - } - } -} - -EXPORT_SYMBOL(evms_cs_invalidate_volume); - -static int -is_open(int minor) -{ - return atomic_read(&evms_logical_volumes[minor].opens); -} - -/**********************************************************/ -/* END -- exported functions/Common Services */ -/**********************************************************/ - -/**********************************************************/ -/* START -- Proc FS Support functions */ -/**********************************************************/ - -#ifdef CONFIG_PROC_FS -static int -evms_info_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int sz = 0; - char *info_level_text = NULL; - - PROCPRINT("Enterprise Volume Management System: Info\n"); - switch (evms_info_level) { - case EVMS_INFO_CRITICAL: - info_level_text = "critical"; - break; - case EVMS_INFO_SERIOUS: - info_level_text = "serious"; - break; - case EVMS_INFO_ERROR: - info_level_text = "error"; - break; - case EVMS_INFO_WARNING: - info_level_text = "warning"; - break; - case EVMS_INFO_DEFAULT: - info_level_text = "default"; - break; - case EVMS_INFO_DETAILS: - info_level_text = "details"; - break; - case EVMS_INFO_DEBUG: - info_level_text = "debug"; - break; - case EVMS_INFO_EXTRA: - info_level_text = "extra"; - break; - case EVMS_INFO_ENTRY_EXIT: - info_level_text = "entry exit"; - break; - case EVMS_INFO_EVERYTHING: - info_level_text = "everything"; - break; - default: - info_level_text = "unknown"; - break; - } - PROCPRINT("EVMS info level: %d (%s).\n", - evms_info_level, info_level_text); - - PROCPRINT("EVMS kernel version: %d.%d.%d\n", - EVMS_MAJOR_VERSION, - EVMS_MINOR_VERSION, EVMS_PATCHLEVEL_VERSION); - - PROCPRINT("EVMS IOCTL interface version: %d.%d.%d\n", - EVMS_IOCTL_INTERFACE_MAJOR, - EVMS_IOCTL_INTERFACE_MINOR, EVMS_IOCTL_INTERFACE_PATCHLEVEL); - - PROCPRINT("EVMS Common Services version: %d.%d.%d\n", - EVMS_COMMON_SERVICES_MAJOR, - EVMS_COMMON_SERVICES_MINOR, EVMS_COMMON_SERVICES_PATCHLEVEL); - - *eof = 1; - -out: - *start = page + off; - sz -= off; - if (sz < 0) - sz = 0; - return sz > count ? count : sz; -} - -static int -evms_plugins_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int sz = 0; - struct evms_registered_plugin *rp = NULL; - - PROCPRINT("Enterprise Volume Management System: Plugins\n"); - /* 0 1 1 2 2 3 3 4 4 5 5 6 6 7 */ - /* 1 5 0 5 0 5 0 5 0 5 0 5 0 5 0 */ - PROCPRINT(" ---------Plugin---------- required services\n"); - PROCPRINT(" ----id---- version version\n\n"); - for (rp = registered_plugin_head; rp; rp = rp->next) { - PROCPRINT(" %x.%x.%x\t %d.%d.%d\t%d.%d.%d\n", - GetPluginOEM(rp->plugin->id), - GetPluginType(rp->plugin->id), - GetPluginID(rp->plugin->id), - rp->plugin->version.major, - rp->plugin->version.minor, - rp->plugin->version.patchlevel, - rp->plugin->required_services_version.major, - rp->plugin->required_services_version.minor, - rp->plugin->required_services_version.patchlevel); - } - -out: - *start = page + off; - sz -= off; - if (sz < 0) - sz = 0; - return sz > count ? count : sz; -} - -static int -evms_volumes_read_proc(char *page, - char **start, off_t off, int count, int *eof, void *data) -{ - int sz = 0, j; - - PROCPRINT("Enterprise Volume Management System: Volumes\n"); - PROCPRINT("major minor #blocks type flags name\n\n"); - for (j = 1; j < MAX_EVMS_VOLUMES; j++) { - struct evms_logical_volume *volume; - - volume = &evms_logical_volumes[j]; - if (volume->node) { - PROCPRINT("%5d %7d %16Ld %s %s %s %s%s\n", - EVMS_MAJOR, j, - (long long)volume->node->total_vsectors >> 1, - (volume->flags & EVMS_VOLUME_FLAG) ? "evms " : "compat", - (volume->flags & EVMS_VOLUME_READ_ONLY) ? "ro" : "rw", - (volume->flags & EVMS_VOLUME_PARTIAL) ? "p " : " ", - EVMS_DEV_NODE_PATH, volume->name); - } - } -out: - *start = page + off; - sz -= off; - if (sz < 0) - sz = 0; - return sz > count ? count : sz; - -} -#endif - -/**********************************************************/ -/* END -- Proc FS Support functions */ -/**********************************************************/ - -/**********************************************************/ -/* START -- FOPS functions definitions */ -/**********************************************************/ - -/************************************************/ -/* START -- IOCTL commands -- EVMS specific */ -/************************************************/ - -static int -evms_ioctl_cmd_get_ioctl_version(void *arg) -{ - int rc = 0; - struct evms_version ver; - - ver.major = EVMS_IOCTL_INTERFACE_MAJOR; - ver.minor = EVMS_IOCTL_INTERFACE_MINOR; - ver.patchlevel = EVMS_IOCTL_INTERFACE_PATCHLEVEL; - - /* copy info to userspace */ - if (copy_to_user(arg, &ver, sizeof (ver))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_get_version(void *arg) -{ - int rc = 0; - struct evms_version ver; - - ver.major = EVMS_MAJOR_VERSION; - ver.minor = EVMS_MINOR_VERSION; - ver.patchlevel = EVMS_PATCHLEVEL_VERSION; - - /* copy info to userspace */ - if (copy_to_user(arg, &ver, sizeof (ver))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_get_info_level(void *arg) -{ - int rc = 0; - - /* copy info to userspace */ - if (copy_to_user(arg, &evms_info_level, sizeof (evms_info_level))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_set_info_level(void *arg) -{ - int temp, rc = 0; - - /* copy info from userspace */ - if (copy_from_user(&temp, arg, sizeof (temp))) - rc = -EFAULT; - else - evms_info_level = temp; - - return rc; -} - -/* function: evms_quiesce_volume - * - * this function performs the actual quiesce operation on - * a volume in kernel memory. - * - * when quiescing, all new I/Os to a volume are stopped, - * causing the calling thread to block. this thread then - * waits until all I/Os in progress are completed, before - * return control to the caller. - * - * when unquiescing, all new I/Os are allowed to proceed - * unencumbered, and all threads waiting (blocked) on this - * volume, are woken up and allowed to proceed. - * - */ -static int -evms_quiesce_volume(struct evms_logical_volume *volume, - struct inode *inode, - struct file *file, struct evms_quiesce_vol_pkt *qv) -{ - int rc; - - LOG_DEBUG("%squiescing %s.\n", - ((qv->command) ? "" : "un"), volume->name); - -#ifdef VFS_PATCH_PRESENT - if (qv->do_vfs) { - /* VFS function call to sync and lock the filesystem */ - fsync_dev_lockfs(MKDEV(EVMS_MAJOR, qv->minor)); - volume->vfs_quiesced = TRUE; - } -#endif - volume->quiesced = qv->command; - - /* Command specified was "quiesce". */ - if (qv->command) { - /* After setting the volume to - * a quiesced state, there could - * be threads (on SMP systems) - * that are executing in the - * function, evms_handle_request, - * between the "wait_event" and the - * "atomic_inc" lines. We need to - * provide a "delay" sufficient - * to allow those threads to - * to reach the atomic_inc's - * before executing the while loop - * below. The "schedule" call should - * provide this. - */ - schedule(); - /* wait for outstanding requests - * to complete - */ - while (atomic_read(&volume->requests_in_progress) > 0) - schedule(); - } - /* send this command down the stack so lower */ - /* layers can know about this */ - rc = IOCTL(volume->node, inode, file, - EVMS_QUIESCE_VOLUME, (unsigned long) qv); - if (!rc) { - /* Command specified was "unquiesce". */ - if (!qv->command) { - /* "wakeup" any I/O requests waiting on - * this volume. - */ - if (waitqueue_active(&volume->wait_queue)) - wake_up(&volume->wait_queue); -#ifdef VFS_PATCH_PRESENT - if (volume->vfs_quiesced) { - /* VFS function call to unlock the filesystem */ - unlockfs(MKDEV(EVMS_MAJOR, qv->minor)); - volume->vfs_quiesced = FALSE; - } -#endif - } - } else { - LOG_ERROR("error(%d) %squiescing %s.\n", - rc, ((qv->command) ? "" : "un"), volume->name); - } - return rc; -} - -/* function: evms_delete_volume - * - * this function performs the actual delete operation on - * a volume to purge it from kernel memory. all structures - * and memory consumed by this volume will be free as well - * as clearing or unregistering any system services or - * global data arrays. - * - * NOTE: this function will return -EBUSY on attempts to - * delete mounted volumes. - * - */ -static int -evms_delete_volume(struct evms_logical_volume *volume, - struct evms_delete_vol_pkt *dv) -{ - int rc = 0; - - /* if this is a "permament" delete */ - /* check to make sure volume is not mounted */ - if (dv->command) { - if (is_open(dv->minor)) { - rc = -EBUSY; - } else { - // invalidate the device since it is not coming back - // this is required incase we are re-using the minor number - invalidate_device(MKDEV(EVMS_MAJOR, dv->minor), 1); - } - } - - /* invoke the delete ioctl at the top of the feature stack */ - if (!rc) { - LOG_DETAILS("deleting '%s'.\n", volume->name); - rc = DELETE(volume->node); - } - - /* the volume has been deleted, do any clean up work - * required. - */ - if (!rc) { - devfs_unregister(volume->devfs_handle); - if (dv->command) { - /* if "permanent" delete, free the name - * and NULL the name field. - */ - kfree(volume->name); - volume->name = NULL; - volume->flags = 0; - } else { - /* if "soft" delete, leave the name so - * we can use it to reassign the same - * minor to this volume after a - * rediscovery. - */ - volume->flags = EVMS_VOLUME_SOFT_DELETED; - } - volume->node = NULL; - set_device_ro(MKDEV(EVMS_MAJOR, dv->minor), 0); - blk_size[EVMS_MAJOR][dv->minor] = 0; - blksize_size[EVMS_MAJOR][dv->minor] = 0; - hardsect_size[EVMS_MAJOR][dv->minor] = 0; - evms_volumes--; - } else { - LOG_ERROR("error(%d) %s deleting %s.\n", - rc, ((dv->command) ? "hard" : "soft"), volume->name); - } - return rc; -} - -/* function: evms_user_delete_volume - * - * this function, depending on the parameters, performs - * a "soft" or a "hard" delete. for a "soft" delete, a - * quiesce & delete request is queued up, to be executed - * at the beginning of the next rediscovery. for a - * "hard" delete, the target volume is quiesced and then - * deleted. if there is any errors attempting to delete - * the target, then the target is unquiesced. if an - * associative volume is specified it is quiesced before - * the target volume is quiesced, and is unquiesced - * after the attempt to delete the target volume. - * - */ -static int -evms_user_delete_volume(struct evms_logical_volume *lvt, - struct inode *inode, - struct file *file, struct evms_delete_vol_pkt *dv) -{ - int rc = 0; - - if (!dv->command) { - /* "soft delete" requested */ - lvt->flags |= (EVMS_REQUESTED_QUIESCE | EVMS_REQUESTED_DELETE); - if (dv->do_vfs) { - lvt->flags |= EVMS_REQUESTED_VFS_QUIESCE; - } - } else { - /* "hard delete" requested */ - int qa = FALSE; - struct evms_quiesce_vol_pkt qv; - struct evms_logical_volume *lva = NULL; - - if (dv->associative_minor) { - /* associative volume specified - * - * quiesce it - */ - lva = &evms_logical_volumes[dv->associative_minor]; - /* quiesce associative volume */ - qv.command = EVMS_QUIESCE; - qv.do_vfs = EVMS_VFS_DO_NOTHING; - qv.minor = dv->associative_minor; - rc = evms_quiesce_volume(lva, inode, file, &qv); - qa = (rc) ? FALSE : TRUE; - } - if (!rc) { - /* quiesce target volume */ - qv.command = EVMS_QUIESCE; - qv.do_vfs = EVMS_VFS_DO_NOTHING; - qv.minor = dv->minor; - rc = evms_quiesce_volume(lvt, inode, file, &qv); - } - if (!rc) { - /* delete the target volume */ - rc = evms_delete_volume(lvt, dv); - if (rc) { - /* got an error undeleting... - * - * unquiesce the target - */ - qv.command = EVMS_UNQUIESCE; - qv.do_vfs = EVMS_VFS_DO_NOTHING; - qv.minor = dv->minor; - evms_quiesce_volume(lvt, inode, file, &qv); - } - } - if (dv->associative_minor) { - /* associative volume specified - * - * unquiesce it - */ - if (qa) { - /* only unquiesce associative - * if we successfully quiesced - * it previously. - */ - qv.command = EVMS_UNQUIESCE; - qv.do_vfs = EVMS_VFS_DO_NOTHING; - qv.minor = dv->associative_minor; - evms_quiesce_volume(lva, inode, file, &qv); - } - } - } - return rc; -} - -/* function: evms_ioctl_cmd_delete_volume - * - * this function copy user data to/from the kernel, and - * validates user parameters. after validation, control - * is passed to worker routine evms_user_delete_volume. - * - */ -static int -evms_ioctl_cmd_delete_volume(struct inode *inode, - struct file *file, unsigned long arg) -{ - int rc = 0; - struct evms_delete_vol_pkt tmp, *user_parms; - struct evms_logical_volume *volume = NULL; - - user_parms = (struct evms_delete_vol_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - /* check to make sure associative minor is in use */ - if (!rc) { - if (tmp.associative_minor) { - volume = &evms_logical_volumes[tmp.associative_minor]; - if (volume->node == NULL) - rc = -ENXIO; - } - } - /* check to make sure target minor is in use */ - if (!rc) { - volume = &evms_logical_volumes[tmp.minor]; - if (volume->node == NULL) - rc = -ENXIO; - else - rc = evms_user_delete_volume(volume, inode, file, &tmp); - } - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -/* function: evms_full_rediscover_prep - * - * this function helps to prevent problems when evms is - * configured with the base built in statically and some - * plugins built as modules. - * - * in these cases, when the initial discovery is done, - * only the statically built modules are available for - * volume construction. as a result, some volumes that - * require the plugins built as modules (which haven't - * been loaded), to be fully reconstructed, may come up - * as compatibility volumes or partial volumes. - * - * when parts of evms are built as modules, the - * evms_rediscover_pkty utility is used, to perform a secondary - * rediscover, after all the plugins built as modules - * have been loaded, to construct all the volumes - * requiring these plugins. - * - * however since some of the volumes, requiring the plugins - * built as modules, may have been already exported as - * compatibility or partial volumes, we need to purge these - * volumes from kernel's memory, so that can be rediscovered - * and claimed by the appropriate plugins, and reconstructed - * into the correct volumes. - * - * this function purges all compatibility volumes that are - * not in use(mounted) and all partial volumes, prior to - * doing the secondary rediscover, thus allowing volumes to - * rediscovered correctly. - * - * NOTE: again, this is only required in cases when a - * combination of plugins are built statically and as - * modules. - * - */ -static void -evms_full_rediscover_prep(struct inode *inode, struct file *file) -{ - int rc = 0, i; - - LOG_DETAILS("%s: started.\n", __FUNCTION__); - /* check for acceptable volumes to be deleted */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_logical_volume *volume = NULL; - struct evms_delete_vol_pkt dv; - int volume_open, doit; - - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - volume_open = is_open(i); - /* only proceed on volumes that are: - * partial volumes - * OR - * unopened compatibility volumes - */ - doit = FALSE; - if (volume->flags & EVMS_VOLUME_PARTIAL) { - /* do all partial volumes - */ - doit = TRUE; - } else if (!(volume->flags & EVMS_VOLUME_FLAG)) { - /* check all compatibility volumes - */ - if (!volume_open && !is_swap_partition(MKDEV(EVMS_MAJOR, i))) { - /* only do unopened volumes - */ - doit = TRUE; - } - } - if (doit == FALSE) { - continue; - } - /* delete the volume from memory. - * do a 'soft' delete if volume - * is mounted, and 'hard' delete - * if it is not. - * - * NOTE: the delete operation will - * clear the bits in the flags field. - */ - dv.command = volume_open ? EVMS_SOFT_DELETE : EVMS_HARD_DELETE; - dv.minor = i; - dv.associative_minor = 0; - dv.status = 0; - rc = evms_user_delete_volume(volume, inode, file, &dv); - } - LOG_DETAILS("%s: completed.\n", __FUNCTION__); -} - -static int -evms_ioctl_cmd_rediscover_volumes(struct inode *inode, - struct file *file, - unsigned int cmd, unsigned long arg) -{ - int rc, i; - struct evms_rediscover_pkt tmp, *user_parms; - u64 *array_ptr = NULL; - ulong array_size = 0; - struct evms_logical_volume *volume = NULL; - - LOG_DEBUG("Rediscovering volumes...\n"); - - rc = tmp.drive_count = 0; - user_parms = (struct evms_rediscover_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (tmp.drive_count == REDISCOVER_ALL_DEVICES) { - evms_full_rediscover_prep(inode, file); - } - /* quiesce all queued volumes */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_quiesce_vol_pkt qv; - - volume = &evms_logical_volumes[i]; - if (!volume->node) { - continue; - } - if (!(volume->flags & EVMS_REQUESTED_QUIESCE)) { - continue; - } - qv.command = EVMS_QUIESCE; - qv.minor = i; - qv.do_vfs = (volume->flags & EVMS_REQUESTED_VFS_QUIESCE) ? - EVMS_VFS_DO : EVMS_VFS_DO_NOTHING, qv.status = 0; - rc = evms_quiesce_volume(volume, inode, file, &qv); - } - /* "soft" delete all queued volumes */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_delete_vol_pkt dv; - - volume = &evms_logical_volumes[i]; - if (!volume->node) { - continue; - } - if (!(volume->flags & EVMS_REQUESTED_DELETE)) { - continue; - } - dv.command = EVMS_SOFT_DELETE; - dv.minor = i; - dv.associative_minor = 0; - dv.status = 0; - rc = evms_delete_volume(volume, &dv); - } - - if (tmp.drive_count && (tmp.drive_count != REDISCOVER_ALL_DEVICES)) { - if (!rc) { - /* create space for userspace drive array */ - array_size = - sizeof (*tmp.drive_array) * tmp.drive_count; - array_ptr = tmp.drive_array; - tmp.drive_array = kmalloc(array_size, GFP_KERNEL); - if (!tmp.drive_array) { - rc = -ENOMEM; - } - } - if (!rc) - /* copy rediscover drive array to kernel space */ - if (copy_from_user - (tmp.drive_array, array_ptr, array_size)) - rc = -EFAULT; - } - - if (!rc) { - static int evms_discover_volumes(struct evms_rediscover_pkt *); - /* perform the rediscovery operation */ - rc = evms_discover_volumes(&tmp); - } - - /* clean up after operation */ - if (tmp.drive_count && (tmp.drive_count != REDISCOVER_ALL_DEVICES)) - kfree(tmp.drive_array); - - /* set return code and copy info to userspace */ - tmp.status = rc; - if (copy_to_user(&user_parms->status, &tmp.status, sizeof (tmp.status))) - rc = -EFAULT; - - return rc; -} - -static struct evms_list_node *user_disk_ptr; -static int -evms_ioctl_cmd_get_logical_disk(void *arg) -{ - int rc = 0; - struct evms_user_disk_pkt tmp, *user_parms; - - user_parms = (struct evms_user_disk_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user - (&tmp.command, &user_parms->command, sizeof (tmp.command))) - rc = -EFAULT; - - if (!rc) { - if (tmp.command == EVMS_FIRST_DISK) - user_disk_ptr = evms_global_device_list; - else /* tmp.command == EVMS_NEXT_DISK */ - user_disk_ptr = user_disk_ptr->next; - - if (user_disk_ptr == NULL) - tmp.status = EVMS_DISK_INVALID; - else { - tmp.status = EVMS_DISK_VALID; - tmp.disk_handle = - NODE_TO_DEV_HANDLE(user_disk_ptr->item); - } - /* copy info to userspace */ - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - } - return rc; -} - -static int -evms_ioctl_cmd_get_logical_disk_info(void *arg) -{ - int rc = 0; - struct evms_user_disk_info_pkt tmp, *user_parms; - struct evms_list_node *p; - struct evms_logical_node *disk_node = NULL; - - user_parms = (struct evms_user_disk_info_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user - (&tmp.disk_handle, &user_parms->disk_handle, - sizeof (tmp.disk_handle))) - rc = -EFAULT; - - /* check handle for validity */ - if (!rc) { - rc = -EINVAL; - disk_node = DEV_HANDLE_TO_NODE(tmp.disk_handle); - for (p = evms_global_device_list; p; p = p->next) - if (p->item == disk_node) { - rc = 0; - user_disk_ptr = p; - break; - } - } - - /* populate kernel copy of user's structure with appropriate info */ - if (!rc) { - struct hd_geometry geo; - struct evms_logical_node *node = - (struct evms_logical_node *) user_disk_ptr->item; - tmp.flags = node->flags; - strcpy(tmp.disk_name, EVMS_DEV_NODE_PATH); - strcat(tmp.disk_name, node->name); - rc = evms_cs_kernel_ioctl(node, EVMS_UPDATE_DEVICE_INFO, - (ulong) NULL); - if (!rc) { - tmp.total_sectors = node->total_vsectors; - tmp.hardsect_size = node->hardsector_size; - tmp.block_size = node->block_size; - rc = evms_cs_kernel_ioctl(node, HDIO_GETGEO, - (unsigned long) &geo); - } - if (!rc) { - tmp.geo_sectors = geo.sectors; - tmp.geo_heads = geo.heads; - tmp.geo_cylinders = geo.cylinders; - } - } - - /* set return code and copy info to userspace */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_sector_io(void *arg) -{ - int rc; -#define MAX_IO_SIZE 128 - u64 io_size, max_io_size = MAX_IO_SIZE; -#undef MAX_IO_SIZE - struct evms_sector_io_pkt tmp, *user_parms; - struct evms_logical_node *disk_node = NULL; - struct evms_list_node *list_node; - unsigned char *io_buffer; - - rc = 0; - list_node = NULL; - io_buffer = NULL; - - user_parms = (struct evms_sector_io_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - /* check handle for validity */ - if (!rc) { - rc = -EINVAL; - disk_node = DEV_HANDLE_TO_NODE(tmp.disk_handle); - for (list_node = evms_global_device_list; list_node; - list_node = list_node->next) - if (list_node->item == disk_node) { - rc = 0; - break; - } - } - if (!rc) { - int done; - /* allocate a io buffer upto 64Kbytes in size */ - if (tmp.sector_count < max_io_size) - max_io_size = tmp.sector_count; - do { - done = TRUE; - /* allocate buffer large enough to max_io_size sectors */ - io_buffer = - kmalloc(max_io_size << EVMS_VSECTOR_SIZE_SHIFT, - GFP_KERNEL); - if (!io_buffer) { - max_io_size >>= 1; - if (!max_io_size) { - rc = -ENOMEM; - } else { - done = FALSE; - } - } - } while (!done); - } - /* perform io with specified disk */ - if (!rc) { - u64 io_sector_offset, io_remaining; - u64 io_bytes; - u_char *user_buffer_ptr; - - io_remaining = tmp.sector_count; - io_sector_offset = 0; - user_buffer_ptr = tmp.buffer_address; - while (io_remaining) { - /* compute the io_size for this pass */ - io_size = (io_remaining >= max_io_size) ? - max_io_size : io_remaining; - - io_bytes = io_size << EVMS_VSECTOR_SIZE_SHIFT; - /* for writes, copy a sector from user to kernel */ - if (tmp.io_flag == EVMS_SECTOR_IO_WRITE) { - /* copy sector from user data buffer */ - if (copy_from_user(io_buffer, - user_buffer_ptr, io_bytes)) - rc = -EFAULT; - } - if (rc) - break; - - /* perform IO one sector at a time */ - rc = INIT_IO(disk_node, - tmp.io_flag, - io_sector_offset + tmp.starting_sector, - io_size, io_buffer); - - if (rc) - break; - - if (tmp.io_flag != EVMS_SECTOR_IO_WRITE) { - /* copy sector to user data buffer */ - if (copy_to_user(user_buffer_ptr, - io_buffer, io_bytes)) - rc = -EFAULT; - } - if (rc) - break; - - user_buffer_ptr += io_bytes; - tmp.buffer_address += io_bytes; - io_sector_offset += io_size; - io_remaining -= io_size; - } - } - - /* if the sector_buffer was allocated, free it */ - if (io_buffer) - kfree(io_buffer); - - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -static int user_minor; -static int -evms_ioctl_cmd_get_minor(void *arg) -{ - int rc = 0; - struct evms_user_minor_pkt tmp, *user_parms; - - user_parms = (struct evms_user_minor_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user - (&tmp.command, &user_parms->command, sizeof (tmp.command))) - rc = -EFAULT; - - if (!rc) { - if (tmp.command == EVMS_FIRST_VOLUME) - user_minor = 1; - else /* tmp.command == EVMS_NEXT_VOLUME */ - user_minor++; - - tmp.status = EVMS_VOLUME_INVALID; - for (; user_minor < MAX_EVMS_VOLUMES; user_minor++) { - struct evms_logical_volume *lv; - - lv = &evms_logical_volumes[user_minor]; - /* see if any corrupt volumes have been - * unmounted. If so, clean up the - * evms_logical_volumes array entry, and - * don't report the volume to the user. - */ - if (lv->flags & EVMS_VOLUME_CORRUPT) { - if (!is_open(user_minor)) { - /* clear logical volume structure - * for this volume so it may be - * reused. - */ - LOG_WARNING("ioctl_get_minor: found " - "unmounted %s volume" - "(%u,%u,%s).\n", - (lv->flags & EVMS_VOLUME_SOFT_DELETED) ? - "'soft deleted'" : "", - EVMS_MAJOR, user_minor, - lv->name); - LOG_WARNING(" releasing minor(%d) " - "used by volume(%s)!\n", - user_minor, lv->name); - kfree(lv->name); - lv->name = NULL; - lv->flags = 0; - } - } - if (lv->node || (lv->flags & EVMS_VOLUME_CORRUPT)) { - tmp.status = EVMS_VOLUME_VALID; - tmp.minor = user_minor; - break; - } - } - - /* copy info to userspace */ - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - } - return rc; -} - -static int -evms_ioctl_cmd_get_volume_data(void *arg) -{ - int rc = 0; - struct evms_volume_data_pkt tmp, *user_parms; - struct evms_logical_volume *volume = NULL; - struct evms_logical_node *node = NULL; - - user_parms = (struct evms_volume_data_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - volume = &evms_logical_volumes[tmp.minor]; - node = volume->node; - if (node == NULL) - rc = -ENODEV; - } - if (!rc) { - tmp.flags = volume->flags; - strcpy(tmp.volume_name, EVMS_DEV_NODE_PATH); - strcat(tmp.volume_name, volume->name); - } - - /* copy return code and info to userspace */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - return rc; -} - -static struct evms_registered_plugin *ioctl_reg_record; -static int -evms_ioctl_cmd_get_plugin(void *arg) -{ - int rc = 0; - struct evms_kernel_plugin_pkt tmp, *user_parms; - - user_parms = (struct evms_kernel_plugin_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user - (&tmp.command, &user_parms->command, sizeof (tmp.command))) - rc = -EFAULT; - - if (!rc) { - /* if the command is not 0, then verify - * that ioctl_reg_record is pointing to - * current and valid plugin header. - */ - if (tmp.command) { /* tmp.command == EVMS_NEXT_PLUGIN */ - struct evms_registered_plugin *tmp_reg_record; - tmp_reg_record = registered_plugin_head; - /* search the current plugin list */ - while (tmp_reg_record) { - if (tmp_reg_record == ioctl_reg_record) - break; - tmp_reg_record = tmp_reg_record->next; - } - /* if the ioctl_reg_record is not in the - * current list, then start at the beginning. - */ - if (!tmp_reg_record) - tmp.command = EVMS_FIRST_PLUGIN; - } - - if (tmp.command == EVMS_FIRST_PLUGIN) - /* start at beginning of plugin list */ - ioctl_reg_record = registered_plugin_head; - else /* tmp.command == EVMS_NEXT_PLUGIN */ - /* continue from current position in list */ - ioctl_reg_record = ioctl_reg_record->next; - - tmp.status = EVMS_PLUGIN_INVALID; - tmp.id = 0; - if (ioctl_reg_record) { - tmp.id = ioctl_reg_record->plugin->id; - tmp.version = ioctl_reg_record->plugin->version; - tmp.status = EVMS_PLUGIN_VALID; - } - - /* copy info to userspace */ - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - } - return rc; -} - -static int -evms_ioctl_cmd_plugin_ioctl(struct inode *inode, - struct file *file, - unsigned int cmd, unsigned long arg) -{ - int rc = 0, found = FALSE; - struct evms_plugin_ioctl_pkt tmp, *user_parms; - struct evms_registered_plugin *p; - - user_parms = (struct evms_plugin_ioctl_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - /* search for the specified plugin */ - for (p = registered_plugin_head; p; p = p->next) - /* check for the specified feature id */ - if (p->plugin->id == tmp.feature_id) { - found = TRUE; - /* check that entry point is used */ - if (p->plugin->fops->direct_ioctl) - rc = DIRECT_IOCTL(p, inode, file, cmd, - arg); - else - rc = -ENOSYS; - break; - } - /* was the specified plugin found? */ - if (found == FALSE) - rc = -ENOPKG; - - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - } - return rc; -} - -#define MAX_BUFFER_SIZE 65536 -static int -evms_ioctl_cmd_kernel_partial_csum(void *arg) -{ - int rc = 0; - u64 compute_size = MAX_BUFFER_SIZE; - struct evms_compute_csum_pkt tmp, *user_parms; - unsigned char *buffer = NULL; - - user_parms = (struct evms_compute_csum_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - /* allocate a io buffer upto 64Kbytes in size */ - if (tmp.buffer_size < MAX_BUFFER_SIZE) - compute_size = tmp.buffer_size; - - /* allocate buffer large enough to hold a single sector */ - buffer = kmalloc(compute_size, GFP_KERNEL); - if (!buffer) { - rc = -ENOMEM; - } - } - /* perform io with specified disk */ - if (!rc) { - u64 remaining_bytes; - u_char *user_buffer_ptr; - unsigned int insum = tmp.insum; - - remaining_bytes = tmp.buffer_size; - user_buffer_ptr = tmp.buffer_address; - while (remaining_bytes) { - /* compute the compute_size for this pass */ - compute_size = (remaining_bytes >= MAX_BUFFER_SIZE) ? - MAX_BUFFER_SIZE : remaining_bytes; - - /* copy into kernel from user data buffer */ - if (copy_from_user(buffer, user_buffer_ptr, - compute_size)) - rc = -EFAULT; - if (rc) - break; - /* compute the checksum for this pass */ - tmp.outsum = csum_partial(buffer, tmp.buffer_size, - insum); - /* set up for another possible pass */ - insum = tmp.outsum; - /* update loop progress variables */ - user_buffer_ptr += compute_size; - tmp.buffer_address += compute_size; - remaining_bytes -= compute_size; - } - } - - /* if the sector_buffer was allocated, free it */ - if (buffer) - kfree(buffer); - - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -#undef MAX_BUFFER_SIZE - -static int -evms_ioctl_cmd_get_bmap(struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct evms_get_bmap_pkt tmp, *user_parms; - - user_parms = (struct evms_get_bmap_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - /* pass the ioctl down the volume stack */ - if (!rc) { - struct evms_logical_volume *volume; - - volume = &evms_logical_volumes[MINOR(inode->i_rdev)]; - rc = IOCTL(volume->node, inode, file, cmd, - (unsigned long) &tmp); - } - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_process_notify_event(unsigned long arg) -{ - int rc = 0, found = FALSE; - struct evms_notify_pkt tmp, *user_parms; - struct evms_list_node **list_node = NULL; - struct evms_event *event = NULL; - - user_parms = (struct evms_notify_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - /* check to see if PID has already been registered - * for this event. - */ - if (!rc) { - list_node = &evms_global_notify_list; - while (*list_node) { - event = (*list_node)->item; - if ((event->pid == tmp.eventry.pid) && - (event->eventid == tmp.eventry.eventid)) { - found = TRUE; - break; - } - list_node = &(*list_node)->next; - } - } - if (tmp.command) { /* tmp.command == EVMS_REGISTER_EVENT */ - /* registration code */ - if (found) { - rc = -EBUSY; - LOG_ERROR("error(%d) pid(%d) already register to " - "receive signal(%d) on event(%d).\n", rc, - tmp.eventry.pid, tmp.eventry.signo, - tmp.eventry.eventid); - } else { - /* register this pid/event type */ - event = kmalloc(sizeof (struct evms_event), GFP_KERNEL); - if (!event) { - rc = -ENOMEM; - LOG_ERROR("error(%d) allocating event structure.\n", rc); - } else { - memset(event, 0, sizeof (struct evms_event)); - event->pid = tmp.eventry.pid; - event->eventid = tmp.eventry.eventid; - event->signo = tmp.eventry.signo; - rc = evms_cs_add_item_to_list - (&evms_global_notify_list, event); - } - } - } else { /* tmp.command == EVMS_UNREGISTER_EVENT */ - /* unregistration code */ - if (!found) { - rc = -ENODATA; - LOG_ERROR("error(%d) attempting to unregister a " - "non-registered pid(%d) on event(%d).\n", - rc, tmp.eventry.pid, tmp.eventry.eventid); - } else { - event = (*list_node)->item; - rc = evms_cs_remove_item_from_list - (&evms_global_notify_list, event); - if (!rc) { - kfree(event); - } - } - } - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_check_mount_status(struct inode *inode, struct file *file, - ulong arg) -{ - int rc = 0; - struct evms_mount_status_pkt tmp, *user_parms; - - user_parms = (struct evms_mount_status_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - tmp.mounted = - (is_mounted(MKDEV(EVMS_MAJOR, tmp.minor))) ? TRUE : FALSE; - } - - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -static int -evms_ioctl_cmd_check_open_status(struct inode *inode, struct file *file, - ulong arg) -{ - int rc = 0; - struct evms_open_status_pkt tmp, *user_parms; - - user_parms = (struct evms_open_status_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - tmp.opens = is_open(tmp.minor); - } - - /* copy the status value back to the user */ - tmp.status = rc; - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - - return rc; -} - -/************************************************/ -/* END -- IOCTL commands -- EVMS specific */ -/************************************************/ - -/************************************************/ -/* START -- IOCTL commands -- Volume specific */ -/************************************************/ - -/************************************************/ -/* END -- IOCTL commands -- Volume specific */ -/************************************************/ - -/************************************************/ -/* START -- IOCTL main */ -/************************************************/ - -/* - * Function: evms_ioctl - * - * This function is the main ioctl entry point for all of evms. - */ - -static int -evms_ioctl(struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - unsigned long minor = 0; - int rc = 0; - struct evms_logical_node *node = NULL; - - /* check user access */ - if (!capable(CAP_SYS_ADMIN)) - rc = -EACCES; - - if (!inode) - rc = -EINVAL; - - if (!rc) { - /* get the minor */ - minor = MINOR(inode->i_rdev); - LOG_EXTRA("ioctl: minor(%lu), dir(%d), size(%d), type(%d), " - "nr(%d)\n", minor, - (cmd >> _IOC_DIRSHIFT) & _IOC_DIRMASK, - (cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK, - (cmd >> _IOC_TYPESHIFT) & _IOC_TYPEMASK, - (cmd >> _IOC_NRSHIFT) & _IOC_NRMASK); - - /* insure this minor points to a valid volume */ - if (minor) { - node = evms_logical_volumes[minor].node; - if (node == NULL) - rc = -ENXIO; - } - } - - /* process the IOCTL commands */ - if (!rc) { - if (!minor) { - /* process all EVMS specific commands */ - switch (cmd) { - case EVMS_GET_IOCTL_VERSION: - rc = evms_ioctl_cmd_get_ioctl_version((void *) - arg); - break; - case EVMS_GET_VERSION: - rc = evms_ioctl_cmd_get_version((void *) arg); - break; - case EVMS_GET_INFO_LEVEL: - rc = evms_ioctl_cmd_get_info_level((void *) - arg); - break; - case EVMS_SET_INFO_LEVEL: - rc = evms_ioctl_cmd_set_info_level((void *) - arg); - break; - case EVMS_REDISCOVER_VOLUMES: - rc = evms_ioctl_cmd_rediscover_volumes(inode, - file, - cmd, - arg); - break; - case EVMS_GET_LOGICAL_DISK: - rc = evms_ioctl_cmd_get_logical_disk((void *) - arg); - break; - case EVMS_GET_LOGICAL_DISK_INFO: - rc = evms_ioctl_cmd_get_logical_disk_info((void - *) - arg); - break; - case EVMS_SECTOR_IO: - rc = evms_ioctl_cmd_sector_io((void *) arg); - break; - case EVMS_GET_MINOR: - rc = evms_ioctl_cmd_get_minor((void *) arg); - break; - case EVMS_GET_VOLUME_DATA: - rc = evms_ioctl_cmd_get_volume_data((void *) - arg); - break; - case EVMS_DELETE_VOLUME: - rc = evms_ioctl_cmd_delete_volume(inode, file, - arg); - break; - case EVMS_GET_PLUGIN: - rc = evms_ioctl_cmd_get_plugin((void *) arg); - break; - case EVMS_PLUGIN_IOCTL: - rc = evms_ioctl_cmd_plugin_ioctl(inode, file, - cmd, arg); - break; - case EVMS_COMPUTE_CSUM: - rc = evms_ioctl_cmd_kernel_partial_csum((void *) - arg); - break; - case EVMS_PROCESS_NOTIFY_EVENT: - rc = evms_ioctl_cmd_process_notify_event(arg); - break; - case EVMS_CHECK_MOUNT_STATUS: - rc = evms_ioctl_cmd_check_mount_status(inode, - file, - arg); - break; - case EVMS_CHECK_OPEN_STATUS: - rc = evms_ioctl_cmd_check_open_status(inode, - file, - arg); - break; - default: - rc = -EINVAL; - break; - } - } else { - /* process Volume specific commands */ - switch (cmd) { - /* pick up standard blk ioctls */ - case BLKFLSBUF: - case BLKROSET: - case BLKROGET: - case BLKRASET: - case BLKRAGET: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) - case BLKBSZGET: - case BLKBSZSET: -#endif - case BLKSSZGET: - rc = blk_ioctl(inode->i_rdev, cmd, arg); - break; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) - case BLKGETSIZE: - { - /* casting size down to 32-bits until - * kernel allows return of 64-bit size - * values. - */ - long size = node->total_vsectors; - if (copy_to_user - ((long *) arg, &size, - sizeof (long))) - rc = -EFAULT; - } - break; - case BLKGETSIZE64: - { - u64 size_in_bytes = - node-> - total_vsectors << - EVMS_VSECTOR_SIZE_SHIFT; - if (copy_to_user - ((u64 *) arg, &size_in_bytes, - sizeof (u64))) - rc = -EFAULT; - } - break; -#endif - case EVMS_GET_IOCTL_VERSION: - rc = evms_ioctl_cmd_get_ioctl_version((void *) - arg); - break; - case EVMS_GET_BMAP: - rc = evms_ioctl_cmd_get_bmap(inode, file, cmd, - arg); - break; - case EVMS_GET_VOL_STRIPE_INFO: - { - struct evms_vol_stripe_info_pkt info; - - info.size = - PAGE_SIZE >> - EVMS_VSECTOR_SIZE_SHIFT; - info.width = 1; - if (copy_to_user - ((struct evms_vol_stripe_info_pkt *) - arg, &info, sizeof (info))) - rc = -EFAULT; - } - break; - - default: - rc = IOCTL(node, inode, file, cmd, arg); - break; - } - } - } - return rc; -} - -/************************************************/ -/* END -- IOCTL main */ -/************************************************/ - -/************************************************/ -/* START -- CHECK MEDIA CHANGE */ -/************************************************/ - -static int -evms_check_media_change(kdev_t dev) -{ - int rc = 0; - struct evms_logical_volume *volume = NULL; - - /* check user access */ - if (!capable(CAP_SYS_ADMIN)) - rc = -EACCES; - if (!rc) { - int minor; - /* get the minor */ - minor = MINOR(dev); - /* insure this minor points to a valid volume */ - volume = &evms_logical_volumes[minor]; - if (volume->node == NULL) { - rc = -ENXIO; - } - } - if (!rc) { - if (volume->flags & EVMS_DEVICE_REMOVABLE) { - /* check for media change */ - rc = evms_cs_kernel_ioctl(volume->node, - EVMS_CHECK_MEDIA_CHANGE, - (unsigned long) NULL); - if (rc < 0) { - LOG_ERROR("error(%d) doing EVMS_CHECK_MEDIA_CHANGE " - "ioctl on '%s'.\n", rc, volume->name); - } - } - } - return rc; -} - -/************************************************/ -/* END -- CHECK MEDIA CHANGE */ -/************************************************/ - -static int -evms_check_for_device_changes(struct inode *inode, struct file *file) -{ - int rc = 0, something_changed = 0, i; - struct evms_rediscover_pkt kernel_rd_pckt = { 0, 0, NULL }; - struct evms_list_node *disk_list = NULL, *lnode, *next_lnode; - struct evms_logical_node *disk, *new_device_list = NULL; - struct evms_logical_volume *volume = NULL; - - /* check for new devices - * - * put all new devices on the disk list so they - * will be included in the rediscovery process. - */ - static void evms_discover_logical_disks(struct evms_logical_node **); - evms_discover_logical_disks(&new_device_list); - if (new_device_list) { - LOG_DETAILS("%s: new devices detected.\n", __FUNCTION__); - something_changed++; - /* put these new nodes on the disk list */ - while (new_device_list) { - disk = new_device_list; - rc = evms_cs_remove_logical_node_from_list - (&new_device_list, disk); - if (rc) { - LOG_ERROR("%s: error(%d) removing device(%s) " - "from list.\n", __FUNCTION__, rc, - disk->name); - } - rc = evms_cs_add_item_to_list(&disk_list, disk); - if (rc) { - LOG_ERROR("%s: error(%d) adding device(%s) " - "from list.\n", __FUNCTION__, rc, - disk->name); - } - } - } - - /* check all devices for changed removable media - * - * scan the global device list and issue check - * media change on each removable media device. - * put all removable devices that indicate a - * media change on the disk list. - * - * also scan for devices that have been unplugged - * or contain corrupt volumes. - */ - for (lnode = evms_global_device_list; lnode; lnode = lnode->next) { - int add_to_list = FALSE; - disk = (struct evms_logical_node *) lnode->item; - /* only really check removable media devices */ - if (disk->flags & EVMS_DEVICE_REMOVABLE) { - /* check for media change */ - rc = evms_cs_kernel_ioctl(disk, - EVMS_CHECK_MEDIA_CHANGE, - (unsigned long) NULL); - if (rc < 0) { - LOG_ERROR("%s: error(%d) doing EVMS_CHECK_MEDIA_CHANGE " - "ioctl on '%s'.\n", __FUNCTION__, rc, - disk->name); - } else if (rc == 1) { - add_to_list = TRUE; - } - } - /* check for device that where present - * before but are gone (unplugged - * device or unloaded driver). - */ - rc = IOCTL(disk, inode, file, - EVMS_CHECK_DEVICE_STATUS, (ulong) NULL); - if (rc) { - LOG_ERROR("error(%d) doing EVMS_CHECK_DEVICE_STATUS " - "ioctl on '%s'.\n", rc, volume->name); - } - if (disk->flags & EVMS_DEVICE_UNAVAILABLE) { - add_to_list = TRUE; - } - if (add_to_list) { - something_changed++; - rc = evms_cs_add_item_to_list(&disk_list, disk); - } - } - /* log a statement that we detected changed media. - */ - if (disk_list) { - LOG_DETAILS("%s: media change detected.\n", __FUNCTION__); - } - - /* check for volumes with removed removable media. - * mark the volumes that reside on changed media. - */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - if (!(volume->flags & EVMS_DEVICE_REMOVABLE)) - continue; - if (evms_check_media_change(MKDEV(EVMS_MAJOR, i)) <= 0) - continue; - /* remember which volumes have changed media */ - volume->flags |= EVMS_MEDIA_CHANGED; - something_changed++; - } - - /* check for removed devices */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - int status; - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - /* check for device status */ - status = 0; - rc = IOCTL(volume->node, inode, file, - EVMS_CHECK_DEVICE_STATUS, (ulong) & status); - if (rc) { - LOG_ERROR("error(%d) doing EVMS_CHECK_DEVICE_STATUS " - "ioctl on '%s'.\n", rc, volume->name); - continue; - } - if (!(status & EVMS_DEVICE_UNAVAILABLE)) { - continue; - } - /* remember which volumes have changed media */ - volume->flags |= EVMS_DEVICE_UNPLUGGED; - something_changed++; - } - - /* do we have some work to do? */ - if (something_changed) { - /* check for volumes to be deleted */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_quiesce_vol_pkt qv; - - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - /* only proceed on volumes with: - * changed media, - * hot-unplugged devices, - * & partial volumes - */ - if (!(volume->flags & - (EVMS_MEDIA_CHANGED | - EVMS_VOLUME_PARTIAL | EVMS_DEVICE_UNPLUGGED))) - continue; - /* gather the disk's needing to be - * rediscovered to rebuild this - * volume. - * - * this will locate other disks that - * the volume resides on that don't - * indicate media change. - */ - rc = evms_cs_kernel_ioctl(volume->node, - EVMS_GET_DISK_LIST, - (unsigned long) &disk_list); - if (rc) { - LOG_ERROR("%s: error(%d) retrieving underlying " - "disk list for '%s', skipping ...\n", - __FUNCTION__, rc, volume->name); - continue; - } - /* quiesce all the changed volumes - * prior to being deleted. - */ - qv.command = 1; // quiesce - qv.minor = i; // - qv.status = 0; // reset status - qv.do_vfs = 0; - rc = evms_quiesce_volume(volume, inode, file, &qv); - if (rc) { - LOG_ERROR("%s: error(%d) attempting to quiesce " - "'%s%s'.\n", __FUNCTION__, rc, - EVMS_DEV_NODE_PATH, volume->name); - } - } - - /* we need to revalidate all the changed - * media. this is accomplished by issuing - * the revalidate disk ioctl to each device - * with changed media. the device manager - * remembers which devices indicated - * media changed (set by check media - * changed ioctl issued earlier), and will - * only issue the revalidate disk ioctl to - * those disks one time. - * - * NOTE: - * this needs to be done BEFORE deleting - * the volumes because deleting the - * last segment on disk will cause the - * associated disk node to freed, and we - * will not be able to issue the - * revalidate disk ioctl after that. - */ - for (lnode = disk_list; lnode; lnode = lnode->next) { - disk = (struct evms_logical_node *) lnode->item; - /* only really do removable media devices */ - if (disk->flags & EVMS_MEDIA_CHANGED) { - /* go revalidate the change media */ - rc = evms_cs_kernel_ioctl(disk, - EVMS_REVALIDATE_DISK, - (unsigned long) NULL); - if (rc) { - LOG_ERROR("%s: error(%d) attempting to " - "revalidate '%s%s'.\n", - __FUNCTION__, rc, - EVMS_DEV_NODE_PATH, volume->name); - } - } - } - - /* delete all the affected volumes */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_delete_vol_pkt dv; - - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - /* only proceed on volumes with: - * changed media, - * hot-unplugged devices, - * & partial volumes - */ - if (!(volume->flags & - (EVMS_MEDIA_CHANGED | - EVMS_VOLUME_PARTIAL | EVMS_DEVICE_UNPLUGGED))) - continue; - /* only delete quiesced volumes */ - if (!volume->quiesced) - continue; - /* delete the volume from memory. - * do a 'soft' delete if volume - * is mounted, and 'hard' delete - * if it is not. - * - * NOTE: the delete operation will - * clear the bits in the flags field. - */ - dv.command = (is_open(i)) ? 0 : 1; - dv.minor = i; - dv.status = 0; - rc = evms_delete_volume(volume, &dv); - } - - /* at this point all devices indicating - * media change that had volumes on them - * should be gone. however, we could still - * have devices indicating media change - * that had no volumes on them in the disk - * list. we need to delete these devices - * from kernel memory and the global device - * list. - */ - for (lnode = evms_global_device_list; lnode; lnode = next_lnode) { - next_lnode = lnode->next; - - disk = (struct evms_logical_node *) lnode->item; - if (disk->flags & EVMS_MEDIA_CHANGED) { - rc = DELETE(disk); - } - } - - /* all the devices that indicated media - * change should be gone, both from kernel - * memory and global device list. we now - * need to remove any references to these - * devices from the disk list. - * - * when removable media is installed, it - * will get detected in the device manager's - * rediscovery as a new device and added to - * the discover list. - */ - for (lnode = disk_list; lnode; lnode = next_lnode) { - struct evms_list_node *glnode; - int lnode_still_there; - - next_lnode = lnode->next; - - lnode_still_there = FALSE; - for (glnode = evms_global_device_list; - glnode; glnode = glnode->next) { - if (glnode->item == lnode->item) { - lnode_still_there = TRUE; - break; - } - } - if (lnode_still_there == FALSE) { - rc = evms_cs_remove_item_from_list(&disk_list, - lnode->item); - if (rc) { - LOG_ERROR("%s: error(%d) attempting to " - "remove item(%p) from " - "disk_list(%p).\n", - __FUNCTION__, rc, lnode->item, - &disk_list); - } - } - } - - /* build the in-kernel rediscover packet */ - - /* allocate the space for the drive_array in - * the struct evms_rediscover_pkt packet. to do this - * we need to count the number of disk nodes, - * then allocate the necessary space. - */ - /* count the disk nodes */ - for (lnode = disk_list; lnode; lnode = lnode->next) - kernel_rd_pckt.drive_count++; - /* allocate the space */ - if (kernel_rd_pckt.drive_count) { - kernel_rd_pckt.drive_array = - kmalloc(kernel_rd_pckt.drive_count * - sizeof (u64), GFP_KERNEL); - if (!kernel_rd_pckt.drive_array) { - rc = -ENOMEM; - LOG_ERROR("%s: error(%d) allocating rediscover " - "drive array.\n", __FUNCTION__, rc); - } - } - /* populate the drive array - * - * this also frees the disk_list which is useful - * if we had an error allocating the drive array. - */ - for (i = 0, lnode = disk_list; lnode; lnode = next_lnode, i++) { - next_lnode = lnode->next; - - /* remove this disk from the disk list */ - disk = (struct evms_logical_node *) lnode->item; - rc = evms_cs_remove_item_from_list(&disk_list, disk); - if (!rc) { - /* add this disk to rediscover - * packet - */ - kernel_rd_pckt.drive_array[i] = - NODE_TO_DEV_HANDLE(disk); - } - } - /* perform the rediscovery operation */ - if (!rc) { - static int evms_discover_volumes(struct - evms_rediscover_pkt *); - rc = evms_discover_volumes(&kernel_rd_pckt); - if (kernel_rd_pckt.drive_count) { - kfree(kernel_rd_pckt.drive_array); - } - } - LOG_DETAILS("%s: rediscover completed.\n", __FUNCTION__); - } - - return rc; -} - -/************************************************/ -/* START -- REVALIDATE DISK */ -/************************************************/ - -static int -evms_revalidate_disk(kdev_t dev) -{ - int rc = 0; - struct evms_logical_volume *volume = NULL; - - /* check user access */ - if (!capable(CAP_SYS_ADMIN)) - rc = -EACCES; - if (!rc) { - int minor; - /* get the minor */ - minor = MINOR(dev); - /* insure this minor points to a valid volume */ - volume = &evms_logical_volumes[minor]; - if (volume->node == NULL) { - rc = -ENXIO; - } - } - if (!rc) { - /* go revalidate the change media */ - rc = evms_cs_kernel_ioctl(volume->node, - EVMS_REVALIDATE_DISK, - (unsigned long) NULL); - } - return rc; -} - -/************************************************/ -/* END -- REVALIDATE DISK */ -/************************************************/ - -/************************************************/ -/* START -- OPEN */ -/************************************************/ - -static int -evms_open(struct inode *inode, struct file *file) -{ - int rc = 0, minor = 0; - struct evms_logical_volume *volume = NULL; - - rc = evms_check_for_device_changes(inode, file); - if (!rc) { - /* get the minor */ - minor = MINOR(inode->i_rdev); - if (minor) { - /* insure this minor points to a valid volume */ - volume = &evms_logical_volumes[minor]; - if (volume->node == NULL) { - rc = -ENXIO; - } - } - } - /* go "open" the volume */ - if (!rc && minor) { - atomic_inc(&volume->opens); - rc = IOCTL(volume->node, inode, file, - EVMS_OPEN_VOLUME, (unsigned long) NULL); - if (rc) { - LOG_ERROR("error(%d) doing EVMS_OPEN_VOLUME ioctl to " - "'%s'.\n", rc, volume->name); - atomic_dec(&volume->opens); - } - } - return rc; -} - -/************************************************/ -/* END -- OPEN */ -/************************************************/ - -/************************************************/ -/* START -- RELEASE */ -/************************************************/ - -static int -evms_release(struct inode *inode, struct file *file) -{ - int rc = 0, minor = 0; - struct evms_logical_volume *volume = NULL; - - /* get the minor */ - minor = MINOR(inode->i_rdev); - if (minor) { - /* insure this minor points to a valid volume */ - volume = &evms_logical_volumes[minor]; - if (volume->node) { - rc = IOCTL(volume->node, inode, file, - EVMS_CLOSE_VOLUME, (unsigned long) NULL); - if (rc) { - LOG_ERROR("error(%d) doing EVMS_CLOSE_VOLUME " - "ioctl to '%s'.\n", rc, volume->name); - } - atomic_dec(&volume->opens); - } - } - return 0; -} - -/************************************************/ -/* END -- RELEASE */ -/************************************************/ - -static struct block_device_operations evms_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) - owner:THIS_MODULE, -#endif - open:evms_open, - release:evms_release, - ioctl:evms_ioctl, - check_media_change:evms_check_media_change, - revalidate:evms_revalidate_disk -}; - -/**********************************************************/ -/* END -- FOPS functions definitions */ -/**********************************************************/ - -/**********************************************************/ -/* START -- RUNTIME support functions */ -/**********************************************************/ - -static request_queue_t * -evms_find_queue(kdev_t dev) -{ - request_queue_t *rq = NULL; - struct evms_logical_volume *volume; - - volume = &evms_logical_volumes[MINOR(dev)]; - rq = &volume->request_queue; - return rq; -} - -/* - * Function: evms_make_request_fn - * - */ -static int -evms_make_request_fn(request_queue_t * q, int rw, struct buffer_head *bh) -{ - struct evms_logical_volume *volume; - -// volume = &evms_logical_volumes[MINOR(bh->b_rdev)]; - volume = q->queuedata; - wait_event(volume->wait_queue, (!volume->quiesced)); - if (volume->node) { - switch (rw) { - case READ: - case READA: - atomic_inc(&volume->requests_in_progress); - R_IO(volume->node, bh); - atomic_dec(&volume->requests_in_progress); - break; - case WRITE: - atomic_inc(&volume->requests_in_progress); - W_IO(volume->node, bh); - atomic_dec(&volume->requests_in_progress); - break; - default: - bh->b_end_io(bh, 0); - } - } else { - LOG_ERROR("request for unknown logical volume [minor(%d)].\n", - MINOR(bh->b_rdev)); - bh->b_end_io(bh, 0); - } - return 0; -} - -/**********************************************************/ -/* END -- RUNTIME support functions */ -/**********************************************************/ - -/**********************************************************/ -/* START -- INIT/DISCOVERY support functions */ -/**********************************************************/ - -#ifdef LOCAL_DEBUG -static void -display_discover_list(struct evms_logical_node *discover_list, char *text) -{ - struct evms_logical_node *node; - - LOG_DETAILS("discover list:(%s)\n", text); - for (node = discover_list; node; node = node->next) { - LOG_DETAILS("\nnode info:\n"); - LOG_DETAILS("node.....................(0x%p)\n", node); - LOG_DETAILS("name.....................(%s)\n", node->name); - LOG_DETAILS("plugin id................(0x%x)\n", - node->plugin->id); - LOG_DETAILS("size.....................("PFU64")\n", - node->total_vsectors); - LOG_DETAILS("flags....................(0x%x)\n", node->flags); - LOG_DETAILS("iflags...................(0x%x)\n", node->iflags); - LOG_DETAILS("sector size..............(%d)\n", - node->hardsector_size); - LOG_DETAILS("block size...............(%d)\n", - node->block_size); - LOG_DETAILS("sys id...................(0x%x)\n", - node->system_id); - - if (node->feature_header) { - struct evms_feature_header *fh; - - fh = node->feature_header; - LOG_DETAILS("\nfeature header:\n"); - LOG_DETAILS("signature................(0x%x)\n", - fh->signature); - LOG_DETAILS("crc......................(0x%x)\n", - fh->crc); - LOG_DETAILS("feature header version...(%d.%d.%d)\n", - fh->version.major, fh->version.minor, - fh->version.patchlevel); - LOG_DETAILS("engine version...........(%d.%d.%d)\n", - fh->engine_version.major, - fh->engine_version.minor, - fh->engine_version.patchlevel); - LOG_DETAILS("flags....................(0x%x)\n", - fh->flags); - LOG_DETAILS("feature id...............(0x%x)\n", - fh->feature_id); - LOG_DETAILS("sequence#................("PFU64")\n", - fh->sequence_number); - LOG_DETAILS("alignment padding........("PFU64")\n", - fh->alignment_padding); - LOG_DETAILS("feature data1 lsn........("PFU64")\n", - fh->feature_data1_start_lsn); - LOG_DETAILS("feature data1 size.......("PFU64")\n", - fh->feature_data1_size); - LOG_DETAILS("feature data2 lsn........("PFU64")\n", - fh->feature_data2_start_lsn); - LOG_DETAILS("feature data2 size.......("PFU64")\n", - fh->feature_data2_size); - LOG_DETAILS("volume sn................("PFU64")\n", - fh->volume_serial_number); - LOG_DETAILS("volume minor#............(%d)\n", - fh->volume_system_id); - LOG_DETAILS("object depth.............(%d)\n", - fh->object_depth); - LOG_DETAILS("object name..............(%s)\n", - fh->object_name); - LOG_DETAILS("volume name..............(%s)\n", - fh->volume_name); - } - - if (node->volume_info) { - struct evms_volume_info *vi; - - vi = node->volume_info; - LOG_DETAILS("\nvolume info:\n"); - LOG_DETAILS("volume name..............(%s)\n", - vi->volume_name); - LOG_DETAILS("volume sn................("PFU64")\n", - vi->volume_sn); - LOG_DETAILS("volume minor#............(%d)\n", - vi->volume_minor); - } - } - if (discover_list) { - LOG_DETAILS("\n"); - } -} -#endif - -/* - * Function: evms_discover_logical_disks - * Description: Construct the logical disk list by calling all registered device managers. - */ -static void -evms_discover_logical_disks(struct evms_logical_node **disk_list) -{ - struct evms_registered_plugin *p; - LOG_EXTRA("discovering logical disks...\n"); - for (p = registered_plugin_head; p; p = p->next) { - if (GetPluginType(p->plugin->id) == EVMS_DEVICE_MANAGER) { - DISCOVER(p, disk_list); - } - } -} - -/* - * Function: evms_discover_logical_partitions - * Description: Construct the logical partition list by calling all registered partition managers. - */ -static void -evms_discover_logical_partitions(struct evms_logical_node **discover_list) -{ - int rc, done; - - struct evms_registered_plugin *p; - LOG_EXTRA("discovering segments...\n"); - do { - done = TRUE; - for (p = registered_plugin_head; p; p = p->next) { - if (GetPluginType(p->plugin->id) == - EVMS_SEGMENT_MANAGER) { - rc = DISCOVER(p, discover_list); - /* RC > 0 means the plugin added something to - * the discover list. This also means we must - * loop thru these plugins another time. - * RC == 0 means nothing was added to the - * discover list by this plugin. RC < 0 means - * the plugin encountered some error and - * nothing was added to the list. - * NOTE: If a plugin has both added something - * new to the discover list and encountered an - * error, RC > 0 must be returned. - */ - if (rc > 0) - done = FALSE; - } - } - } while (done == FALSE); - - /* send the end of discovery signal to each - * partition manager plugin. - */ - for (p = registered_plugin_head; p; p = p->next) - if (GetPluginType(p->plugin->id) == EVMS_SEGMENT_MANAGER) - if (p->plugin->fops->end_discover) - rc = END_DISCOVER(p, discover_list); -} - -/* - * Function: evms_discover_volume_groups - * Description: Find volume groups within the logical partitions list - */ -static void -evms_discover_volume_groups(struct evms_logical_node **discover_list) -{ - int rc, done; - - struct evms_registered_plugin *p; - LOG_EXTRA("discovering regions...\n"); - do { - done = TRUE; - for (p = registered_plugin_head; p; p = p->next) { - if (GetPluginType(p->plugin->id) == EVMS_REGION_MANAGER) { - rc = DISCOVER(p, discover_list); - /* RC > 0 means the plugin added something to - * the discover list. This also means we must - * loop thru these plugins another time. - * RC == 0 means nothing was added to the - * discover list by this plugin. RC < 0 means - * the plugin encountered some error and - * nothing was added to the list. - * NOTE: If a plugin has both added something - * new to the discover list and encountered an - * error, RC > 0 must be returned. - */ - if (rc > 0) - done = FALSE; - } - } - } while (done == FALSE); - - /* send the end of discovery signal to each volume - * group plugin. - */ - for (p = registered_plugin_head; p; p = p->next) - if (GetPluginType(p->plugin->id) == EVMS_REGION_MANAGER) - if (p->plugin->fops->end_discover) - rc = END_DISCOVER(p, discover_list); -} - -/* - * - * convert all the feature header fields into cpu native format - * from the on-disk Little Endian format. From this point forward - * all plugins can deal with feature headers natively. - */ -void -le_feature_header_to_cpu(struct evms_feature_header *fh) -{ - fh->signature = le32_to_cpup(&fh->signature); - fh->crc = le32_to_cpup(&fh->crc); - fh->version.major = le32_to_cpup(&fh->version.major); - fh->version.minor = le32_to_cpup(&fh->version.minor); - fh->version.patchlevel = le32_to_cpup(&fh->version.patchlevel); - fh->engine_version.major = le32_to_cpup(&fh->engine_version.major); - fh->engine_version.minor = le32_to_cpup(&fh->engine_version.minor); - fh->engine_version.patchlevel = le32_to_cpup(&fh->engine_version.patchlevel); - fh->flags = le32_to_cpup(&fh->flags); - fh->feature_id = le32_to_cpup(&fh->feature_id); - fh->sequence_number = le64_to_cpup(&fh->sequence_number); - fh->alignment_padding = le64_to_cpup(&fh->alignment_padding); - fh->feature_data1_start_lsn = le64_to_cpup(&fh->feature_data1_start_lsn); - fh->feature_data1_size = le64_to_cpup(&fh->feature_data1_size); - fh->feature_data2_start_lsn = le64_to_cpup(&fh->feature_data2_start_lsn); - fh->feature_data2_size = le64_to_cpup(&fh->feature_data2_size); - fh->volume_serial_number = le64_to_cpup(&fh->volume_serial_number); - fh->volume_system_id = le32_to_cpup(&fh->volume_system_id); - fh->object_depth = le32_to_cpup(&fh->object_depth); -} - -static int -edef_load_feature_header(struct evms_logical_node *node) -{ - int i, rc = 0, rc_array[2] = { 0, 0 }; - unsigned long size_in_bytes; - u64 size_in_sectors, starting_sector = 0; - struct evms_feature_header *fh = NULL, *fh1 = NULL, *fh2 = NULL; - char *location_name = NULL; - struct evms_version version = { - EVMS_FEATURE_HEADER_MAJOR, - EVMS_FEATURE_HEADER_MINOR, - EVMS_FEATURE_HEADER_PATCHLEVEL - }; - - if (!node->feature_header) { - size_in_sectors = evms_cs_size_in_vsectors(sizeof (*fh)); - size_in_bytes = size_in_sectors << EVMS_VSECTOR_SIZE_SHIFT; - fh1 = kmalloc(size_in_bytes, GFP_KERNEL); - if (fh1) { - fh2 = kmalloc(size_in_bytes, GFP_KERNEL); - if (!fh2) { - kfree(fh1); - rc = -ENOMEM; - } - } else { - rc = -ENOMEM; - } - - for (i = 0; i < 2; i++) { - if (i == 0) { - starting_sector = - node->total_vsectors - size_in_sectors; - fh = fh1; - location_name = evms_primary_string; - } else { - starting_sector--; - fh = fh2; - location_name = evms_secondary_string; - } - /* read header into buffer */ - rc = INIT_IO(node, - 0, starting_sector, size_in_sectors, fh); - if (rc) { - LOG_ERROR("error(%d) probing for %s feature " - "header(at "PFU64") on '%s'.\n", rc, - location_name, starting_sector, - node->name); - rc_array[i] = rc; - continue; - } - /* validate header signature */ - if (cpu_to_le32(fh->signature) != - EVMS_FEATURE_HEADER_SIGNATURE) { - rc = -ENODATA; - rc_array[i] = rc; - continue; - } - /* validate header CRC */ - if (fh->crc != EVMS_MAGIC_CRC) { - u32 org_crc, final_crc; - org_crc = cpu_to_le32(fh->crc); - fh->crc = 0; - final_crc = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, fh, - sizeof (*fh)); - if (final_crc != org_crc) { - LOG_ERROR("CRC mismatch error [stored(%x), " - "computed(%x)] in %s feature " - "header(at "PFU64") on '%s'.\n", - org_crc, final_crc, location_name, - starting_sector, node->name); - rc = -EINVAL; - rc_array[i] = rc; - continue; - } - } else { - LOG_WARNING("CRC disabled in %s feature header " - "(at "PFU64") on '%s'.\n", - location_name, starting_sector, - node->name); - } - /* convert the feature header from the - * on-disk format (Little Endian) to - * native cpu format. - */ - le_feature_header_to_cpu(fh); - /* verify the system data version */ - rc = evms_cs_check_version(&version, &fh->version); - if (rc) { - LOG_ERROR("error: obsolete version(%d,%d,%d) " - "in %s feature header on '%s'.\n", - fh->version.major, fh->version.minor, - fh->version.patchlevel, location_name, - node->name); - rc_array[i] = rc; - } - } - - /* getting same return code for both copies? */ - if (rc_array[0] == rc_array[1]) { - rc = rc_array[0]; - /* if no errors on both copies, - * check the sequence numbers. - * use the highest sequence number. - */ - if (!rc) { - /* compare sequence numbers */ - if (fh1->sequence_number == - fh2->sequence_number) { - fh = fh1; - } else { - LOG_WARNING("%s feature header sequence " - "number("PFU64") mismatches " - "%s feature header sequence " - "number("PFU64") on '%s'!\n", - evms_primary_string, - fh1->sequence_number, - evms_secondary_string, - fh2->sequence_number, node->name); - if (fh1->sequence_number > - fh2->sequence_number) { - fh = fh1; - location_name = - evms_primary_string; - /* indicate bad sequence number of secondary */ - rc_array[1] = -1; - } else { - fh = fh2; - location_name = - evms_secondary_string; - /* indicate bad sequence number of primary */ - rc_array[0] = -1; - } - } - } - /* getting different return codes for each copy */ - } else - /* either primary or secondary copy is - * valid, so use the valid copy. - */ - if ((rc_array[0] == 0) || (rc_array[1] == 0)) { - char *warn_name = NULL; - - /* indicate success */ - rc = 0; - /* set variables based on which copy is valid */ - if (rc_array[0] == 0) { - /* use primary (rear) copy if its good */ - fh = fh1; - location_name = evms_primary_string; - warn_name = evms_secondary_string; - } else { - /* use secondary (front) copy if its good */ - fh = fh2; - location_name = evms_secondary_string; - warn_name = evms_primary_string; - } - /* warn the user about the invalid copy */ - LOG_WARNING("warning: error(%d) probing/verifying the " - "%s feature header on '%s'.\n", - rc_array[0] + rc_array[1], - warn_name, node->name); - } else - /* both copies had a different error, - * and one was a fatal error, so - * indicate fatal error. - */ - if ((rc_array[0] == -EINVAL) || (rc_array[1] == -EINVAL)) { - rc = -EINVAL; - } - - /* on error, set fh to NULL */ - if (rc) - fh = NULL; - - /* deallocate metadata buffers appropriately */ - if (fh != fh1) - kfree(fh1); - if (fh != fh2) - kfree(fh2); - - /* save validated feature header pointer */ - if (!rc) { - node->feature_header = fh; - if (rc_array[0] != rc_array[1]) { - LOG_DETAILS("using %s feature header on '%s'.\n", - location_name, node->name); - } - } - - /* if no signature found, adjust return code */ - if (rc == -ENODATA) { - rc = 0; - LOG_DEBUG("no feature header found on '%s'.\n", - node->name); - } - } - return rc; -} - -static int -edef_find_first_features(struct evms_logical_node **discover_list) -{ - int rc; - struct evms_logical_node *node, *tmp_list_head; - - tmp_list_head = *discover_list; - *discover_list = NULL; - - while (tmp_list_head) { - struct evms_list_node **evms_node; - - node = tmp_list_head; - evms_cs_remove_logical_node_from_list(&tmp_list_head, node); - - /* check for duplicate pointers - * search for the node in global list - */ - evms_node = - evms_cs_lookup_item_in_list(&evms_global_feature_node_list, - node); - /* already present? */ - if (*evms_node) { - /* yes, already present */ - rc = -ENODATA; /* dont process this node further */ - LOG_DETAILS("deleting duplicate reference to '%s'.\n", - node->name); - /* forget this node */ - node = NULL; - } else { - /* load the feature header if present */ - rc = edef_load_feature_header(node); - /* This node have a feature header ? - * it won't be if there is no header to load - * OR - * there was a fatal error attempting to read it. - */ - if (node->feature_header) { - /* check for object flag */ - if (node->feature_header->flags & - EVMS_VOLUME_DATA_OBJECT) { - LOG_DEFAULT("object detected, deleting " - "'%s'.\n", node->name); - rc = -EINVAL; - } else - /* check for stop-data flag */ - if (node->feature_header->flags & - EVMS_VOLUME_DATA_STOP) { - LOG_DEFAULT("stop data detected, " - "deleting '%s'.\n", - node->name); - rc = -EINVAL; - } else { - /* we have a valid feature header. - * initialize appropriate node fields - * to indicate this. - */ - node->flags |= EVMS_VOLUME_FLAG; - node->iflags |= EVMS_FEATURE_BOTTOM; - node->volume_info = - kmalloc(sizeof - (struct evms_volume_info), - GFP_KERNEL); - if (node->volume_info) { - /* set up volume - * info struct - */ - memset(node->volume_info, 0, - sizeof - (struct - evms_volume_info)); - node->volume_info->volume_sn = - node->feature_header-> - volume_serial_number; - node->volume_info-> - volume_minor = - node->feature_header-> - volume_system_id; - strcpy(node->volume_info-> - volume_name, - node->feature_header-> - volume_name); - /* register(add) node to - * the global list. - */ - rc = evms_cs_add_item_to_list - (&evms_global_feature_node_list, - node); - } else { - rc = -ENOMEM; - } - } - } - } - /* if any errors, delete the node */ - if (rc) { - if (node) { - DELETE(node); - } - } else - /* on successful processing of this node - * place it back on the discover list. - */ - evms_cs_add_logical_node_to_list(discover_list, node); - } - return 0; -} - -/* These define describe the node types that can be isolated. */ -#define ISOLATE_ASSOCIATIVE_FEATURES 0 -#define ISOLATE_COMPATIBILITY_VOLUMES 1 -#define ISOLATE_EVMS_VOLUMES 2 -#define ISOLATE_EVMS_VOLUME_SERIAL_NUMBER 3 -#define ISOLATE_EVMS_NODES_BY_FEATURE_AND_DEPTH 4 -static int -edef_isolate_nodes_by_type(unsigned int type, - struct evms_logical_node **src_list, - struct evms_logical_node **trg_list, - u32 compare32, u64 compare64) -{ - struct evms_logical_node *node, *next_node; - int rc = 0, found_node; - struct evms_feature_header *fh = NULL; - - for (node = *src_list; node; node = next_node) { - next_node = node->next; - - if (node->feature_header) - fh = node->feature_header; - found_node = FALSE; - switch (type) { - case ISOLATE_ASSOCIATIVE_FEATURES: - if (fh) { - if (GetPluginType(fh->feature_id) == - EVMS_ASSOCIATIVE_FEATURE) - found_node = TRUE; - } - break; - case ISOLATE_COMPATIBILITY_VOLUMES: - if (!(node->flags & EVMS_VOLUME_FLAG)) - found_node = TRUE; - break; - case ISOLATE_EVMS_VOLUMES: - if (node->flags & EVMS_VOLUME_FLAG) - found_node = TRUE; - break; - /* EVMS volumes with same serial # */ - case ISOLATE_EVMS_VOLUME_SERIAL_NUMBER: - if (node->volume_info->volume_sn == compare64) - found_node = TRUE; - break; - case ISOLATE_EVMS_NODES_BY_FEATURE_AND_DEPTH: - if (fh) - if (fh->object_depth == compare64) - if (fh->feature_id == compare32) - found_node = TRUE; - break; - } - if (found_node == TRUE) { - rc = evms_cs_remove_logical_node_from_list(src_list, - node); - if (rc) - break; - rc = evms_cs_add_logical_node_to_list(trg_list, node); - if (rc) - break; - } - } - return rc; -} - -static int -edef_apply_feature(struct evms_logical_node *node, - struct evms_logical_node **volume_node_list) -{ - struct evms_registered_plugin *p; - int rc = -1; - - for (p = registered_plugin_head; p; p = p->next) { - if (p->plugin->id == node->feature_header->feature_id) { - rc = DISCOVER(p, volume_node_list); - break; - } - } - return rc; -} - -static int -edef_get_feature_plugin_header(u32 id, struct evms_plugin_header **header) -{ - int rc = -ENOPKG; - struct evms_registered_plugin *p; - - for (p = registered_plugin_head; p; p = p->next) { - if (p->plugin->id == id) { - *header = p->plugin; - rc = 0; - break; - } - } - if (rc) { - LOG_SERIOUS("no plugin loaded for feature id(0x%x)\n", id); - } - return rc; -} - -typedef struct evms_volume_build_info_s { - int node_count; - int feature_header_count; - int feature_count; - int associative_feature_count; - u64 max_depth; - struct evms_plugin_header *plugin; - struct evms_logical_node *feature_node_list; -} evms_volume_build_info_t; - -/* - * edef_evaluate_volume_node_list: - * does: - * 1) put all nodes from feature list back on volume list - * 2) loads the node's feature headers - * 3) counts the node list's entries - * 4) builds the feature node list - * 5) counts the feature headers for associative features - * 6) sets feature count to >1 if >1 features to be processed - */ -static int -edef_evaluate_volume_node_list(struct evms_logical_node **volume_node_list, - evms_volume_build_info_t * vbi, - int volume_complete) -{ - int rc; - struct evms_logical_node *node; - - vbi->node_count = - vbi->feature_count = - vbi->associative_feature_count = vbi->max_depth = 0; - vbi->plugin = NULL; - - /* put all feature nodes back on the volume list */ - rc = edef_isolate_nodes_by_type(ISOLATE_EVMS_VOLUMES, - &vbi->feature_node_list, - volume_node_list, 0, 0); - if (rc) - return rc; - - /* load all the feature headers */ - if (!volume_complete) { - for (node = *volume_node_list; node; node = node->next) { - rc = edef_load_feature_header(node); - if (rc) - return rc; - } - } - - /* find the 1st max depth object: - * record the depth - * record the plugin - */ - for (node = *volume_node_list; node; node = node->next) { - struct evms_plugin_header *plugin; - struct evms_feature_header *fh = node->feature_header; - - /* count the nodes */ - vbi->node_count++; - - /* no feature header found, continue to next node */ - if (!fh) - continue; - - /* check the depth */ - if (fh->object_depth > vbi->max_depth) { - /* record new max depth */ - vbi->max_depth = fh->object_depth; - /* find the plugin header for this feature id */ - rc = edef_get_feature_plugin_header(fh->feature_id, - &plugin); - if (rc) - return rc; - /* check for >1 plugins */ - if (vbi->plugin != plugin) { - vbi->feature_count++; - vbi->plugin = plugin; - } - } - /* check for "associative" feature indicator */ - if (GetPluginType(vbi->plugin->id) == EVMS_ASSOCIATIVE_FEATURE) - vbi->associative_feature_count++; - } - /* build a list of max depth nodes for this feature */ - if (vbi->max_depth) { - rc = edef_isolate_nodes_by_type - (ISOLATE_EVMS_NODES_BY_FEATURE_AND_DEPTH, volume_node_list, - &vbi->feature_node_list, vbi->plugin->id, vbi->max_depth); - if (rc) - return rc; - if (!vbi->plugin) - return -ENODATA; - if (!vbi->feature_node_list) - return -ENODATA; - } - - return rc; -} - -/* function: edef_check_feature_conditions - * - * This routine verifies the state of volume based on the features - * headers and nodes in the current discovery list. All detected - * errors are considered fatal. - */ -static int -edef_check_feature_conditions(evms_volume_build_info_t * vbi) -{ - int rc = 0; - - if (vbi->associative_feature_count) { - if (vbi->node_count > 1) { - rc = -EVMS_VOLUME_FATAL_ERROR; - LOG_ERROR("associative ERROR: > 1 nodes(%d) remaining " - "to be processed!\n", vbi->node_count); - } else if (vbi->max_depth != 1) { - rc = -EVMS_VOLUME_FATAL_ERROR; - LOG_ERROR("associative ERROR: associative feature " - "found at node depth("PFU64") != 1!\n", - vbi->max_depth); - } else - rc = -EVMS_ASSOCIATIVE_FEATURE; - } - if (!rc) { - if (!vbi->max_depth) { - if (vbi->node_count > 1) { - rc = -EVMS_VOLUME_FATAL_ERROR; - LOG_ERROR("max depth ERROR: > 1 nodes(%d) " - "remaining to be processed!\n", - vbi->node_count); - } - } else if (vbi->max_depth == 1) { - if (vbi->feature_count > 1) { - rc = -EVMS_VOLUME_FATAL_ERROR; - LOG_ERROR("max depth 1 ERROR: > 1 features " - "remaining to be processed!\n"); - } - } - } - return rc; -} - -/* function: edef_apply_features - * - * This routine applies none, one, or more features to an EVMS - * volume. The system data structure is first verified and then - * features are applied and verified recursively until the - * entire volume has been constructed. Fatal errors result in - * all nodes in the volume discovery list being deleted. - */ -static int -edef_apply_features(struct evms_logical_node **volume_node_list) -{ - int rc = 1, done, top_feature_applying; - evms_volume_build_info_t vbi; - - vbi.feature_node_list = NULL; - rc = edef_evaluate_volume_node_list(volume_node_list, &vbi, FALSE); - - /* ensure we don't go into the next loop - * without having a target plugin to - * pass control to. - */ - if (!rc) { - if (!vbi.plugin) { - rc = -ENODATA; - } - } - - /* this loop should ONLY get used when - * there are features to process. - */ - done = (rc) ? TRUE : FALSE; - while (!done) { - rc = edef_check_feature_conditions(&vbi); - if (rc) - break; - top_feature_applying = (vbi.max_depth == 1) ? TRUE : FALSE; - rc = vbi.plugin->fops->discover(&vbi.feature_node_list); - if (!rc) { - rc = edef_evaluate_volume_node_list(volume_node_list, - &vbi, - top_feature_applying); - if (top_feature_applying == TRUE) { - if (vbi.node_count > 1) { - rc = -EVMS_VOLUME_FATAL_ERROR; - LOG_ERROR("ERROR: detected > 1 node at " - "volume completion!\n"); - } - done = TRUE; - } else { - if (!vbi.plugin) { - rc = -EVMS_VOLUME_FATAL_ERROR; - LOG_ERROR("ERROR: depth("PFU64"): " - "expected another feature!\n", - vbi.max_depth); - done = TRUE; - } - } - } else { /* rc != 0 */ - rc = -EVMS_VOLUME_FATAL_ERROR; - done = TRUE; - } - } - if (rc) - /* put all feature nodes back on the volume list */ - if (edef_isolate_nodes_by_type(ISOLATE_EVMS_VOLUMES, - &vbi.feature_node_list, - volume_node_list, 0, 0)) - BUG(); - return rc; -} - -static int -edef_delete_node(struct evms_logical_node **node_list, - struct evms_logical_node *node, int return_code, - char *log_text) -{ - int rc; - - rc = evms_cs_remove_logical_node_from_list(node_list, node); - if (!rc) { - LOG_ERROR("%s error(%d): deleting volume(%s), node(%s)\n", - log_text, return_code, - node->volume_info->volume_name, node->name); - rc = DELETE(node); - if (rc) { - LOG_ERROR("error(%d) while deleting node(%s)\n", - rc, node->name); - } - } else { - LOG_WARNING("%s error(%d): node gone, assumed deleted by " - "plugin.\n", log_text, return_code); - /* plugin must have cleaned up the node. - * So just reset the return code and leave. - */ - rc = 0; - } - - return rc; -} - -static int -edef_process_evms_volumes(struct evms_logical_node **discover_list, - struct evms_logical_node **associative_feature_list) -{ - int rc = 0; - struct evms_logical_node *node, *evms_volumes_list, *volume_node_list; - u64 volume_sn; - - /* put all EVMS volumes on their own list */ - evms_volumes_list = NULL; - rc = edef_isolate_nodes_by_type(ISOLATE_EVMS_VOLUMES, - discover_list, - &evms_volumes_list, 0, 0); - - /* apply features to each EVMS volume */ - /* one volume at a time on each pass */ - while (evms_volumes_list) { - node = evms_volumes_list; - /* put all nodes for one EVMS volume on separate list */ - volume_node_list = NULL; - volume_sn = node->volume_info->volume_sn; - rc = edef_isolate_nodes_by_type - (ISOLATE_EVMS_VOLUME_SERIAL_NUMBER, &evms_volumes_list, - &volume_node_list, 0, volume_sn); - if (rc) - break; - /* go apply all the volume features now */ - rc = edef_apply_features(&volume_node_list); - switch (rc) { - case 0: /* SUCCESS */ - /* remove volume just processed */ - node = volume_node_list; - rc = evms_cs_remove_logical_node_from_list - (&volume_node_list, node); - if (rc) - break; - /* put volume on global list */ - rc = evms_cs_add_logical_node_to_list(discover_list, - node); - break; - case -EVMS_ASSOCIATIVE_FEATURE: - /* put all "associative" features on their own list */ - rc = edef_isolate_nodes_by_type - (ISOLATE_ASSOCIATIVE_FEATURES, &volume_node_list, - associative_feature_list, 0, 0); - break; - default: /* FATAL ERROR */ - /* delete each node remaining in the list */ - if (volume_node_list) { - LOG_ERROR("encountered fatal error building volume '%s'\n", - volume_node_list->volume_info->volume_name); - } - while (volume_node_list) { - node = volume_node_list; - edef_delete_node(&volume_node_list, - node, rc, "EVMS feature"); - } - rc = 0; - break; - } - if (rc) - break; - } - return rc; -} - -static int -edef_process_associative_volumes(struct evms_logical_node - **associative_feature_list, - struct evms_logical_node **discover_list) -{ - int rc = 0; - struct evms_logical_node *node; - - while (*associative_feature_list) { - node = *associative_feature_list; - /* remove this node from associative feature list */ - rc = evms_cs_remove_logical_node_from_list - (associative_feature_list, node); - if (rc) - break; - /* put volume on global list */ - rc = evms_cs_add_logical_node_to_list(discover_list, node); - if (rc) - break; - rc = edef_load_feature_header(node); - if (rc) - break; - rc = edef_apply_feature(node, discover_list); - if (rc) - edef_delete_node(discover_list, node, rc, - "Associative feature"); - } - return rc; -} - -static int -edef_check_for_incomplete_volumes(struct evms_logical_node **discover_list) -{ - int rc = 0; - struct evms_logical_node *next_node, *node; - - /* check to see if any incomplete volumes are left around */ - /* if so, delete them. */ - /* complete volumes should not have feature_headers */ - /* hanging off them, if we find any, we know the volume */ - /* is incomplete. */ - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - - if (node->feature_header) { - edef_delete_node(discover_list, node, rc, - "Unexpected feature header"); - } - } - return rc; -} - -/* - * Function: evms_discover_evms_features - * Description: Find features for nodes on the logical partitions list - */ -static int -evms_discover_evms_features(struct evms_logical_node **discover_list) -{ - struct evms_logical_node *associative_feature_list; - int rc = 0; - - LOG_EXTRA("discovering evms volume features...\n"); - - /* initialize "associative" features list */ - associative_feature_list = NULL; - - /* find the bottom features */ - rc = edef_find_first_features(discover_list); -#ifdef LOCAL_DEBUG - display_discover_list(*discover_list, "after 1st features hdr"); -#endif - if (!rc) - /* process EVMS volumes here */ - rc = edef_process_evms_volumes(discover_list, - &associative_feature_list); -#ifdef LOCAL_DEBUG - display_discover_list(*discover_list, "after evms volumes"); -#endif - if (!rc) - /* process "associative" features here */ - rc = edef_process_associative_volumes(&associative_feature_list, - discover_list); -#ifdef LOCAL_DEBUG - display_discover_list(*discover_list, "after associatives"); -#endif - if (!rc) - /* check for incomplete volumes */ - rc = edef_check_for_incomplete_volumes(discover_list); - - return rc; -} - -/* - * function: eelv_assign_volume_minor - * - * This is a support function for evms_export_logical_volumes. - * This routine assigns a specific minor number to a volume. It - * also performs the remaining steps to make this volume visible - * and usable to the kernel. - * - */ -static int -eelv_assign_volume_minor(struct evms_logical_node *node, int minor) -{ - struct evms_logical_volume *volume; - - /* initialize the logical_node entry in the volume array */ - volume = &evms_logical_volumes[minor]; - volume->name = kmalloc(strlen(EVMS_GET_NODE_NAME(node)) + 1, GFP_KERNEL); - if (!volume->name) { - return -ENOMEM; - } - strcpy(volume->name, EVMS_GET_NODE_NAME(node)); - volume->node = node; - - /* copy flags from top level node into volume structure */ - volume->flags = node->flags; - - /* check for read-only volume */ - if (volume->flags & EVMS_VOLUME_READ_ONLY) { - set_device_ro(MKDEV(EVMS_MAJOR, minor), 1); - } - - /* adjust volume size based on hardsector size */ - node->total_vsectors &= ~((node->hardsector_size >> - EVMS_VSECTOR_SIZE_SHIFT) - 1); - - /* initialize the global device arrays */ - blksize_size[EVMS_MAJOR][minor] = node->block_size; - hardsect_size[EVMS_MAJOR][minor] = node->hardsector_size; - blk_size[EVMS_MAJOR][minor] = (int) (node->total_vsectors >> 1); - - /* register this volume with devfs */ - volume->devfs_handle = devfs_register(evms_dir_devfs_handle, - volume->name, DEVFS_FL_DEFAULT, - EVMS_MAJOR, minor, - S_IFBLK|S_IRUGO|S_IWUGO, - &evms_fops, NULL); - - evms_volumes++; - - LOG_DEFAULT("Exporting EVMS Volume(%u,%u) from \"%s%s\".\n", - EVMS_MAJOR, minor, EVMS_DEV_NODE_PATH, volume->name); - return 0; -} - -/* - * function: eelv_check_for_duplicity - * - * This is a support function for evms_export_logical_volumes. - * This routine compares the serial number in the top most node - * in the volume to the list of currently exported volumes. If - * this volumes serial number is found in the list then we know - * this volume is a duplicate and it is then delete. - * - */ -static void -eelv_check_for_duplicity(struct evms_logical_node **discover_list) -{ - struct evms_logical_node *next_node, *node; - struct evms_logical_volume *lv; - int i, is_dup; - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - - is_dup = FALSE; - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - lv = &evms_logical_volumes[i]; - /* only check exported volumes */ - if (lv->node) { - char *type_ptr = NULL; - - /* check for duplicate pointer */ - if (node == lv->node) { - is_dup = TRUE; - type_ptr = "pointer"; - /* check for duplicate node */ - } else if (!strcmp(node->name, lv->node->name)) { - is_dup = TRUE; - type_ptr = "node"; - } - if (is_dup == TRUE) { - evms_cs_remove_logical_node_from_list - (discover_list, node); - LOG_DETAILS("deleting duplicate %s to " - "EVMS volume(%u,%u,%s)...\n", - type_ptr, EVMS_MAJOR, i, - EVMS_GET_NODE_NAME(node)); - /* forget duplicate */ - break; - } - } - } - } -} - -/* - * function: eelv_reassign_soft_deleted_volume_minors - * - * This is a support function for evms_export_logical_volumes. - * This routine reassigns minor numbers to rediscovered "soft" - * deleted volumes. - * - */ -static void -eelv_reassign_soft_deleted_volume_minors(struct evms_logical_node - **discover_list) -{ - struct evms_logical_node *next_node, *node; - struct evms_logical_volume *lv; - int rc, i, flags; - char *name; - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - lv = &evms_logical_volumes[i]; - /* only check soft deleted volumes: - * they have a non-NULL name. - */ - if (lv->flags & EVMS_VOLUME_SOFT_DELETED) { - if (!strcmp(EVMS_GET_NODE_NAME(node), lv->name)) { - /* reassign requested minor */ - evms_cs_remove_logical_node_from_list(discover_list, - node); - LOG_DEFAULT("Re"); - /* free the previously used name */ - name = lv->name; - lv->name = NULL; - /* clear the EVMS_VOLUME_SOFT_DELETED flag */ - flags = lv->flags; - lv->flags = 0; - rc = eelv_assign_volume_minor(node, i); - if (rc) { - DELETE(node); - lv->node = NULL; - lv->name = name; - lv->flags = flags; - } else { - kfree(name); - } - break; - } - } - } - } -} - -/* - * function: eelv_assign_evms_volume_minors - * - * This is a support function for evms_export_logical_volumes. - * This routine assigns minor numbers to new evms volumes. If - * the specified minor is already in use, the requested minor - * is set to 0, and will be assigned next available along with - * any remaining volumes at the end of evms_export_logical_volumes. - * - */ -static void -eelv_assign_evms_volume_minors(struct evms_logical_node **discover_list) -{ - struct evms_logical_node *next_node, *node, *lv_node; - unsigned int requested_minor; - int rc, lv_flags; - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - - /* only process evms volumes */ - if (!(node->flags & EVMS_VOLUME_FLAG)) { - continue; - } - - /* is there a requested minor? */ - requested_minor = node->volume_info->volume_minor; - if (!requested_minor) { - continue; - } - - lv_flags = 0; - lv_node = NULL; - - /* check range of requested minor */ - if (requested_minor >= MAX_EVMS_VOLUMES) { - lv_node = node; - } else { - struct evms_logical_volume *lv; - lv = &evms_logical_volumes[requested_minor]; - lv_node = lv->node; - lv_flags = lv->flags; - } - - if (!lv_node && !(lv_flags & EVMS_VOLUME_SOFT_DELETED)) { - /* assign requested minor */ - evms_cs_remove_logical_node_from_list(discover_list, - node); - rc = eelv_assign_volume_minor(node, requested_minor); - if (rc) { - DELETE(node); - } - } else { - LOG_WARNING("EVMS volume(%s) requesting invalid/in-use " - "minor(%d), assigning next available!\n", - node->volume_info->volume_name, - requested_minor); - /* requested minor is already - * in use, defer assignment - * until later. - */ - node->volume_info->volume_minor = 0; - } - } -} - -/* - * function: eelv_assign_remaining_evms_volume_minors - * - * This is a support function for evms_export_logical_volumes. - * This routine assigns minor numbers to new evms volumes that - * have no/conflicting minor assignments. This function will - * search from high(255) minor values down, for the first available - * minor. Searching high to low minimizes the possibility of - * conflicting evms volumes causing "compatibility" minor - * assignments to shift from expected assignments. - * - */ -static void -eelv_assign_remaining_evms_volume_minors(struct evms_logical_node - **discover_list) -{ - struct evms_logical_node *next_node, *node; - int requested_minor, rc; - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - - /* only process evms volumes */ - /* all remaining evms volumes should now - * have a minor value of 0, meaning they - * had no minor assignment, or their minor - * assignment conflicted with an existing - * minor assignment. - */ - if (node->flags & EVMS_VOLUME_FLAG) { - evms_cs_remove_logical_node_from_list(discover_list, - node); - /* find next available minor number */ - for (requested_minor = 255; - requested_minor > 0 && - (evms_logical_volumes[requested_minor].node || - evms_logical_volumes[requested_minor].name); - requested_minor--) ; - /* check range of assigned minor */ - if (!requested_minor) { - LOG_CRITICAL("no more minor numbers available " - "for evms volumes!!!!\n"); - DELETE(node); - } else { - /* assign requested minor */ - rc = eelv_assign_volume_minor(node, requested_minor); - if (rc) { - DELETE(node); - } - } - } - } -} - -/* - * function: eelv_assign_remaining_volume_minors - * - * This is a support function for evms_export_logical_volumes. - * This routine assigns minor numbers to all remaining unassigned - * volumes. Minor numbers are assigned on an availability - * basis. The first free minor number is used in the assignment. - * - */ -static void -eelv_assign_remaining_volume_minors(struct evms_logical_node **discover_list) -{ - struct evms_logical_node *node; - int minor, rc; - - while (*discover_list) { - node = *discover_list; - evms_cs_remove_logical_node_from_list(discover_list, node); - - /* find next available minor number */ - for (minor = 1; - minor < MAX_EVMS_VOLUMES && - (evms_logical_volumes[minor].node || - evms_logical_volumes[minor].name); - minor++) ; - - if (minor >= MAX_EVMS_VOLUMES) { - LOG_CRITICAL("no more minor numbers available for " - "compatibility volumes!!!!\n"); - DELETE(node); - } else { - /* assign minor */ - rc = eelv_assign_volume_minor(node, minor); - if (rc) { - DELETE(node); - } - } - } -} - -/* - * function: eelv_check_for_unreassign_soft_deleted_volume - * - * This is a support function for evms_export_logical_volumes. - * This routine reports any "soft deleted" volumes that were not - * found after a rediscovery. - */ -static void -eelv_check_for_unreassign_soft_deleted_volume(void) -{ - struct evms_logical_volume *lv; - int i; - - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - lv = &evms_logical_volumes[i]; - /* only check soft deleted volumes: - * they have a NULL node ptr & - * they have a non-NULL name. - */ - if (lv->flags & EVMS_VOLUME_SOFT_DELETED) { - if (is_open(i)) - lv->flags |= EVMS_VOLUME_CORRUPT; - LOG_ERROR("error: rediscovery failed to find %smounted " - "'soft deleted' volume(%u,%u,%s)...\n", - ((lv->flags & EVMS_VOLUME_CORRUPT) ? "" : "un"), - EVMS_MAJOR, i, lv->name); - if (lv->flags & EVMS_VOLUME_CORRUPT) { - LOG_ERROR(" flagging volume(%u,%u,%s) as " - "CORRUPT!\n", EVMS_MAJOR, i, lv->name); - } else { - LOG_ERROR(" releasing minor(%d) used by " - "volume(%s)!\n", i, lv->name); - /* clear logical volume structure - * for this volume so it may be - * reused. - */ - kfree(lv->name); - lv->name = NULL; - lv->flags = 0; - } - } - } -} - -static void -eelv_unquiesce_volumes(void) -{ - int i; - - /* check each volume array entry */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_logical_volume *volume; - - volume = &evms_logical_volumes[i]; - /* is this volume "quiesced" ? */ - if (volume->quiesced) { - int rc = 1; - if (volume->node) { - /* "unquiesce" it */ - struct inode inode; - struct evms_quiesce_vol_pkt qv; - - qv.command = qv.status = 0; - qv.do_vfs = 0; - qv.minor = i; - rc = evms_quiesce_volume(volume, &inode, NULL, - &qv); - } - /* Wake up any waiters */ - if (rc) { - /* clear the flag */ - volume->quiesced = 0; - /* wake up the waiters */ - if (waitqueue_active(&volume->wait_queue)) - wake_up(&volume->wait_queue); -#ifdef VFS_PATCH_PRESENT - /* unquiesce VFS if quiesced */ - if (volume->vfs_quiesced) { - /* VFS function call to unlock the filesystem */ - unlockfs(MKDEV(EVMS_MAJOR, i)); - volume->vfs_quiesced = FALSE; - } -#endif - } - } - } -} - -/* - * Function: evms_export_logical_volumes - * - * This function is called from evms_discover_volumes. It - * check for duplicate volumes, assigns minor values to evms - * volumes, and assigns minor values to the remaining volumes. - * In addition to assigning minor values to each volume this - * function also completes the final steps necessary to allow - * the volumes to be using by the operating system. - */ -static void -evms_export_logical_volumes(struct evms_logical_node **discover_list) -{ - LOG_EXTRA("exporting EVMS logical volumes...\n"); - - eelv_check_for_duplicity(discover_list); - - eelv_reassign_soft_deleted_volume_minors(discover_list); - - eelv_assign_evms_volume_minors(discover_list); - - eelv_assign_remaining_evms_volume_minors(discover_list); - - eelv_assign_remaining_volume_minors(discover_list); - - eelv_check_for_unreassign_soft_deleted_volume(); - - /* "unquiesce" any "quiesced" volumes */ - eelv_unquiesce_volumes(); -} - -static int -edv_populate_discover_list(struct evms_list_node *src_list, - struct evms_logical_node **trg_list, - struct evms_rediscover_pkt *discover_parms) -{ - int rc = 0, i, move_node, use_all_disks = FALSE; - struct evms_list_node *src_node; - struct evms_logical_node *disk_node = NULL; - - /* if no discover parameters are specified */ - /* copy ALL the disk nodes into the */ - /* discovery list. */ - if ((discover_parms == NULL) || - (discover_parms->drive_count == REDISCOVER_ALL_DEVICES)) - use_all_disks = TRUE; - - if (!use_all_disks) { - LOG_DEBUG("discovering %d disks:\n", discover_parms->drive_count); - for (i = 0; i < discover_parms->drive_count; i++) { - disk_node = DEV_HANDLE_TO_NODE(discover_parms->drive_array[i]); - LOG_DEBUG(" disk %d: %s\n", i, disk_node->name); - } - } - - /* copy the disk nodes specified in the */ - /* discover_parms over to a discover list */ - src_node = src_list; - while (src_node) { - move_node = use_all_disks; - if (move_node == FALSE) { - /* check the rediscovery array */ - for (i = 0; i < discover_parms->drive_count; i++) { - disk_node = - DEV_HANDLE_TO_NODE(discover_parms-> - drive_array[i]); - if (disk_node == src_node->item) { - move_node = TRUE; - break; - } - } - } - /* check to see if we want this node */ - if (move_node == TRUE) - evms_cs_add_logical_node_to_list(trg_list, - (struct - evms_logical_node *) - src_node->item); - /* advance to next struct evms_list_node */ - src_node = src_node->next; - } - return rc; -} - -static int -evms_discover_volumes(struct evms_rediscover_pkt *discover_parms) -{ - int rc = 0; - struct evms_logical_node *discover_list = NULL; - - evms_discover_logical_disks(&discover_list); - if (evms_global_device_list) { - /* move the appropriate disk nodes, based on */ - /* on the discover parameters, onto the */ - /* discover list for the partition managers */ - /* to process */ - edv_populate_discover_list(evms_global_device_list, - &discover_list, discover_parms); - } - if (discover_list) { -#ifdef LOCAL_DEBUG - display_discover_list(discover_list, "after dev mgrs"); -#endif - evms_discover_logical_partitions(&discover_list); - } - if (discover_list) { -#ifdef LOCAL_DEBUG - display_discover_list(discover_list, "after seg mgrs"); -#endif - evms_discover_volume_groups(&discover_list); - } - if (discover_list) { -#ifdef LOCAL_DEBUG - display_discover_list(discover_list, "after reg mgrs"); -#endif - evms_discover_evms_features(&discover_list); - } - if (discover_list) { -#ifdef LOCAL_DEBUG - display_discover_list(discover_list, "after features"); -#endif - evms_export_logical_volumes(&discover_list); - evms_cs_signal_event(EVMS_EVENT_END_OF_DISCOVERY); - } - return rc; -} - -/* function: evms_notify_reboot - * - * this function gets called at shutdown time and is used - * to remove any evms controlled volumes from memory, thus - * allowing any plugins needing to flush internal caches - * to do so. - */ -int -evms_notify_reboot(struct notifier_block *this, unsigned long code, void *x) -{ - int i; - struct evms_logical_volume *volume; - - switch (code) { - case SYS_DOWN: - case SYS_HALT: - case SYS_POWER_OFF: - LOG_DEFAULT("stopping all evms controlled volumes.\n"); - - /* quiesce all volumes */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_quiesce_vol_pkt qv; - struct inode inode; - - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - qv.command = 1; // quiesce - qv.minor = i; - qv.status = 0; // reset status - qv.do_vfs = 0; - evms_quiesce_volume(volume, &inode, NULL, &qv); - } - /* delete all volumes - * - * to ensure this work under the - * most circumstances, a "soft" - * delete will be done. this will - * handle the strange case of a - * volume still being mounted. - */ - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_delete_vol_pkt dv; - - volume = &evms_logical_volumes[i]; - if (!volume->node) - continue; - /* only delete quiesced volumes */ - if (!volume->quiesced) - continue; - /* delete the volume from memory. - * do a 'soft' delete if volume - * is mounted, and 'hard' delete - * if it is not. - */ - dv.command = (is_open(i)) ? 0 : 1; - dv.minor = i; - dv.status = 0; - evms_delete_volume(volume, &dv); - } - } - return NOTIFY_DONE; -} - -static struct notifier_block evms_notifier = { - .notifier_call = evms_notify_reboot, - .next = NULL, - .priority = INT_MAX, /* before any real devices */ -}; - -/* - * Function: find_root_fs_dev - * If "root=/dev/evms/???" was specified on the kernel command line, and devfs - * is not enabled, we need to determine the appropriate minor number for the - * specified volume for the root fs. - */ -static void -find_root_fs_dev(void) -{ -#ifndef MODULE - char root_name[64] = { 0 }; - char *name; - int i; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,18) - strncpy(root_name, root_device_name, 63); -#else - get_root_device_name(root_name); -#endif - - if (!strncmp(root_name, EVMS_DIR_NAME "/", strlen(EVMS_DIR_NAME) + 1)) { - name = &root_name[strlen(EVMS_DIR_NAME) + 1]; - - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - if (evms_logical_volumes[i].name && - !strncmp(name, evms_logical_volumes[i].name, - strlen(evms_logical_volumes[i].name))) { - ROOT_DEV = MKDEV(EVMS_MAJOR, i); - return; - } - } - } -#endif -} - -/* - * Function: bh_cache_ctor - * this function initializes the b_wait field in the buffer heads - * in our private buffer head pool. - */ -static void -io_notify_cache_ctor(void *foo, kmem_cache_t * cachep, unsigned long flags) -{ - if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { - io_notify_t *io_notify = (io_notify_t *) foo; - memset(io_notify, 0, sizeof (*io_notify)); - } -} - -/* - * Function: bh_cache_ctor - * this function initializes the b_wait field in the buffer heads - * in our private buffer head pool. - */ -static void -bh_cache_ctor(void *foo, kmem_cache_t * cachep, unsigned long flags) -{ - if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { - struct buffer_head *bh = (struct buffer_head *) foo; - memset(bh, 0, sizeof (*bh)); - init_waitqueue_head(&bh->b_wait); - } -} - -/* - * Function: evms_init_module - * This function runs once at system initialization. - */ -static int __init -evms_init_module(void) -{ - int rc = -ENOMEM, i; - int *evms_blocksizes; - - LOG_DEFAULT("EVMS v%d.%d.%d initializing .... info level(%d).\n", - EVMS_MAJOR_VERSION, EVMS_MINOR_VERSION, - EVMS_PATCHLEVEL_VERSION, evms_info_level); - - /* Initialize memory management counters */ - atomic_set(&evms_allocs, 0); - atomic_set(&evms_logical_nodes, 0); - - /* Initialize the io_notify_entry pool */ - evms_io_notify_pool = evms_cs_create_pool(sizeof (io_notify_t), - "EVMS IO Notify", - io_notify_cache_ctor, NULL); - if (!evms_io_notify_pool) { - LOG_CRITICAL("can't allocate memory for I/O Notify pool.\n"); - goto error; - } - - /* Initialize the "public" buffer_head pool */ - evms_bh_pool = evms_cs_create_pool(sizeof (struct buffer_head), - "EVMS BH", bh_cache_ctor, NULL); - if (!evms_bh_pool) { - LOG_CRITICAL("can't allocate memory for BH pool.\n"); - goto error; - } - - /* Allocate the EVMS blk_size array */ - evms_blocksizes = kmalloc(MAX_EVMS_VOLUMES * sizeof (int), GFP_KERNEL); - if (!evms_blocksizes) { - LOG_CRITICAL("can't allocate memory for blk_size array.\n"); - goto error; - } - memset(evms_blocksizes, 0, MAX_EVMS_VOLUMES * sizeof (int)); - blk_size[EVMS_MAJOR] = evms_blocksizes; - - /* Allocate the EVMS blksize_size array */ - evms_blocksizes = kmalloc(MAX_EVMS_VOLUMES * sizeof (int), GFP_KERNEL); - if (!evms_blocksizes) { - LOG_CRITICAL("can't allocate memory for blksize_size array.\n"); - goto error; - } - memset(evms_blocksizes, 0, MAX_EVMS_VOLUMES * sizeof (int)); - blksize_size[EVMS_MAJOR] = evms_blocksizes; - - /* Allocate the EVMS hardsect_size array */ - evms_blocksizes = kmalloc(MAX_EVMS_VOLUMES * sizeof (int), GFP_KERNEL); - if (!evms_blocksizes) { - LOG_CRITICAL("can't allocate memory for hardsect_size array.\n"); - goto error; - } - memset(evms_blocksizes, 0, MAX_EVMS_VOLUMES * sizeof (int)); - hardsect_size[EVMS_MAJOR] = evms_blocksizes; - - - /* Allocate the logical volume array */ - evms_logical_volumes = kmalloc(sizeof (struct evms_logical_volume) * - MAX_EVMS_VOLUMES, GFP_KERNEL); - if (!evms_logical_volumes) { - LOG_CRITICAL("can't allocate memory for logical volume array.\n"); - goto error; - } - - /* initialize the logical volume array entries */ - memset(evms_logical_volumes, 0, - sizeof (struct evms_logical_volume) * MAX_EVMS_VOLUMES); - for (i = 1; i < MAX_EVMS_VOLUMES; i++) { - struct evms_logical_volume *volume = &evms_logical_volumes[i]; - atomic_set(&volume->opens, 0); - atomic_set(&volume->requests_in_progress, 0); - init_waitqueue_head(&volume->wait_queue); - blk_queue_make_request(&volume->request_queue, evms_make_request_fn); - volume->request_queue.queuedata = volume; - } - - - /* Register the block device */ - rc = devfs_register_blkdev(EVMS_MAJOR, EVMS_DIR_NAME, &evms_fops); - if (rc) { - LOG_CRITICAL("error(%d) calling devfs_register_blkdev().\n", rc); - goto error; - } - - /* Register with devfs. A NULL return is not fatal. */ - evms_dir_devfs_handle = devfs_mk_dir(NULL, EVMS_DIR_NAME, NULL); - if (evms_dir_devfs_handle) { - evms_blk_devfs_handle = devfs_register(evms_dir_devfs_handle, - EVMS_DEV_NAME, DEVFS_FL_DEFAULT, - EVMS_MAJOR, 0, - S_IFBLK|S_IRUGO|S_IWUGO, - &evms_fops, NULL); - if (!evms_blk_devfs_handle) { - LOG_DETAILS("NULL return from devfs_register() for \"%s\"\n", - EVMS_DEV_NAME); - } - } - - read_ahead[EVMS_MAJOR] = 4096; - blk_dev[EVMS_MAJOR].queue = evms_find_queue; - blk_queue_make_request(BLK_DEFAULT_QUEUE(EVMS_MAJOR), evms_make_request_fn); - -#ifdef CONFIG_PROC_FS - evms_cs_get_evms_proc_dir(); - if (evms_proc_dir) { - create_proc_read_entry("info", 0, evms_proc_dir, - evms_info_read_proc, NULL); - create_proc_read_entry("plugins", 0, evms_proc_dir, - evms_plugins_read_proc, NULL); - create_proc_read_entry("volumes", 0, evms_proc_dir, - evms_volumes_read_proc, NULL); - } - evms_table_header = register_sysctl_table(dev_dir_table, 1); -#endif - - /* Register for reboot notification */ - register_reboot_notifier(&evms_notifier); - -#if defined(CONFIG_PPC64) || defined(CONFIG_SPARC64) || defined(CONFIG_X86_64) - /* Register evms 32bit ioctl handlers. UGLY!!! */ - lock_kernel(); - register_ioctl32_conversion(EVMS_GET_IOCTL_VERSION,NULL); - register_ioctl32_conversion(EVMS_GET_VERSION,NULL); - register_ioctl32_conversion(EVMS_GET_INFO_LEVEL,NULL); - register_ioctl32_conversion(EVMS_SET_INFO_LEVEL,NULL); - register_ioctl32_conversion(EVMS_REDISCOVER_VOLUMES_32, evms_rediscover); - register_ioctl32_conversion(EVMS_DELETE_VOLUME,NULL); - register_ioctl32_conversion(EVMS_PLUGIN_IOCTL_32, evms_plugin_ioctl); - register_ioctl32_conversion(EVMS_PROCESS_NOTIFY_EVENT,NULL); - register_ioctl32_conversion(EVMS_GET_LOGICAL_DISK,NULL); - register_ioctl32_conversion(EVMS_GET_LOGICAL_DISK_INFO,NULL); - register_ioctl32_conversion(EVMS_SECTOR_IO_32, evms_sector_io); - register_ioctl32_conversion(EVMS_GET_MINOR,NULL); - register_ioctl32_conversion(EVMS_GET_VOLUME_DATA,NULL); - register_ioctl32_conversion(EVMS_GET_PLUGIN,NULL); - register_ioctl32_conversion(EVMS_COMPUTE_CSUM_32, evms_compute_csum); - register_ioctl32_conversion(EVMS_GET_BMAP,NULL); - register_ioctl32_conversion(EVMS_CHECK_MOUNT_STATUS,NULL); - register_ioctl32_conversion(EVMS_CHECK_OPEN_STATUS,NULL); - register_ioctl32_conversion(EVMS_GET_VOL_STRIPE_INFO,NULL); - unlock_kernel(); -#endif - -done: - return rc; - -error: - if (evms_logical_volumes) { - kfree(evms_logical_volumes); - evms_logical_volumes = NULL; - } - if (hardsect_size[EVMS_MAJOR]) { - kfree(hardsect_size[EVMS_MAJOR]); - hardsect_size[EVMS_MAJOR] = NULL; - } - if (blksize_size[EVMS_MAJOR]) { - kfree(blksize_size[EVMS_MAJOR]); - blksize_size[EVMS_MAJOR] = NULL; - } - if (blk_size[EVMS_MAJOR]) { - kfree(blk_size[EVMS_MAJOR]); - blk_size[EVMS_MAJOR] = NULL; - } - if (evms_bh_pool) { - evms_cs_destroy_pool(evms_bh_pool); - evms_bh_pool = NULL; - } - if (evms_io_notify_pool) { - evms_cs_destroy_pool(evms_io_notify_pool); - evms_io_notify_pool = NULL; - } - goto done; -} - -/* - * Function: evms_exit_module - * This function runs once when the EVMS core module is unloaded. - */ -static void __exit -evms_exit_module(void) -{ - LOG_DEFAULT("EVMS v%d.%d.%d unloading ....\n", EVMS_MAJOR_VERSION, - EVMS_MINOR_VERSION, EVMS_PATCHLEVEL_VERSION); - -#if defined(CONFIG_PPC64) || defined(CONFIG_SPARC64) || defined(CONFIG_X86_64) - /* Unregister evms 32bit ioctl handlers */ - lock_kernel(); - unregister_ioctl32_conversion(EVMS_GET_IOCTL_VERSION); - unregister_ioctl32_conversion(EVMS_GET_VERSION); - unregister_ioctl32_conversion(EVMS_GET_INFO_LEVEL); - unregister_ioctl32_conversion(EVMS_SET_INFO_LEVEL); - unregister_ioctl32_conversion(EVMS_REDISCOVER_VOLUMES_32); - unregister_ioctl32_conversion(EVMS_DELETE_VOLUME); - unregister_ioctl32_conversion(EVMS_PLUGIN_IOCTL_32); - unregister_ioctl32_conversion(EVMS_PROCESS_NOTIFY_EVENT); - unregister_ioctl32_conversion(EVMS_GET_LOGICAL_DISK); - unregister_ioctl32_conversion(EVMS_GET_LOGICAL_DISK_INFO); - unregister_ioctl32_conversion(EVMS_SECTOR_IO_32); - unregister_ioctl32_conversion(EVMS_GET_MINOR); - unregister_ioctl32_conversion(EVMS_GET_VOLUME_DATA); - unregister_ioctl32_conversion(EVMS_GET_PLUGIN); - unregister_ioctl32_conversion(EVMS_COMPUTE_CSUM_32); - unregister_ioctl32_conversion(EVMS_GET_BMAP); - unregister_ioctl32_conversion(EVMS_CHECK_MOUNT_STATUS); - unregister_ioctl32_conversion(EVMS_CHECK_OPEN_STATUS); - unregister_ioctl32_conversion(EVMS_GET_VOL_STRIPE_INFO); - unlock_kernel(); -#endif - - unregister_reboot_notifier(&evms_notifier); - -#ifdef CONFIG_PROC_FS - unregister_sysctl_table(evms_table_header); - if (evms_proc_dir) { - remove_proc_entry("volumes", evms_proc_dir); - remove_proc_entry("plugins", evms_proc_dir); - remove_proc_entry("info", evms_proc_dir); - remove_proc_entry("evms", NULL); - } -#endif - - /* Clean up the default queue. */ - blk_dev[EVMS_MAJOR].queue = NULL; - blk_queue_make_request(BLK_DEFAULT_QUEUE(EVMS_MAJOR), NULL); - - /* Unregister with devfs */ - devfs_unregister(evms_dir_devfs_handle); - - /* Unregister the block device */ - devfs_unregister_blkdev(EVMS_MAJOR, EVMS_DIR_NAME); - - /* Deallocate logical volumes array */ - kfree(evms_logical_volumes); - - /* Deallocate device arrays */ - kfree(blk_size[EVMS_MAJOR]); - kfree(blksize_size[EVMS_MAJOR]); - kfree(hardsect_size[EVMS_MAJOR]); - blk_size[EVMS_MAJOR] = NULL; - blksize_size[EVMS_MAJOR] = NULL; - hardsect_size[EVMS_MAJOR] = NULL; - read_ahead[EVMS_MAJOR] = 0; - - /* Destroy buffer head pool */ - evms_cs_destroy_pool(evms_bh_pool); - - /* Destroy io notify pool */ - evms_cs_destroy_pool(evms_io_notify_pool); -} - -/* - * Function: evms_init_discover - * If EVMS is statically built into the kernel, this function will be called - * to perform an initial volume discovery. - */ -int __init -evms_init_discover(void) -{ - /* go find volumes */ - evms_discover_volumes(NULL); - - /* Check if the root fs is on EVMS */ - if (MAJOR(ROOT_DEV) == EVMS_MAJOR) { - find_root_fs_dev(); - } - - return 0; -} - -static int __init -evms_boot_info_level(char *str) -{ - int evms_boot_info_level = (int) simple_strtoul(str, NULL, 10); - if (evms_boot_info_level) { - evms_info_level = evms_boot_info_level; - } - return 1; -} - -__setup("evms_info_level=", evms_boot_info_level); -module_init(evms_init_module); -module_exit(evms_exit_module); -__initcall(evms_init_discover); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms_bbr.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms_bbr.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms_bbr.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms_bbr.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1873 +0,0 @@ -/* -*- linux-c -*- */ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* linux/driver/evms/evms_bbr.c - * - * EVMS - Bad Block Relocation (BBR) Feature Plugin - * - * BBR feature is designed to remap I/O write failures to another safe location - * on disk. Note that most disk drives have BBR built into them, this means - * that our software BBR will be only activated when all hardware BBR - * replacement sectors have been used. - */ - -#define LOG_PREFIX "bbr: " - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* API prototypes. */ -static int bbr_discover(struct evms_logical_node ** discover_list); -static int bbr_delete(struct evms_logical_node * node); -static void bbr_read(struct evms_logical_node * node, struct buffer_head * bh); -static void bbr_write(struct evms_logical_node * node, struct buffer_head * bh); -static int bbr_ioctl(struct evms_logical_node * bbr_node, struct inode * inode, - struct file * file, unsigned int cmd, unsigned long arg); -static int bbr_direct_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); -static int bbr_init_io(struct evms_logical_node * bbr_node, int io_flag, - u64 startLSN, u64 nr_sects, void * bufptr); - -/* Other function prototypes. */ -static int bbr_create_pools(void); -static u32 bbr_table_to_remap_list(struct bbr_private * bbr_id); -static void bbr_io_handler(void * void_data); -static void bbr_free_private(struct bbr_private * bbr_id); -static inline void bbr_list_add(struct bbr_private * bbr_id); - -/* List of all BBR nodes. */ -static struct bbr_private * bbr_instances = NULL; - -/* Data pertaining to the I/O thread. */ -static struct evms_thread * bbr_io_thread = NULL; -static spinlock_t bbr_io_list_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(bbr_io_list); - -/* Global pools for bbr_io_buf's and bbr_remap's. */ -kmem_cache_t * bbr_io_buf_slab; -mempool_t * bbr_io_buf_pool; -kmem_cache_t * bbr_bh_slab; -mempool_t * bbr_bh_pool; -kmem_cache_t * bbr_remap_slab; -mempool_t * bbr_remap_pool; - -/* Plugin function table and header. */ -static struct evms_plugin_fops function_table = { - .discover = bbr_discover, - .delete = bbr_delete, - .read = bbr_read, - .write = bbr_write, - .init_io = bbr_init_io, - .ioctl = bbr_ioctl, - .direct_ioctl = bbr_direct_ioctl -}; - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_FEATURE, - EVMS_BBR_FEATURE_ID), - .version = { - .major = EVMS_BBR_VERSION_MAJOR, - .minor = EVMS_BBR_VERSION_MINOR, - .patchlevel = EVMS_BBR_VERSION_PATCHLEVEL - }, - .required_services_version = { - .major = EVMS_BBR_COMMON_SERVICES_MAJOR, - .minor = EVMS_BBR_COMMON_SERVICES_MINOR, - .patchlevel = EVMS_BBR_COMMON_SERVICES_PATCHLEVEL - }, - .fops = &function_table -}; - -/** - * le_meta_data_to_cpu - * - * Convert bbr meta data from on-disk (LE) format - * to the native cpu endian format. - */ -void le_meta_data_to_cpu(struct evms_bbr_metadata * md) -{ - md->signature = le32_to_cpup(&md->signature); - md->crc = le32_to_cpup(&md->crc); - md->block_size = le32_to_cpup(&md->block_size); - md->flags = le32_to_cpup(&md->flags); - md->sequence_number = le64_to_cpup(&md->sequence_number); - md->start_sect_bbr_table = le64_to_cpup(&md->start_sect_bbr_table); - md->nr_sects_bbr_table = le64_to_cpup(&md->nr_sects_bbr_table); - md->start_replacement_sect = le64_to_cpup(&md->start_replacement_sect); - md->nr_replacement_blks = le64_to_cpup(&md->nr_replacement_blks); -} - -/** - * le_bbr_table_sector_to_cpu - * - * Convert bbr meta data from on-disk (LE) format - * to the native cpu endian format. - */ -void le_bbr_table_sector_to_cpu(struct evms_bbr_table * p) -{ - int i; - p->signature = le32_to_cpup(&p->signature); - p->crc = le32_to_cpup(&p->crc); - p->sequence_number = le32_to_cpup(&p->sequence_number); - p->in_use_cnt = le32_to_cpup(&p->in_use_cnt); - for ( i = 0; i < EVMS_BBR_ENTRIES_PER_SECT; i++ ) { - p->entries[i].bad_sect = - le64_to_cpup(&p->entries[i].bad_sect); - p->entries[i].replacement_sect = - le64_to_cpup(&p->entries[i].replacement_sect); - } -} - -/** - * cpu_bbr_table_sector_to_le - * - * Convert bbr meta data from cpu endian format to on-disk (LE) format - */ -void cpu_bbr_table_sector_to_le(struct evms_bbr_table * p, - struct evms_bbr_table * le) -{ - int i; - le->signature = cpu_to_le32p(&p->signature); - le->crc = cpu_to_le32p(&p->crc); - le->sequence_number = cpu_to_le32p(&p->sequence_number); - le->in_use_cnt = cpu_to_le32p(&p->in_use_cnt); - for ( i = 0; i < EVMS_BBR_ENTRIES_PER_SECT; i++ ) { - le->entries[i].bad_sect = - cpu_to_le64p(&p->entries[i].bad_sect); - le->entries[i].replacement_sect = - cpu_to_le64p(&p->entries[i].replacement_sect); - } -} - -#ifdef EVMS_BBR_DEBUG -static void print_meta_data(struct evms_bbr_metadata * md) -{ - LOG_DEBUG("BBR Metadata Sector:\n" - " signature 0x%08X\n" - " crc 0x%08X\n" - " block_size %u\n" - " start_sect_bbr_table "PFU64"\n" - " nr_sects_bbr_table "PFU64"\n" - " start_replacement_sect "PFU64"\n" - " nr_replacement_blks "PFU64"\n", - md->signature, md->crc, md->block_size, - md->start_sect_bbr_table, md->nr_sects_bbr_table, - md->start_replacement_sect, md->nr_replacement_blks); -} - -static void print_bbr_table_sector(struct evms_bbr_table * p) -{ - int i; - LOG_DEBUG("BBR Table Sector:\n" - " sig 0x%08X\n" - " crc 0x%08X\n" - " sequence %u\n" - " in_use_cnt %u\n" - " Table Entries:\n", - p->signature, p->crc, p->sequence_number, p->in_use_cnt); - for ( i = 0; i < EVMS_BBR_ENTRIES_PER_SECT; i++ ) { - LOG_DEBUG(" [%d] bad_sect: "PFU64" replacement_sect: "PFU64"\n", - i, p->entries[i].bad_sect, - p->entries[i].replacement_sect); - } -} - -void print_binary_tree(struct bbr_runtime_remap * node) -{ - if (node) { - LOG_DEFAULT("["PFU64","PFU64"]\n", node->remap.bad_sect, - node->remap.replacement_sect); - print_binary_tree(node->left); - print_binary_tree(node->right); - } -} - -static void print_remap_list(struct bbr_private * bbr_id) -{ - if (bbr_id->remap_root) { - LOG_DEFAULT("%s for %s\n", __FUNCTION__, bbr_id->node->name); - print_binary_tree(bbr_id->remap_root); - } -} -#endif - -/** - * validate_bbr_table_sector - * - * Check the specified BBR table sector for a valid signature and CRC. - */ -static int validate_bbr_table_sector(struct evms_bbr_table * p) -{ - int rc = 0; - int org_crc, final_crc; - - if ( le32_to_cpup(&p->signature) != EVMS_BBR_TABLE_SIGNATURE ) { - LOG_ERROR("BBR table signature doesn't match!\n"); - LOG_ERROR("Sector has (0x%08X) expected(0x%08X)\n", - le32_to_cpup(&p->signature), - EVMS_BBR_TABLE_SIGNATURE); - rc = -EINVAL; - } else { - if (p->crc) { - org_crc = le32_to_cpup(&p->crc); - p->crc = 0; - final_crc = evms_cs_calculate_crc(EVMS_INITIAL_CRC, p, - sizeof(*p)); - if ( final_crc != org_crc ) { - LOG_ERROR("CRC failed!\n"); - LOG_ERROR("Sector has (0x%08X) calculated(0x%08X)\n", - org_crc, final_crc); - rc = -EINVAL; - } - p->crc = cpu_to_le32p(&org_crc); - } else { - LOG_ERROR("BBR table sector has no CRC!\n"); - rc = -EINVAL; - } - } - if (rc) - BBR_DEBUG_PRINT_TABLE_SECTOR(p); - le_bbr_table_sector_to_cpu(p); - return rc; -} - -/** - * update_invalid_bbr_table_sector - * - * If one copy of a BBR table sector is bad, replace it with the valid copy. - */ -void update_invalid_bbr_table_sector(struct evms_logical_node * node, - struct evms_bbr_table * valid, - struct evms_bbr_table * invalid, - u64 lsn) -{ - int rc; - struct evms_bbr_table * tmp_bbr_table; - - /* Correct the invalid bbr table sector */ - memcpy(invalid, valid, sizeof(struct evms_bbr_table)); - - /* Allocate memory for I/O */ - tmp_bbr_table = kmalloc(sizeof(struct evms_bbr_table), GFP_KERNEL); - if (tmp_bbr_table) { - memset(tmp_bbr_table, 0, sizeof(struct evms_bbr_table)); - cpu_bbr_table_sector_to_le(valid, tmp_bbr_table); - LOG_WARNING("Correcting BBR table sector "PFU64"\n", lsn); - rc = INIT_IO(node, 1, lsn, 1, tmp_bbr_table); - if (rc) { - LOG_ERROR("Could not correct BBR table sector "PFU64".\n", - lsn); - } - kfree(tmp_bbr_table); - } -} - -/** - * validate_bbr_table - * - * Validate the entire range of sectors in the BBR table. - */ -static u32 validate_bbr_table(struct evms_bbr_metadata * md, - struct evms_bbr_table * p) -{ - u32 i, nr_sects; - - nr_sects = md->nr_sects_bbr_table; - - for ( i = 0; i < nr_sects; i++, p++ ) { - if ( validate_bbr_table_sector(p) ) - break; - } - - if ( i != nr_sects ) { - LOG_SERIOUS("Stopped BBR table validation at sector %u.\n", i); - nr_sects = i; - } - LOG_DEBUG("Validated %u BBR table sectors.\n", nr_sects); - return nr_sects; -} - -/** - * validate_bbr_tables - * @node: BBR node to validate. - * @MD1: Primary metadata sector. - * @MD2: Secondary metadata sector. - * @p1: Primary BBR table. - * @p2: Secondary BBR table. - * - * Validate both copies of the BBR table. If one of them is invalid, - * try to correct the errors using the valid copy. - */ -static u32 validate_bbr_tables(struct evms_logical_node * node, - struct evms_bbr_metadata * MD1, - struct evms_bbr_metadata * MD2, - struct evms_bbr_table * p1, - struct evms_bbr_table * p2) -{ - u32 i, rc1, rc2, nr_sects; - - nr_sects = MD1->nr_sects_bbr_table; - if ( nr_sects != MD2->nr_sects_bbr_table ) { - nr_sects = (nr_sects < MD2->nr_sects_bbr_table) ? - nr_sects : MD2->nr_sects_bbr_table; - LOG_SERIOUS("Size of BBR tables don't match. Using %u\n", - nr_sects); - } - - for ( i = 0; i < nr_sects; i++, p1++, p2++ ) { - rc1 = validate_bbr_table_sector(p1); - if (rc1) { - LOG_WARNING("Invalid BBR table sector at "PFU64".\n", - MD1->start_sect_bbr_table + i); - } - rc2 = validate_bbr_table_sector(p2); - if (rc2) { - LOG_WARNING("Invalid BBR table sector at "PFU64".\n", - MD2->start_sect_bbr_table + i); - } - - /* Correct BBR table errors. */ - if (rc1 && rc2) { - /* Cannot fix. */ - break; - } else if (rc1) { - update_invalid_bbr_table_sector(node, p2, p1, - MD1->start_sect_bbr_table + i); - continue; - } else if (rc2) { - update_invalid_bbr_table_sector(node, p1, p2, - MD2->start_sect_bbr_table + i); - continue; - } - - if ( p1->sequence_number != p2->sequence_number ) { - LOG_WARNING("Sequence numbers for BBR table index %u don't match.\n", i); - LOG_WARNING("MD1 sequence_nr=%u, MD2 sequence_nr_2=%u\n", - p1->sequence_number, p2->sequence_number); - if ( p1->sequence_number < p2->sequence_number ) { - update_invalid_bbr_table_sector(node, p2, p1, - MD1->start_sect_bbr_table + i); - } else { - update_invalid_bbr_table_sector(node, p1, p2, - MD2->start_sect_bbr_table + i); - } - } - } - if ( i != nr_sects ) { - LOG_SERIOUS("Stopped validation at sector %u\n", i); - nr_sects = i; - } - LOG_DEBUG("Validated %u BBR table sectors.\n", nr_sects); - return nr_sects; -} - -/** - * validate_meta_data - * - * Check the specified BBR metadata sector for a valid signature and CRC. - */ -static int validate_meta_data(struct evms_bbr_metadata * md) -{ - int org_crc, final_crc; - - BBR_DEBUG_PRINT_META_DATA(md); - - if ( le32_to_cpup(&md->signature) != EVMS_BBR_SIGNATURE ) { - LOG_SERIOUS("BBR signature doesn't match!\n"); - LOG_SERIOUS("Found: 0x%08X Expecting: 0x%08X\n", - le32_to_cpup(&md->signature), EVMS_BBR_SIGNATURE); - return -EINVAL; - } - - if (md->crc) { - org_crc = le32_to_cpup(&md->crc); - md->crc = 0; - final_crc = evms_cs_calculate_crc(EVMS_INITIAL_CRC, md, - sizeof(*md)); - if ( final_crc != org_crc ) { - LOG_ERROR("CRC failed!\n"); - LOG_ERROR("Sector has (0x%08X) calculated(0x%08X)\n", - org_crc, final_crc); - return -EINVAL; - } - md->crc = cpu_to_le32p(&org_crc); - } else { - LOG_WARNING("Metadata sector has no CRC!\n"); - } - - le_meta_data_to_cpu(md); - return 0; -} - -/** - * bbr_load_meta_data - * @node: BBR node to read metadata from. - * @lsn: Sector to read metadata from. - * @md: Pointer to return metadata structure. - * @bbr_table: Pointer to return BBR table. - * - * Load one copy of the BBR metadata. If the metadata is valid, load the - * corresponding copy of the BBR table. - */ -static int load_meta_data(struct evms_logical_node * node, - u64 lsn, - struct evms_bbr_metadata ** md, - struct evms_bbr_table ** bbr_table) -{ - int rc; - - *md = NULL; - *bbr_table = NULL; - - if (!lsn) { - LOG_WARNING("No sector specified for BBR metadata on %s.\n", - node->name); - return -ENODATA; - } - - /* Allocate a buffer for the metadata sector. */ - *md = kmalloc(sizeof(struct evms_bbr_metadata), GFP_KERNEL); - if (!*md) { - LOG_ERROR("kmalloc error creating metadata buffer for %s.\n", - node->name); - return -ENOMEM; - } - - /* Read the metadata sector. */ - rc = INIT_IO(node, 0, lsn, 1, *md); - if (rc) { - LOG_ERROR("init_io error on %s.\n", node->name); - kfree(*md); - *md = NULL; - return rc; - } - - /* Validate the metadata sector. */ - rc = validate_meta_data(*md); - if (rc) { - LOG_ERROR("Error validating metadata for %s.\n", node->name); - kfree(*md); - *md = NULL; - return rc; - } - - /* Allocate a buffer for the BBR table. */ - *bbr_table = kmalloc((*md)->nr_sects_bbr_table << - EVMS_VSECTOR_SIZE_SHIFT, GFP_KERNEL); - if (!*bbr_table) { - LOG_ERROR("kmalloc error creating BBR table buffer for %s.\n", - node->name); - kfree(*md); - *md = NULL; - return -ENOMEM; - } - - /* Read the BBR table but don't validate here. */ - rc = INIT_IO(node, 0, (*md)->start_sect_bbr_table, - (*md)->nr_sects_bbr_table, *bbr_table); - if (rc) { - LOG_ERROR("init_io error on %s.\n", node->name); - kfree(*md); - *md = NULL; - kfree(*bbr_table); - *bbr_table = NULL; - } - - return rc; -} - -/** - * bbr_load_feature_data - * @node: BBR node - * @ID: Return pointer to BBR private data. - * - * Load both copies of the BBR metadata and table. If one is invalid, try - * to correct is using the valid copy. When a valid copy is found, create - * a private data structure for the specified node. - */ -static int load_feature_data(struct evms_logical_node * node, - struct bbr_private ** ID) -{ - struct evms_bbr_metadata * md1 = NULL; - struct evms_bbr_metadata * md2 = NULL; - struct evms_bbr_table * table1 = NULL; - struct evms_bbr_table * table2 = NULL; - u64 lba_table1 = 0, lba_table2 = 0; - u32 nr_sects = 0; - int rc = 0, rc1, rc2; - - *ID = NULL; - - /* Load metadata 1 */ - rc1 = load_meta_data(node, - node->feature_header->feature_data1_start_lsn, - &md1, &table1); - /* Load metadata 2 */ - rc2 = load_meta_data(node, - node->feature_header->feature_data2_start_lsn, - &md2, &table2); - - if (rc1 && rc2) { - /* Both copies are bad? Cannot continue. */ - rc = -ENODATA; - } else if (rc1 || rc2) { - /* One copy is bad. Use the good copy. */ - if (rc1) { - lba_table2 = md2->start_sect_bbr_table; - kfree(table1); - kfree(md1); - table1 = table2; - table2 = NULL; - md1 = md2; - md2 = NULL; - } else { - lba_table1 = md1->start_sect_bbr_table; - } - - nr_sects = validate_bbr_table(md1, table1); - if ( nr_sects == 0 ) { - rc = -ENODATA; - } - } else { - lba_table1 = md1->start_sect_bbr_table; - lba_table2 = md2->start_sect_bbr_table; - nr_sects = validate_bbr_tables(node, md1, md2, table1, table2); - if ( nr_sects == 0 ) { - rc = -ENODATA; - } - } - - if (!rc && nr_sects) { - *ID = kmalloc(sizeof(struct bbr_private), GFP_KERNEL); - if (*ID) { - memset(*ID, 0, sizeof(struct bbr_private)); - (*ID)->source = node; - (*ID)->blksize_in_sects = md1->block_size >> - EVMS_VSECTOR_SIZE_SHIFT; - (*ID)->remap_root = NULL; - (*ID)->lba_table1 = lba_table1; - (*ID)->lba_table2 = lba_table2; - (*ID)->bbr_table = table1; - (*ID)->nr_sects_bbr_table = nr_sects; - if ( nr_sects < md1->nr_sects_bbr_table ) { - LOG_WARNING("Making BBR node read-only\n"); - (*ID)->flag |= EVMS_VOLUME_READ_ONLY; - } - (*ID)->nr_replacement_blks = nr_sects * - EVMS_BBR_ENTRIES_PER_SECT; - (*ID)->start_replacement_sect = md1->start_replacement_sect; - atomic_set(&(*ID)->in_use_replacement_blks, 0); - (*ID)->bbr_id_lock = SPIN_LOCK_UNLOCKED; - if ( !bbr_remap_pool || !bbr_io_buf_pool ) { - rc = bbr_create_pools(); - } - if (!rc) { - atomic_set(&(*ID)->in_use_replacement_blks, - bbr_table_to_remap_list(*ID)); - } - } else { - rc = -ENOMEM; - } - } - - if (!rc) { - if (!bbr_io_thread) { - const char * name = "evms_bbr_io"; - bbr_io_thread = evms_cs_register_thread(bbr_io_handler, - NULL, name); - if (!bbr_io_thread) { - rc = -EINVAL; - } - } - } - - /* If error, free table1. */ - if (rc) { - if (table1) { - kfree(table1); - } - if (*ID) { - (*ID)->bbr_table = NULL; - bbr_free_private(*ID); - (*ID) = NULL; - } - } - - /* Will never use md1, md2 and table2 again */ - if (md1) { - kfree(md1); - } - if (md2) { - kfree(md2); - } - if (table2) { - kfree(table2); - } - - return rc; -} - -/** - * bbr_binary_tree_insert - * - * Insert a node into the binary tree. - */ -void bbr_binary_tree_insert(struct bbr_runtime_remap ** root, - struct bbr_runtime_remap * newnode) -{ - struct bbr_runtime_remap ** node = root; - while (node && *node) { - if ( newnode->remap.bad_sect > (*node)->remap.bad_sect ) { - node = &((*node)->right); - } else { - node = &((*node)->left); - } - } - - newnode->left = newnode->right = NULL; - *node = newnode; -} - -/** - * bbr_binary_search - * - * Search for a node that contains bad_sect = lsn. - */ -struct bbr_runtime_remap * bbr_binary_search(struct bbr_runtime_remap * root, - u64 lsn) -{ - struct bbr_runtime_remap * node = root; - while (node) { - if (node->remap.bad_sect == lsn) { - break; - } - if ( lsn > node->remap.bad_sect ) { - node = node->right; - } else { - node = node->left; - } - } - return node; -} - -/** - * bbr_binary_tree_destroy - * - * Destroy the binary tree. - */ -void bbr_binary_tree_destroy(struct bbr_runtime_remap * root, - struct bbr_private * bbr_id) -{ - struct bbr_runtime_remap ** link = NULL; - struct bbr_runtime_remap * node = root; - - while (node) { - if (node->left) { - link = &(node->left); - node = node->left; - continue; - } - if (node->right) { - link = &(node->right); - node = node->right; - continue; - } - - mempool_free(node, bbr_remap_pool); - if (node == root) { - /* If root is deleted, we're done. */ - break; - } - - /* Back to root. */ - node = root; - *link = NULL; - } -} - -static void bbr_free_remap(struct bbr_private * bbr_id) -{ - unsigned long flags; - spin_lock_irqsave(&bbr_id->bbr_id_lock, flags); - bbr_binary_tree_destroy(bbr_id->remap_root, bbr_id); - bbr_id->remap_root = NULL; - spin_unlock_irqrestore(&bbr_id->bbr_id_lock, flags); -} - -/** - * bbr_insert_remap_entry - * - * Create a new remap entry and add it to the binary tree for this node. - */ -static int bbr_insert_remap_entry(struct bbr_private * bbr_id, - struct evms_bbr_table_entry * new_bbr_entry) -{ - struct bbr_runtime_remap * newnode = NULL; - unsigned long flags; - int rc; - - newnode = mempool_alloc(bbr_remap_pool, GFP_NOIO); - if (!newnode) { - rc = -ENOMEM; - LOG_SERIOUS("Could not allocate from remap pool! (rc=%d)\n", rc); - return rc; - } - newnode->remap.bad_sect = new_bbr_entry->bad_sect; - newnode->remap.replacement_sect = new_bbr_entry->replacement_sect; - spin_lock_irqsave(&bbr_id->bbr_id_lock, flags); - bbr_binary_tree_insert(&bbr_id->remap_root, newnode); - spin_unlock_irqrestore(&bbr_id->bbr_id_lock, flags); - return 0; -} - -/** - * bbr_table_to_remap_list - * - * The on-disk bbr table is sorted by the replacement sector LBA. In order to - * improve run time performance, the in memory remap list must be sorted by - * the bad sector LBA. This function is called at discovery time to initialize - * the remap list. This function assumes that at least one copy of meta data - * is valid. - */ -static u32 bbr_table_to_remap_list(struct bbr_private * bbr_id) -{ - u32 in_use_blks = 0; - int i, j; - struct evms_bbr_table * p; - - - for ( i = 0, p = bbr_id->bbr_table; - i < bbr_id->nr_sects_bbr_table; - i++, p++ ) { - if (!p->in_use_cnt) { - break; - } - in_use_blks += p->in_use_cnt; - for ( j = 0; j < p->in_use_cnt; j++ ) { - bbr_insert_remap_entry(bbr_id, &p->entries[j]); - } - } - - return in_use_blks; -} - -/** - * bbr_search_remap_entry - * - * Search remap entry for the specified sector. If found, return a pointer to - * the table entry. Otherwise, return NULL. - */ -static struct evms_bbr_table_entry * bbr_search_remap_entry(struct bbr_private * bbr_id, - u64 lsn) -{ - struct bbr_runtime_remap * p; - unsigned long flags; - - spin_lock_irqsave(&bbr_id->bbr_id_lock, flags); - p = bbr_binary_search(bbr_id->remap_root, lsn); - spin_unlock_irqrestore(&bbr_id->bbr_id_lock, flags); - if (p) { - return (&p->remap); - } else { - return NULL; - } -} - -/** - * bbr_remap - * - * If *lsn is in the remap table, return TRUE and modify *lsn, - * else, return FALSE. - */ -static inline int bbr_remap(struct bbr_private * bbr_id, - u64 * lsn) -{ - struct evms_bbr_table_entry *e; - - if ( atomic_read(&bbr_id->in_use_replacement_blks) && - ! (bbr_id->flag & BBR_STOP_REMAP) ) { - e = bbr_search_remap_entry(bbr_id, *lsn); - if (e) { - *lsn = e->replacement_sect; - LOG_EXTRA("%s replacement sector (LSN="PFU64")\n", - __FUNCTION__, *lsn); - return TRUE; - } - } - return FALSE; -} - -/** - * bbr_remap_probe - * - * If any of the sectors in the range [lsn, lsn+nr_sects] are in the remap - * table return TRUE, Else, return FALSE. - */ -static inline int bbr_remap_probe(struct bbr_private * bbr_id, - u64 lsn, u64 nr_sects) -{ - u64 tmp, cnt; - - if ( atomic_read(&bbr_id->in_use_replacement_blks) && - ! (bbr_id->flag & BBR_STOP_REMAP) ) { - for ( cnt = 0, tmp = lsn; - cnt < nr_sects; - cnt += bbr_id->blksize_in_sects, tmp = lsn + cnt) { - if ( bbr_remap(bbr_id,&tmp) ) { - return TRUE; - } - } - } - return FALSE; -} - -static void *bbr_slab_pool_alloc(int gfp_mask, void * data) -{ - return kmem_cache_alloc(data, gfp_mask); -} - -static void bbr_slab_pool_free(void *ptr, void * data) -{ - kmem_cache_free(data, ptr); -} - -static void bbr_destroy_pools(void) -{ - if (bbr_io_buf_pool) { - mempool_destroy(bbr_io_buf_pool); - bbr_io_buf_pool = NULL; - } - if (bbr_io_buf_slab) { - kmem_cache_destroy(bbr_io_buf_slab); - bbr_io_buf_slab = NULL; - } - if (bbr_bh_pool) { - mempool_destroy(bbr_bh_pool); - bbr_bh_pool = NULL; - } - if (bbr_bh_slab) { - kmem_cache_destroy(bbr_bh_slab); - bbr_bh_slab = NULL; - } - if (bbr_remap_pool) { - mempool_destroy(bbr_remap_pool); - bbr_remap_pool = NULL; - } - if (bbr_remap_slab) { - kmem_cache_destroy(bbr_remap_slab); - bbr_remap_slab = NULL; - } -} - -static int bbr_create_pools(void) -{ - /* Create a memory pool for the remap list. */ - bbr_remap_slab = kmem_cache_create("BBR_Remap_Slab", - sizeof(struct bbr_runtime_remap), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!bbr_remap_slab) { - LOG_ERROR("Unable to create BBR remap cache."); - goto error; - } - - bbr_remap_pool = mempool_create(64, bbr_slab_pool_alloc, - bbr_slab_pool_free, bbr_remap_slab); - if (!bbr_remap_pool) { - LOG_ERROR("Unable to create BBR remap pool."); - goto error; - } - - /* Create a memory pool for cloning buffer-heads. */ - bbr_bh_slab = kmem_cache_create("BBR_BH_Slab", - sizeof(struct buffer_head), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!bbr_bh_slab) { - LOG_ERROR("Unable to create BBR BH cache."); - goto error; - } - - bbr_bh_pool = mempool_create(256, bbr_slab_pool_alloc, - bbr_slab_pool_free, bbr_bh_slab); - if (!bbr_bh_pool) { - LOG_ERROR("Unable to create BBR BH pool."); - goto error; - } - - /* Create a memory pool for the BBR I/O anchors. */ - bbr_io_buf_slab = kmem_cache_create("BBR_IO_Buf_Slab", - sizeof(struct bbr_io_buffer), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!bbr_io_buf_slab) { - LOG_ERROR("Unable to create BBR I/O buffer cache."); - goto error; - } - - bbr_io_buf_pool = mempool_create(256, bbr_slab_pool_alloc, - bbr_slab_pool_free, bbr_io_buf_slab); - if (!bbr_io_buf_pool) { - LOG_ERROR("Unable to create BBR I/O buffer pool."); - goto error; - } - - return 0; - -error: - bbr_destroy_pools(); - return -ENOMEM; -} - -/** - * bbr_discover - * - * Search through the discover list looking for object with BBR metadata. - * Remove them from the list and replace with a new BBR node. - */ -static int bbr_discover(struct evms_logical_node ** discover_list) -{ - struct evms_logical_node * node, * next_node; - struct evms_logical_node * bbr_node = NULL; - struct bbr_private * bbr_id; - int bad_blocks, rc = 0; - - MOD_INC_USE_COUNT; - - next_node = *discover_list; - while (next_node) { - node = next_node; - next_node = node->next; - - /* The node must have a BBR feature-header. */ - if ( ! node->feature_header || - node->feature_header->feature_id != plugin_header.id ) { - continue; - } - - rc = load_feature_data(node, &bbr_id); - if (rc) { - /* Error loading feature data. - * This node belongs to us, but metadata is invalid, - * - remove it from the discovery list - * - delete it - * - clear error code then continue. - * Will consider creating a read only BBR node in - * the future. - */ - LOG_SERIOUS("Error in node (%s) with "PFU64" sectors.\n", - node->name, node->total_vsectors); - evms_cs_remove_logical_node_from_list(discover_list, - node); - DELETE(node); - rc = 0; - continue; - } - - rc = evms_cs_allocate_logical_node(&bbr_node); - if (rc) { - LOG_SERIOUS("Could not allocate logical node! rc=%d\n", rc); - bbr_free_private(bbr_id); - continue; - } - - MOD_INC_USE_COUNT; - bbr_node->volume_info = node->volume_info; - bbr_node->flags |= node->flags; - bbr_node->plugin = &plugin_header; - strcpy(bbr_node->name, - node->feature_header->object_name); - bbr_node->hardsector_size = node->hardsector_size; - bbr_node->total_vsectors = node->total_vsectors - 2 - - node->feature_header->feature_data1_size - - node->feature_header->feature_data2_size; - bbr_node->block_size = node->block_size; - bbr_node->private = bbr_id; - bbr_id->node = bbr_node; - - /* Free the feature header */ - kfree(node->feature_header); - node->feature_header = NULL; - evms_cs_remove_logical_node_from_list(discover_list, node); - - /* If bad blocks exist, give warning */ - bad_blocks = atomic_read(&bbr_id->in_use_replacement_blks); - if (bad_blocks) { - BBR_DEBUG_PRINT_REMAP_LIST(bbr_id); - LOG_WARNING("%s has %d bad blocks.\n", - bbr_id->source->name, bad_blocks); - LOG_WARNING("There are "PFU64" total replacement blocks.\n", - bbr_id->nr_replacement_blks); - LOG_WARNING("There are "PFU64" remaining replacement blocks.\n", - bbr_id->nr_replacement_blks - - bad_blocks); - } - - evms_cs_add_logical_node_to_list(discover_list, bbr_node); - bbr_list_add(bbr_id); - } - - MOD_DEC_USE_COUNT; - return rc; -} - -static inline void bbr_list_add(struct bbr_private * bbr_id) -{ - bbr_id->next = bbr_instances; - bbr_instances = bbr_id; -} - -static void bbr_list_remove(struct bbr_private * bbr_id) -{ - struct bbr_private ** p; - - for ( p = &bbr_instances; *p; p = &(*p)->next ) { - if ( *p == bbr_id ) { - *p = (*p)->next; - break; - } - } -} - -static struct bbr_private * bbr_find_private(char * object_name) -{ - struct bbr_private * p; - - for ( p = bbr_instances; p; p = p->next ) { - if ( ! strncmp(p->node->name, object_name, - EVMS_VOLUME_NAME_SIZE) ) { - return p; - } - } - return NULL; -} - -static void bbr_free_private(struct bbr_private * bbr_id) -{ - if (bbr_id->remap_root) { - bbr_free_remap(bbr_id); - } - if (bbr_id->bbr_table) { - kfree(bbr_id->bbr_table); - } - bbr_list_remove(bbr_id); - kfree(bbr_id); -} - -/** - * bbr_delete - * - * Delete the specified BBR node and the node it is built on. If the last BBR - * node is deleted, shut down the I/O thread. - */ -static int bbr_delete(struct evms_logical_node * bbr_node) -{ - struct bbr_private * bbr_id; - int rc; - - bbr_id = bbr_node->private; - - rc = DELETE(bbr_id->source); - if (!rc) { - /* Now cleanup and go away */ - bbr_free_private(bbr_id); - evms_cs_deallocate_logical_node(bbr_node); - if (!bbr_instances) { - bbr_destroy_pools(); - if (bbr_io_thread) { - evms_cs_unregister_thread(bbr_io_thread); - bbr_io_thread = NULL; - } - } - MOD_DEC_USE_COUNT; - } - return rc; -} - -static struct buffer_head * allocate_bbr_bh(struct buffer_head * org_bh) -{ - struct buffer_head * new_bh; - - new_bh = mempool_alloc(bbr_bh_pool, GFP_NOIO); - if (!new_bh) { - LOG_WARNING("Could not allocate from BBR BH pool!\n"); - return NULL; - } - - memset(new_bh, 0, sizeof(*new_bh)); - new_bh->b_size = org_bh->b_size; - new_bh->b_list = BUF_LOCKED; - new_bh->b_dev = org_bh->b_dev; - atomic_set(&new_bh->b_count, 1); - new_bh->b_rdev = org_bh->b_rdev; - set_bit(BH_Dirty, &new_bh->b_state); - set_bit(BH_Lock, &new_bh->b_state); - set_bit(BH_Req, &new_bh->b_state); - set_bit(BH_Mapped, &new_bh->b_state); - set_bit(BH_Uptodate, &new_bh->b_state); - new_bh->b_this_page = (struct buffer_head *)1; - new_bh->b_data = org_bh->b_data; - new_bh->b_page = org_bh->b_page; - new_bh->b_rsector = org_bh->b_rsector; - init_waitqueue_head(&new_bh->b_wait); - - return new_bh; -} - -static void free_bbr_bh(struct buffer_head * bh) -{ - mempool_free(bh, bbr_bh_pool); -} - -static struct bbr_io_buffer * allocate_bbr_io_buf(struct bbr_private * bbr_id, - struct buffer_head * org_bh, - int rw) -{ - struct bbr_io_buffer * bbr_io_buf; - - bbr_io_buf = mempool_alloc(bbr_io_buf_pool, GFP_NOIO); - if (bbr_io_buf) { - memset(bbr_io_buf, 0, sizeof(struct bbr_io_buffer)); - INIT_LIST_HEAD(&bbr_io_buf->bbr_io_list); - bbr_io_buf->bbr_id = bbr_id; - bbr_io_buf->org_bh = org_bh; - bbr_io_buf->rw = rw; - } else { - LOG_WARNING("Could not allocate from BBR I/O buffer pool!\n"); - } - return bbr_io_buf; -} - -static void free_bbr_io_buf(struct bbr_io_buffer * bbr_io_buf) -{ - mempool_free(bbr_io_buf, bbr_io_buf_pool); -} - -/** - * bbr_io_remap_error - * @bbr_id: Private data for the BBR node. - * @rw: READ or WRITE. - * @starting_lsn: Starting sector of request to remap. - * @count: Number of sectors in the request. - * @buffer: Data buffer for the request. - * - * For the requested range, try to write each sector individually. For each - * sector that fails, find the next available remap location and write the - * data to that new location. Then update the table and write both copies - * of the table to disk. Finally, update the in-memory mapping and do any - * other necessary bookkeeping. - */ -static int bbr_io_remap_error(struct bbr_private * bbr_id, - int rw, - u64 starting_lsn, - u64 count, - char * buffer ) -{ - struct evms_bbr_table * bbr_table; - unsigned long table_sector_index; - unsigned long table_sector_offset; - unsigned long index; - u64 lsn, new_lsn; - int rc; - - if ( rw == READ ) { - /* Nothing can be done about read errors. */ - return -EIO; - } - - /* For each sector in the request. */ - for ( lsn = 0; lsn < count; lsn++, buffer += EVMS_VSECTOR_SIZE ) { - rc = INIT_IO(bbr_id->source, rw, starting_lsn + lsn, 1, buffer); - while (rc) { - if ( bbr_id->flag & BBR_STOP_REMAP ) { - /* Can't allow new remaps if the - * engine told us to stop. - */ - LOG_ERROR("Object %s: Bad sector ("PFU64"), but remapping is turned off.\n", - bbr_id->node->name, starting_lsn+lsn); - return -EIO; - } - - /* Find the next available relocation sector. */ - new_lsn = atomic_read(&bbr_id->in_use_replacement_blks); - if ( new_lsn >= bbr_id->nr_replacement_blks ) { - /* No more replacement sectors available. */ - return -EIO; - } - new_lsn += bbr_id->start_replacement_sect; - - /* Write the data to its new location. */ - LOG_WARNING("Object %s: Trying to remap bad sector ("PFU64") to sector ("PFU64")\n", - bbr_id->node->name, starting_lsn + lsn, - new_lsn); - rc = INIT_IO(bbr_id->source, rw, new_lsn, 1, buffer); - if (rc) { - /* This replacement sector is bad. - * Try the next one. - */ - LOG_ERROR("Object %s: Replacement sector ("PFU64") is bad. Skipping.\n", - bbr_id->node->name, new_lsn); - atomic_inc(&bbr_id->in_use_replacement_blks); - continue; - } - - /* Add this new entry to the on-disk table. */ - table_sector_index = new_lsn - - bbr_id->start_replacement_sect; - table_sector_offset = table_sector_index / - EVMS_BBR_ENTRIES_PER_SECT; - index = table_sector_index % EVMS_BBR_ENTRIES_PER_SECT; - - bbr_table = &bbr_id->bbr_table[table_sector_offset]; - bbr_table->entries[index].bad_sect = starting_lsn + lsn; - bbr_table->entries[index].replacement_sect = new_lsn; - bbr_table->in_use_cnt++; - bbr_table->sequence_number++; - bbr_table->crc = 0; - bbr_table->crc = evms_cs_calculate_crc(EVMS_INITIAL_CRC, - bbr_table, - sizeof(struct evms_bbr_table)); - - /* Write the table to disk. */ - cpu_bbr_table_sector_to_le(bbr_table, bbr_table); - if ( bbr_id->lba_table1 ) { - rc = INIT_IO(bbr_id->source, WRITE, - bbr_id->lba_table1 + - table_sector_offset, - 1, bbr_table); - } - if ( bbr_id->lba_table2 ) { - rc |= INIT_IO(bbr_id->source, WRITE, - bbr_id->lba_table2 + - table_sector_offset, - 1, bbr_table); - } - le_bbr_table_sector_to_cpu(bbr_table); - - if (rc) { - /* Error writing one of the tables to disk. */ - LOG_ERROR("Object %s: Error updating BBR tables on disk.\n", - bbr_id->node->name); - return rc; - } - - /* Insert a new entry in the remapping binary-tree. */ - rc = bbr_insert_remap_entry(bbr_id, - &bbr_table->entries[index]); - if (rc) { - LOG_ERROR("Object %s: Error adding new entry to remap tree.\n", - bbr_id->node->name); - return rc; - } - - atomic_inc(&bbr_id->in_use_replacement_blks); - } - } - - return 0; -} - -/** - * bbr_io_process_request - * - * For each sector in this request, check if the sector has already - * been remapped. If so, process all previous sectors in the request, - * followed by the remapped sector. Then reset the starting lsn and - * count, and keep going with the rest of the request as if it were - * a whole new request. If any of the INIT_IO's return an error, - * call the remapper to relocate the bad sector(s). - */ -static int bbr_io_process_request(struct bbr_io_buffer * bbr_io_buf) -{ - struct bbr_private * bbr_id = bbr_io_buf->bbr_id; - u64 starting_lsn = bbr_io_buf->org_bh->b_rsector; - u64 count = bbr_io_buf->org_bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - u64 lsn, remapped_lsn; - char * buffer = bbr_io_buf->org_bh->b_data; - int rc = 0, rw = bbr_io_buf->rw; - - /* For each sector in this request, check if this sector has already - * been remapped. If so, process all previous sectors in this request, - * followed by the remapped sector. Then reset the starting lsn and - * count and keep going with the rest of the request as if it were - * a whole new request. - */ - for ( lsn = 0; lsn < count && !(bbr_id->flag & BBR_STOP_REMAP); lsn++ ) { - remapped_lsn = starting_lsn + lsn; - rc = bbr_remap(bbr_id, &remapped_lsn); - if (!rc) { - /* This sector is fine. */ - continue; - } - - /* Process all sectors in the request up to this one. */ - if ( lsn > 0 ) { - rc = INIT_IO(bbr_id->source, rw, - starting_lsn, lsn, buffer); - if (rc) { - /* If this I/O failed, then one of the sectors - * in this request needs to be relocated. - */ - rc = bbr_io_remap_error(bbr_id, rw, starting_lsn, - lsn, buffer); - if (rc) { - return rc; - } - } - buffer += (lsn << EVMS_VSECTOR_SIZE_SHIFT); - } - - /* Process the remapped sector. */ - rc = INIT_IO(bbr_id->source, rw, remapped_lsn, 1, buffer); - if (rc) { - /* BUGBUG - Need more processing if this caused an - * an error. If this I/O failed, then the existing - * remap is now bad, and we need to find a new remap. - * Can't use bbr_io_remap_error(), because the existing - * map entry needs to be changed, not added again, and - * the original table entry also needs to be changed. - */ - return rc; - } - - buffer += EVMS_VSECTOR_SIZE; - starting_lsn += (lsn + 1); - count -= (lsn + 1); - lsn = -1; - } - - /* Check for any remaining sectors after the last split. This could - * potentially be the whole request, but that should be a rare case - * because requests should only be processed by the thread if we know - * an error occurred or they contained one or more remapped sectors. - */ - if ( count ) { - rc = INIT_IO(bbr_id->source, rw, starting_lsn, count, buffer); - if (rc) { - /* If this I/O failed, then one of the sectors in this - * request needs to be relocated. - */ - rc = bbr_io_remap_error(bbr_id, rw, starting_lsn, - count, buffer); - if (rc) { - return rc; - } - } - } - - return 0; -} - -/** - * bbr_io_handler - * - * This is the handler for the bbr_io_thread. It continuously loops, - * taking I/O requests off its list and processing them. If nothing - * is on the list, the thread goes back to sleep until specifically - * woken up. - * - * I/O requests should only be sent to this thread if we know that: - * a) the request contains at least one remapped sector. - * or - * b) the request caused an error on the normal I/O path. - * This function uses synchronous I/O, so sending a request to this - * thread that doesn't need special processing will cause severe - * performance degredation. - */ -static void bbr_io_handler(void * void_data) -{ - struct bbr_io_buffer * bbr_io_buf; - struct buffer_head * bh; - unsigned long flags; - int rc = 0; - - while (1) { - /* Process bbr_io_list, one entry at a time. */ - spin_lock_irqsave(&bbr_io_list_lock, flags); - if (list_empty(&bbr_io_list)) { - /* No more items on the list. */ - spin_unlock_irqrestore(&bbr_io_list_lock, flags); - break; - } - bbr_io_buf = list_entry(bbr_io_list.next, - struct bbr_io_buffer, bbr_io_list); - list_del(&bbr_io_buf->bbr_io_list); - spin_unlock_irqrestore(&bbr_io_list_lock, flags); - - rc = bbr_io_process_request(bbr_io_buf); - - /* Clean up and complete the original I/O. */ - bh = bbr_io_buf->org_bh; - if (bh->b_end_io) { - free_bbr_io_buf(bbr_io_buf); - evms_cs_volume_request_in_progress(bh->b_rdev, -1, NULL); - bh->b_end_io(bh, rc ? 0 : 1); - } else { - /* A request that originated from bbr_init_io. */ - bbr_io_buf->rc = rc; - complete(bbr_io_buf->complete); - } - } -} - -/** - * bbr_schedule_io - * - * Place the specified bbr_io_buf on the thread's processing list. - */ -static void bbr_schedule_io(struct bbr_io_buffer * bbr_io_buf) -{ - unsigned long flags; - - spin_lock_irqsave(&bbr_io_list_lock, flags); - list_add_tail(&bbr_io_buf->bbr_io_list, &bbr_io_list); - spin_unlock_irqrestore(&bbr_io_list_lock, flags); - evms_cs_wakeup_thread(bbr_io_thread); -} - -/** - * bbr_read - * - * If there are any remapped sectors on this object, send this request over - * to the thread for processing. Otherwise send it down the stack normally. - */ -static void bbr_read(struct evms_logical_node * bbr_node, - struct buffer_head * bh) -{ - struct bbr_private * bbr_id = bbr_node->private; - struct bbr_io_buffer * bbr_io_buf; - - if ( bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) > - bbr_node->total_vsectors ) { - /* Request is off the end of the object. */ - bh->b_end_io(bh, 0); - return; - } - - if ( atomic_read(&bbr_id->in_use_replacement_blks) == 0 || - bbr_id->flag & BBR_STOP_REMAP || - ! bbr_remap_probe(bbr_id, bh->b_rsector, - bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) ) { - /* No existing remaps, this request doesn't contain any - * remapped sectors, or the engine told us not to remap. - */ - R_IO(bbr_id->source, bh); - return; - } - - /* This request has at least one remapped sector. */ - bbr_io_buf = allocate_bbr_io_buf(bbr_id, bh, READ); - if (!bbr_io_buf) { - /* Can't get memory to track the I/O. */ - bh->b_end_io(bh, 0); - return; - } - - evms_cs_volume_request_in_progress(bh->b_rdev, +1, NULL); - bbr_schedule_io(bbr_io_buf); -} - -/** - * bbr_write_callback - * - * This is the callback for normal write requests. Check for an error - * during the I/O, and send to the thread for processing if necessary. - */ -static void bbr_write_callback(struct buffer_head * bh, - int uptodate) -{ - struct bbr_io_buffer * bbr_io_buf = bh->b_private; - struct buffer_head * org_bh = bbr_io_buf->org_bh; - - free_bbr_bh(bh); - - if (!(bbr_io_buf->bbr_id->flag & BBR_STOP_REMAP) && - !uptodate) { - LOG_ERROR("Object %s: Write failure on sector ("PFU64"). Scheduling for retry.\n", - bbr_io_buf->bbr_id->node->name, - (u64)org_bh->b_rsector); - bbr_schedule_io(bbr_io_buf); - } else { - free_bbr_io_buf(bbr_io_buf); - evms_cs_volume_request_in_progress(org_bh->b_rdev, -1, NULL); - org_bh->b_end_io(org_bh, uptodate); - } -} - -/** - * bbr_write - * - * If there are any remapped sectors on this object, send the request over - * to the thread for processing. Otherwise, register for callback - * notification, and send the request down normally. - */ -static void bbr_write(struct evms_logical_node * bbr_node, - struct buffer_head * bh) -{ - struct bbr_private * bbr_id = bbr_node->private; - struct bbr_io_buffer * bbr_io_buf; - struct buffer_head * new_bh; - - if ( bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) > - bbr_node->total_vsectors || - bbr_id->flag & EVMS_VOLUME_READ_ONLY ) { - /* Request is off the end of the object, or this - * is a read-only object. - */ - bh->b_end_io(bh, 0); - return; - } - - bbr_io_buf = allocate_bbr_io_buf(bbr_id, bh, WRITE); - if (!bbr_io_buf) { - /* Can't get memory to track the I/O. */ - bh->b_end_io(bh, 0); - return; - } - - new_bh = allocate_bbr_bh(bh); - if (!new_bh) { - /* Can't get memory to track the I/O. */ - free_bbr_io_buf(bbr_io_buf); - bh->b_end_io(bh, 0); - return; - } - - evms_cs_volume_request_in_progress(bh->b_rdev, +1, NULL); - - if ( atomic_read(&bbr_id->in_use_replacement_blks) == 0 || - bbr_id->flag & BBR_STOP_REMAP || - ! bbr_remap_probe(bbr_id, bh->b_rsector, - bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) ) { - /* No existing remaps, this request contains no remapped - * sectors, or the engine said to stop remapping. - */ - new_bh->b_private = bbr_io_buf; - new_bh->b_end_io = bbr_write_callback; - W_IO(bbr_id->source, new_bh); - } else { - /* This request contains at least one remapped sector. */ - free_bbr_bh(new_bh); - bbr_schedule_io(bbr_io_buf); - } -} - -/** - * bbr_init_io_schedule_io - * @bbr_id: Private data for the BBR node. - * @rw: READ or WRITE. - * @lsn: Starting sector for the request. - * @count: Number of sectors in the request. - * @buffer: Data buffer for the request. - * - * During init_io, failures must still be handled by the I/O thread. Create - * a bbr_io_buf, and schedule it to be handled by the thread. Then wait until - * the request is complete. - */ -static int bbr_init_io_schedule_io(struct bbr_private * bbr_id, - int rw, - u64 lsn, - u64 count, - void * buffer) -{ - struct bbr_io_buffer * bbr_io_buf; - struct buffer_head bh; - struct completion complete; - int rc = 0; - - if ( rw != WRITE ) { - /* Nothing can be done about read failures. */ - return -EIO; - } - - LOG_ERROR("Object %s: init_io write failure (sector "PFU64": count "PFU64"). Scheduling for retry.\n", - bbr_id->node->name, lsn, count); - bbr_io_buf = allocate_bbr_io_buf(bbr_id, &bh, rw); - if (!bbr_io_buf) { - return -ENOMEM; - } - - memset(&bh, 0, sizeof(struct buffer_head)); - init_waitqueue_head(&bh.b_wait); - bh.b_rsector = lsn; - bh.b_size = count << EVMS_VSECTOR_SIZE_SHIFT; - bh.b_data = buffer; - bh.b_end_io = NULL; - - /* Schedule the I/O and wait for it to finish. */ - bbr_io_buf->complete = &complete; - init_completion(bbr_io_buf->complete); - bbr_schedule_io(bbr_io_buf); - wait_for_completion(bbr_io_buf->complete); - - rc = bbr_io_buf->rc; - free_bbr_io_buf(bbr_io_buf); - - return rc; -} - -/** - * bbr_init_io - * @bbr_node: BBR node. - * @rw: READ or WRITE. - * @lsn: Starting sector for I/O request. - * @count: Number of sectors in the I/O request. - * @buffer: Data buffer for the I/O request. - * - * Synchronous I/O requests. - */ -static int bbr_init_io(struct evms_logical_node * bbr_node, - int rw, - u64 start_lsn, - u64 count, - void * buffer ) -{ - struct bbr_private * bbr_id = bbr_node->private; - u64 lsn; - int rc = 0; - - if ( start_lsn + count > bbr_node->total_vsectors ) { - /* Request is off the end of the object. */ - return -EINVAL; - } - - if ( rw == WRITE && (bbr_id->flag & EVMS_VOLUME_READ_ONLY) ) { - /* Can't write to a read-only object. */ - return -EINVAL; - } - - if ( bbr_id->flag & BBR_STOP_REMAP || - atomic_read(&bbr_id->in_use_replacement_blks) == 0 || - ! bbr_remap_probe(bbr_id, start_lsn, count) ) { - /* Normal case (no existing remaps). */ - rc = INIT_IO(bbr_id->source, rw, start_lsn, count, buffer); - if (rc && ! (bbr_id->flag & BBR_STOP_REMAP) ) { - /* Init_io error. Send request over to - * thread for further processing. - */ - rc = bbr_init_io_schedule_io(bbr_id, rw, start_lsn, - count, buffer); - } - } else { - /* At least one sector in this request needs to be remapped. - * Test and send each one down individually. - */ - for ( lsn = start_lsn; - lsn < start_lsn + count; - lsn++, buffer += EVMS_VSECTOR_SIZE ) { - bbr_remap(bbr_id, &lsn); - rc = INIT_IO(bbr_id->source, rw, lsn, 1, buffer); - if (rc) { - /* Init_io error. Send request - * to thread for processing. - */ - rc = bbr_init_io_schedule_io(bbr_id, rw, - lsn, 1, buffer); - if (rc) { - break; - } - } - } - } - - return rc; -} - -/** - * bbr_direct_ioctl_sector_io - * - * Process an I/O from the engine on an active BBR object. - */ -static int bbr_direct_ioctl_sector_io(struct bbr_private * bbr_id, - struct evms_notify_bbr * notify) -{ - char * buffer, * user_buffer; - u64 lsn; - int rc = 0; - - buffer = kmalloc(EVMS_VSECTOR_SIZE, GFP_NOIO); - if (!buffer) { - return -ENOMEM; - } - - user_buffer = (char*)notify->buffer; - - for ( lsn = 0; - lsn < notify->nr_sect; - lsn++, user_buffer += EVMS_VSECTOR_SIZE ) { - if ( notify->rw == WRITE ) { - if ( copy_from_user(buffer, user_buffer, - EVMS_VSECTOR_SIZE) ) { - rc = -EFAULT; - break; - } - } - - rc = bbr_init_io(bbr_id->node, notify->rw, - notify->start_sect + lsn, 1, buffer); - if (rc) { - break; - } - - if ( notify->rw == READ ) { - if ( copy_to_user(user_buffer, buffer, - EVMS_VSECTOR_SIZE) ) { - rc = -EFAULT; - break; - } - } - } - - kfree(buffer); - return rc; -} - -/** - * bbr_direct_ioctl - * @inode: N/A - * @file: N/A - * @cmd: N/A - * @arg: Pointer to an evms_plugin_ioctl_pkt. - * - * BBR-specific ioctls from the engine. Currently handles: - * BBR_STOP_REMAP_CMD - * BBR_GET_INFO_CMD - * BBR_SECTOR_IO_CMD - */ -static int bbr_direct_ioctl(struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - struct bbr_private * bbr_id; - struct evms_plugin_ioctl_pkt pkt, * user_pkt; - struct evms_notify_bbr notify, * user_notify; - - MOD_INC_USE_COUNT; - - user_pkt = (struct evms_plugin_ioctl_pkt *)arg; - if ( copy_from_user(&pkt, user_pkt, sizeof(pkt)) ) { - MOD_DEC_USE_COUNT; - return -EFAULT; - } - - if ( pkt.feature_id != plugin_header.id ) { - MOD_DEC_USE_COUNT; - return -EINVAL; - } - - user_notify = (struct evms_notify_bbr *)pkt.feature_ioctl_data; - if ( copy_from_user(¬ify, user_notify, sizeof(notify)) ) { - rc = -EFAULT; - } else { - bbr_id = bbr_find_private(notify.object_name); - if (!bbr_id) { - rc = -ENODEV; - } else { - - switch(pkt.feature_command) { - - case BBR_STOP_REMAP_CMD: - bbr_id->flag |= BBR_STOP_REMAP; - /* Fall through. */ - - case BBR_GET_INFO_CMD: - notify.count = atomic_read(&bbr_id->in_use_replacement_blks); - if ( copy_to_user(&user_notify->count, - ¬ify.count, - sizeof(user_notify->count))) { - rc = -EFAULT; - } - break; - - case BBR_SECTOR_IO_CMD: - rc = bbr_direct_ioctl_sector_io(bbr_id, - ¬ify); - break; - - default: - rc = -ENOSYS; - } - } - } - - pkt.status = rc; - copy_to_user(user_pkt, &pkt, sizeof(pkt)); - MOD_DEC_USE_COUNT; - return rc; -} - -/** - * bbr_ioctl - * @bbr_node: BBR node. - * @inode: N/A - * @file: N/A - * @cmd: ioctl command to process. - * @arg: ioctl-specific data pointer. - * - * IOCTL handler. Currently BBR handles plugin-specific ioctls, as well as - * EVMS_GET_BMAP. All others are passed to the child node. - */ -static int bbr_ioctl (struct evms_logical_node * bbr_node, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct bbr_private * bbr_id = bbr_node->private; - struct evms_get_bmap_pkt * bmap; - int rc = 0; - - switch (cmd) { - case EVMS_PLUGIN_IOCTL: - rc = bbr_direct_ioctl(inode, file, cmd, arg); - break; - - case EVMS_GET_BMAP: - bmap = (struct evms_get_bmap_pkt *)arg; - bbr_remap(bbr_id, &bmap->rsector); - /* fall thru */ - - default: - rc = IOCTL(bbr_id->source, inode, file, cmd, arg); - } - return rc; -} - -static int __init bbr_init(void) -{ - return evms_cs_register_plugin(&plugin_header); -} - -static void __exit bbr_exit(void) -{ - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(bbr_init); -module_exit(bbr_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms_drivelink.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms_drivelink.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms_drivelink.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms_drivelink.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1275 +0,0 @@ -/* -*- linux-c -*- - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ -/* - * linux/drivers/evms/drvlink.c - - * - * EVMS Drive Linking Feature. - * - * This feature provides the ability to link multiple storage objects - * together as a single virtual storage object. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_PREFIX "drivelink: " - -/* prototypes for mandatory plugin interface functions */ -static int drivelink_discover(struct evms_logical_node **); -static int drivelink_delete(struct evms_logical_node *); -static void drivelink_read(struct evms_logical_node *, struct buffer_head *); -static void drivelink_write(struct evms_logical_node *, struct buffer_head *); -static int drivelink_ioctl(struct evms_logical_node *, - struct inode *, - struct file *, unsigned int, unsigned long); -static int drivelink_init_io(struct evms_logical_node *, - int, u64, u64, void *); - -/* plugin function table definition */ -static struct evms_plugin_fops fops = { - .discover = drivelink_discover, - .delete = drivelink_delete, - .read = drivelink_read, - .write = drivelink_write, - .init_io = drivelink_init_io, - .ioctl = drivelink_ioctl -}; - -/* plugin header definition */ -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_FEATURE, - EVMS_DRIVELINK_FEATURE_ID), - .version = { - .major = 2, - .minor = 0, - .patchlevel = 2 - }, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0 - }, - .fops = &fops -}; - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Discover function & Support routines */ -/********************************************************/ - -/** - * le_feature_data_to_cpu: - * @md: drivelink metadata - * - * convert feature data from on-disk (Little Endian) format - * to the native cpu endian format. -**/ -static void -le_feature_data_to_cpu(struct evms_drivelink_metadata *md) -{ - int i; - - md->signature = le32_to_cpup(&md->signature); - md->crc = le32_to_cpup(&md->crc); - md->version.major = le32_to_cpup(&md->version.major); - md->version.minor = le32_to_cpup(&md->version.minor); - md->version.patchlevel = le32_to_cpup(&md->version.patchlevel); - md->flags = le32_to_cpup(&md->flags); - md->sequence_number = le64_to_cpup(&md->sequence_number); - md->child_serial_number = le64_to_cpup(&md->child_serial_number); - md->parent_serial_number = le64_to_cpup(&md->parent_serial_number); - md->child_count = le64_to_cpup(&md->child_count); - for (i = 0; i < EVMS_DRIVELINK_MAX_ENTRIES; i++) { - struct evms_dl_ordering_table_entry *child_entry; - - child_entry = &md->ordering_table[i]; - child_entry->child_serial_number = - le64_to_cpup(&child_entry->child_serial_number); - child_entry->child_vsize = - le64_to_cpup(&child_entry->child_vsize); - } -} - -/** - * load_feature_data: load a feature header from disk - * @node: storage object - * @md: ptr to drivelink metadata - * - * loads and verifies redundant copies of drivelink metadata. @md is modified - * and returned to the caller. - * - * Return value: 0 on success - * Otherwise error code -**/ -static int -load_feature_data(struct evms_logical_node *node, - struct evms_drivelink_metadata **md) -{ - int i, rc = 0, rc_array[2] = { 0, 0 }, size_in_bytes; - u64 real_metadata_size, feature_data_size; - u64 starting_sector; - struct evms_drivelink_metadata *cur_md, *md1, *md2 = NULL; - char *location_name; - - /* verify the feature metadata size from the */ - /* feature header agrees with the real size */ - /* of the current metadata structure. */ - real_metadata_size = evms_cs_size_in_vsectors(sizeof (**md)); - - /* allocate a buffer large enough to hold all */ - /* sectors containing the feature's metadata */ - size_in_bytes = real_metadata_size * EVMS_VSECTOR_SIZE; - md1 = kmalloc(size_in_bytes, GFP_KERNEL); - if (md1) { - md2 = kmalloc(size_in_bytes, GFP_KERNEL); - if (!md2) { - kfree(md1); - rc = -ENOMEM; - } - } else { - rc = -ENOMEM; - } - if (!rc) { - for (i = 0; i < 2; i++) { - if (i == 0) { - starting_sector = - node->feature_header-> - feature_data1_start_lsn; - feature_data_size = - node->feature_header->feature_data1_size; - cur_md = md1; - location_name = evms_primary_string; - } else { - starting_sector = - node->feature_header-> - feature_data2_start_lsn; - feature_data_size = - node->feature_header->feature_data2_size; - cur_md = md2; - location_name = evms_secondary_string; - } - /* check that real metadata size matches the */ - /* feature data size */ - if (real_metadata_size != feature_data_size) { - LOG_ERROR - ("%s feature data size("PFU64" bytes) doesn't match expected size("PFU64" bytes).\n", - location_name, - feature_data_size << - EVMS_VSECTOR_SIZE_SHIFT, - real_metadata_size << - EVMS_VSECTOR_SIZE_SHIFT); - rc = -EINVAL; - rc_array[i] = rc; - continue; - } - /* load the node's feature data */ - rc = INIT_IO(node, - 0, - starting_sector, - feature_data_size, cur_md); - if (rc) { - LOG_ERROR - ("error(%d) probing for %s feature data at sector("PFU64") on '%s'.\n", - rc, location_name, starting_sector, - node->name); - rc_array[i] = rc; - continue; - } - /* check for valid metadata signature */ - if (le32_to_cpup(&cur_md->signature) != - EVMS_DRIVELINK_SIGNATURE) { - rc = -ENODATA; - LOG_SERIOUS - ("error(%d) invalid signature in %s feature data on '%s'\n", - rc, location_name, node->name); - rc_array[i] = rc; - continue; - } - /* validate feature data CRC */ - if (cur_md->crc != EVMS_MAGIC_CRC) { - int org_crc, final_crc; - org_crc = le32_to_cpup(&cur_md->crc); - cur_md->crc = 0; - final_crc = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, - cur_md, - sizeof (*cur_md)); - if (final_crc != org_crc) { - LOG_ERROR - ("CRC mismatch error [stored(%x), computed(%x)] in %s feature data on '%s'.\n", - org_crc, final_crc, location_name, - node->name); - rc = -EINVAL; - rc_array[i] = rc; - continue; - } - } else { - LOG_WARNING - ("CRC disabled in %s feature data on '%s'.\n", - location_name, node->name); - } - /* convert feature data from on-disk - * format (Little Endian) to native - * cpu endian format. - */ - le_feature_data_to_cpu(cur_md); - /* check for valid structure version */ - rc = evms_cs_check_version(&metadata_ver, - &cur_md->version); - if (rc) { - LOG_SERIOUS - ("error(%d) obsolete version detected: actual(%d,%d,%d), requires(%d,%d,%d) in %s feature data on '%s'\n", - rc, cur_md->version.major, - cur_md->version.minor, - cur_md->version.patchlevel, - DRIVELINK_METADATA_MAJOR, - DRIVELINK_METADATA_MINOR, - DRIVELINK_METADATA_PATCHLEVEL, - location_name, node->name); - rc_array[i] = rc; - } - } - /* getting same return code for both copies? */ - if (rc_array[0] == rc_array[1]) { - rc = rc_array[0]; - /* if no errors on both copies, - * check the sequence numbers. - * use the highest sequence number. - */ - if (!rc) { - /* compare sequence numbers */ - if (md1->sequence_number == - md2->sequence_number) { - cur_md = md1; - } else { - LOG_WARNING - ("sequence number mismatches between front("PFU64") and rear("PFU64") feature data copies on node(%s)!\n", - md2->sequence_number, - md1->sequence_number, node->name); - if (md1->sequence_number > - md2->sequence_number) - cur_md = md1; - else - cur_md = md2; - LOG_WARNING - ("using %s feature data copy!\n", - (cur_md == - md1) ? evms_primary_string : - evms_secondary_string); - } - } - /* getting different return codes for each copy */ - } else if (rc_array[0] == 0) { - /* use 1st (rear) copy if its good */ - rc = 0; - cur_md = md1; - } else if (rc_array[1] == 0) { - /* use 2nd (front) copy if its good */ - rc = 0; - cur_md = md2; - } else if ((rc_array[0] == -EINVAL) || (rc_array[1] == -EINVAL)) { - /* fail if either give a fatal error */ - rc = -EINVAL; - cur_md = NULL; - } - - /* deallocate metadata buffers appropriately */ - if (rc || (cur_md == md1)) - kfree(md2); - if (rc || (cur_md == md2)) - kfree(md1); - - /* save validated feature header pointer */ - if (!rc) - *md = cur_md; - } - return (rc); -} - -/** - * find_parent_node_for_child_node: finds or creates a parent node for this child node - * @child_node: input, child node - * @md: input, on-disk metadata - * @parent_node: output, parent node - * @dl_private: output, runtime metadata - * @discover_list: input/output, list of objects being discovered - * - * finds or creates a parent node for the specified child node. if the parent node is - * created, create and initialize the parent's private data area. - * - * Return value: 0 on success - * Otherwise error code. -**/ -static int -find_parent_node_for_child_node(struct evms_logical_node *child_node, - struct evms_drivelink_metadata *md, - struct evms_logical_node **parent_node, - struct runtime_data **dl_private, - struct evms_logical_node **discover_list) -{ - int rc = 0, parent_found = FALSE; - struct evms_logical_node *parent = NULL; - struct runtime_data *rd = NULL; - - /* find the parent node for this child */ - for (parent = *discover_list; parent; parent = parent->next) { - /* only parent nodes will have null feature headers */ - if (!parent->feature_header) { - rd = (struct runtime_data *) parent->private; - if (rd->parent_sn == md->parent_serial_number) { - parent_found = TRUE; - break; - } - } - } - /* if no parent node found, create it */ - if (parent_found == FALSE) { - rc = evms_cs_allocate_logical_node(&parent); - if (!rc) { - /* transpose info from child to parent */ - parent->flags |= child_node->flags; - strcpy(parent->name, - child_node->feature_header->object_name); - /* copy evms system data to parent */ - parent->volume_info = child_node->volume_info; - /* initialize the plugin id field */ - parent->plugin = &plugin_header; - /* allocate parent's instance data */ - parent->private = kmalloc(sizeof(*rd), GFP_KERNEL); - if (!parent->private) - rc = -ENOMEM; - } - if (!rc) { - /* initialize some instance data fields */ - rd = (struct runtime_data *) parent->private; - rd->block_size = 0; - rd->parent_sn = md->parent_serial_number; - rd->child_count = md->child_count; - /* allocate the child table */ - rd->child_table = kmalloc(sizeof(struct runtime_entry) * - rd->child_count, GFP_KERNEL); - if (!rd->child_table) - rc = -ENOMEM; - } - if (!rc) { - memset(rd->child_table, 0, - sizeof(struct runtime_entry) * rd->child_count); - /* add the parent node to the discover list */ - rc = evms_cs_add_logical_node_to_list(discover_list, - parent); - MOD_INC_USE_COUNT; - } - /* if any errors encountered, try to clean up */ - if (rc) { - LOG_SERIOUS("find_parent_node: rc(%d) from '%s'\n", - rc, child_node->name); - if (parent) { - DELETE(parent); - parent = NULL; - rd = NULL; - } - } - } - - *dl_private = rd; - *parent_node = parent; - - return (rc); -} - -/** - * compute_child_index: compute the index for a specific child node - * @node: the child node - * @md: the drivelink on-disk metadata - * - * compute and return and 0-based index value of this child node's position - * in the parent node's ordering table. - * - * Return value: -1 on error - * otherwise the index of the specified child. -**/ -static int -compute_child_index(struct evms_logical_node *node, - struct evms_drivelink_metadata *md) -{ - int i, position = -1; - - for (i = 0; i < md->child_count; i++) { - if (md->ordering_table[i].child_serial_number == - md->child_serial_number) { - position = i; - break; - } - } - if (position == -1) { - LOG_SERIOUS("%s: child not found from '%s'\n", - __FUNCTION__, node->name); - } - return (position); -} - -/** - * process_child_nodes: perform the discovery operation on each child node - * @discover_list: the list of potential child objects - * - * search the discovery list of drivelink child nodes. for each node found, - * perform the discovery operation on it. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -process_child_nodes(struct evms_logical_node **discover_list) -{ - int rc = 0, index = -1; - struct evms_logical_node *node, *next_node, *parent; - struct evms_drivelink_metadata *md; - struct runtime_data *rd; - struct runtime_entry *child_entry = NULL; - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - if ((!node->feature_header) || - (node->feature_header->feature_id != plugin_header.id)) { - continue; - } - - rc = evms_cs_remove_logical_node_from_list(discover_list, node); - if (rc) - BUG(); - /* we need to load the feature data to */ - /* find the parent's serial number this */ - /* child node belongs to. */ - md = NULL; - rc = load_feature_data(node, &md); - if (!rc) { - /* find the parent node for this child */ - parent = NULL; - rc = find_parent_node_for_child_node(node, md, - &parent, &rd, - discover_list); - } - if (!rc) { - /* determine position of child in drive link object */ - index = compute_child_index(node, md); - if (index == -1) - rc = index; - } - if (!rc) { - /* check for multiple child index requests */ - child_entry = - (struct runtime_entry *) &rd->child_table[index]; - /* check to see if this child index is - * already in use. - */ - if (child_entry->child_node) { - LOG_SERIOUS - ("attempt to put '%s' in child index(%d). Already occupied by '%s'.\n", - node->name, index, - child_entry->child_node->name); - rc = -1; - } - } - if (!rc) { - /* fill in child info in parent */ - - /* check the sector size for this node */ - if (node->hardsector_size > parent->hardsector_size) - parent->hardsector_size = node->hardsector_size; - /* check the block size for this node */ - if (node->block_size > parent->block_size) - parent->block_size = node->block_size; - /* set the child node */ - child_entry->child_node = node; - /* set the metadata for this node */ - child_entry->child_metadata = md; - } - - /* on error, clean up accordingly */ - if (rc) { - if (md) - kfree(md); - LOG_SERIOUS("%s: rc(%d) from '%s'\n", - __FUNCTION__, rc, node->name); - LOG_SERIOUS("deleting child node '%s'.\n", node->name); - rc = DELETE(node); - if (rc) { - LOG_SERIOUS - ("error(%d) attempting to delete '%s'.\n", - rc, node->name); - } - } - } - - /* errors are handled internal to this function */ - /* by deleting the failed node. This will get */ - /* picked up by finalize_parent_nodes as a */ - /* missing child node */ - return (0); -} - -#define TEST_CHILD_PRESENCE 0 -#define TEST_CHILD_COUNT 1 -#define TEST_CHILD_PARENTS_SERIAL_NUM 2 -#define TEST_CHILD_POSITION 3 -#define TEST_CHILD_METADATA 4 - -/** - * test_parent_node: verify that a parent is complete - * @node: specified parent node - * - * verify that the parent node has all of its child nodes accounted for. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -test_parent_node(struct evms_logical_node *node) -{ - int i, rc = 0; - struct runtime_data *rd; - struct runtime_entry *child_entry; - - rd = (struct runtime_data *) node->private; - for (i = 0; i < rd->child_count; i++) { - child_entry = (struct runtime_entry *) &rd->child_table[i]; - - /* insure each child entry is filled */ - if (!child_entry->child_node) { - node->flags |= - EVMS_VOLUME_SET_READ_ONLY | EVMS_VOLUME_PARTIAL; - LOG_ERROR("%s: missing child(%d).\n", __FUNCTION__, i); - } else - /* insure child count is the same */ - /* in each child's metadata */ - if (child_entry->child_metadata->child_count != rd->child_count) { - rc = -EVMS_FEATURE_FATAL_ERROR; - LOG_ERROR("%s: child count wrong for node '%s'\n", - __FUNCTION__, node->name); - } else - /* insure parent serial number is */ - /* the same in each child's metadata */ - if (child_entry->child_metadata->parent_serial_number != - rd->parent_sn) { - rc = -EVMS_FEATURE_FATAL_ERROR; - LOG_ERROR - ("%s: incorrect [is("PFU64"), should be("PFU64")] child serial number for node '%s'\n", - __FUNCTION__, - child_entry->child_metadata->parent_serial_number, - rd->parent_sn, node->name); - } else - /* insure each is in the correct entry */ - if (child_entry->child_metadata->ordering_table[i]. - child_serial_number != - child_entry->child_metadata->child_serial_number) { - rc = -EVMS_FEATURE_FATAL_ERROR; - LOG_ERROR - ("%s: child reports different index for node '%s'\n", - __FUNCTION__, node->name); - } else { - struct runtime_entry *other_child_entry; - int j, rc2; - /* compare the children's metadata */ - - /* look for another present child to - * compare against. - */ - other_child_entry = NULL; - for (j = 0; j < rd->child_count; j++) { - /* skip comparing to ourselves */ - if (j == i) { - continue; - } - /* is this child is present? */ - if (rd->child_table[j].child_node) { - /* yes, use it */ - other_child_entry = &rd->child_table[j]; - break; - } - } - /* if we can't find another valid - * child node's metadata to compare - * against, just skip this test. - */ - if (!other_child_entry) { - continue; - } - rc2 = - memcmp(other_child_entry->child_metadata-> - ordering_table, - child_entry->child_metadata->ordering_table, - sizeof (child_entry->child_metadata-> - ordering_table)); - if (rc2) { - rc = -EVMS_FEATURE_FATAL_ERROR; - LOG_ERROR - ("%s: mismatching child metadata for nodes '%s' and '%s'\n", - __FUNCTION__, - rd->child_table[i - 1].child_node->name, - child_entry->child_node->name); - } - } - /* stop if fatal error encountered */ - if (rc == -EVMS_FEATURE_FATAL_ERROR) { - break; - } - } - return (rc); -} - -/** - * perform_final_adjustments: do final tweaks to parent node - * @node: parent node - * - * This function does the following: - * sets the vsize (in vsectors) field in each child node - * sets the voffset (in vsectors) field in each child node - * frees each child node's metadata - * sets the parent's total size field -**/ -static void -perform_final_adjustments(struct evms_logical_node *node) -{ - int i; - struct runtime_data *rd; - struct runtime_entry *child_entry = NULL; - struct evms_drivelink_metadata *ref_data = NULL; - - rd = (struct runtime_data *) node->private; - /* find a valid copy of the ordering table. - * since all the ordering tables are the same - * we can just pick one to use for all the - * child computations. - */ - for (i = 0; i < rd->child_count; i++) { - child_entry = (struct runtime_entry *) &rd->child_table[i]; - if (child_entry->child_node) { - ref_data = child_entry->child_metadata; - break; - } - } - /* if we got this far, there should - * always be at least one valid child. - */ - if (!ref_data) - BUG(); - /* compute the parent's usable size, - * and construct the table used to - * remap parent I/Os to child I/Os */ - for (i = 0; i < rd->child_count; i++) { - child_entry = (struct runtime_entry *) &rd->child_table[i]; - /* set the LBA count for this child node */ - child_entry->vsize = ref_data->ordering_table[i].child_vsize; - /* set the start LBA value for this child node */ - child_entry->voffset = node->total_vsectors; - /* keep a running total of size in sectors */ - node->total_vsectors += child_entry->vsize; - /* free the metadata for this child node */ - if (ref_data != child_entry->child_metadata) { - kfree(child_entry->child_metadata); - } - child_entry->child_metadata = NULL; - /* free the feature header for this child node */ - if (child_entry->child_node) { - kfree(child_entry->child_node->feature_header); - child_entry->child_node->feature_header = NULL; - } - } - /* free the reference data */ - kfree(ref_data); -} - -/** - * finalize_parent_nodes: verify and prepare parent nodes - * @discover_list: list of potential drivelink parent objects - * - * verify the completeness of each parent node. if not complete, purge the in-memory - * structs for this object and all its children. If complete, perform final tweaks - * to allow this node to useable. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -finalize_parent_nodes(struct evms_logical_node **discover_list) -{ - int rc = 0, rc2; - struct evms_logical_node *node, *next_node; - - for (node = *discover_list; node; node = next_node) { - next_node = node->next; - /* only check parent nodes */ - if (!node->feature_header) { - /* valid the children of this parent */ - rc = test_parent_node(node); - if (!rc) { - /* compute parent size and - * child remap table. - */ - perform_final_adjustments(node); - } else { - /* fatal error encountered. - * cleanup from this node and - * delete it from memory. - */ - evms_cs_remove_logical_node_from_list - (discover_list, node); - rc2 = DELETE(node); - if (rc2) { - LOG_SERIOUS - ("error(%d) attempting to delete '%s'.\n", - rc2, node->name); - } - } - } - } - return (rc); -} - -/** - * drivelink_discover: discover drivelinked storage objects - * @discover_list: the list of objects to inspect - * - * perform the drivelink discover process on the objects in the discovery list - * - * Return value: 0 on success - * otherwise error code -**/ -static int -drivelink_discover(struct evms_logical_node **discover_list) -{ - int rc = 0; - - MOD_INC_USE_COUNT; - rc = process_child_nodes(discover_list); - if (!rc) - rc = finalize_parent_nodes(discover_list); - - MOD_DEC_USE_COUNT; - return (rc); -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Delete function */ -/********************************************************/ - -/** - * drivelink_delete: purges a drivelink object and its children from memory - * @node: the drivelink object to delete - * - * purge the drivelink object, its private data, and all its children from memory. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -drivelink_delete(struct evms_logical_node *node) -{ - int i, rc = 0; - struct runtime_data *rd; - struct runtime_entry *child_entry; - - LOG_DETAILS("deleting '%s'.\n", node->name); - - rd = (struct runtime_data *) node->private; - if (rd) { - for (i = 0; i < rd->child_count; i++) { - child_entry = &rd->child_table[i]; - /* delete the child node */ - if (child_entry->child_node) { - rc = DELETE(child_entry->child_node); - if (rc) - break; - child_entry->child_node = NULL; - } - /* delete the child's metadata */ - if (child_entry->child_metadata) { - kfree(child_entry->child_metadata); - child_entry->child_metadata = NULL; - } - } - if (!rc) { - /* delete the child table */ - if (rd->child_table) { - kfree(rd->child_table); - rd->child_table = NULL; - } - /* delete the instance data */ - kfree(rd); - node->private = NULL; - } - } - if (!rc) { - evms_cs_deallocate_logical_node(node); - MOD_DEC_USE_COUNT; - } - - return (rc); -} - -/** - * which_child: find the child node targetted by a IO to this drivelink object - * @parent: parent drivelink object - * @rsector: relative sector on the parent object - * @max_io_sects: largest IO size on the child, starting from rsector position - * - * This function find the child node a parent rsector maps to. - * It then adjusts the rsector value to be child relative and - * optionally computes the max # of sectors that can be access - * from this starting point on the child. - * - * Return value: - * The child node, the child relative rsector and max io size are - * returned to the caller. On error, the returned child node will - * be NULL. -**/ -static struct evms_logical_node * -which_child(struct evms_logical_node *parent, - u64 * rsector, u64 * max_io_sects) -{ - int i; - struct evms_logical_node *child = NULL; - struct runtime_data *rd; - struct runtime_entry *child_entry = NULL; - - rd = (struct runtime_data *) parent->private; - for (i = 0; i < rd->child_count; i++) { - child_entry = (struct runtime_entry *) &rd->child_table[i]; - - if (*rsector >= child_entry->vsize) { - *rsector -= child_entry->vsize; - } else { - /* get the child node */ - child = child_entry->child_node; - /* compute the sector count if requested */ - if (max_io_sects) - /* this is only used for INIT I/O - * to return the largest sector - * count size for this child based - * on first sector in the I/O. - */ - *max_io_sects = child_entry->vsize - *rsector; - break; - } - } - return (child); -} - -/** - * drivelink_io_error: log an IO error for drivelink - * @node: drivelink object - * @bh: buffer head targetting this object - * - * this function was primarily created because the function - * buffer_IO_error is inline and kgdb doesn't allow breakpoints - * to be set on inline functions. Since this was an error path - * and not mainline, I decided to add a trace statement to help - * report on the failing condition. -**/ -static void -drivelink_io_error(struct evms_logical_node *node, int io_flag, struct buffer_head *bh) -{ - LOG_SERIOUS("%s error on '%s' remapping rsector("PFU64").\n", - (io_flag) ? "WRITE" : "READ", - node->name, (u64) bh->b_rsector); - - bh->b_end_io(bh, 0); -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Read function & Support routines */ -/********************************************************/ - -/** - * drivelink_read: handles IO read operations to drivelink objects - * @node: drivelink object - * @bh: buffer head targetting this object - * - * handles IO read operations to the drivelink objects. internally remaps the - * drivelink relative requests to the child relative requests and then routes - * it to the child for further processing. -**/ -static void -drivelink_read(struct evms_logical_node *node, struct buffer_head *bh) -{ - struct evms_logical_node *child; - u64 io_size, rsector; - - rsector = bh->b_rsector; - child = which_child(node, &rsector, &io_size); - if (child && ((bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) <= io_size)) { - bh->b_rsector = rsector; - R_IO(child, bh); - } else { - drivelink_io_error(node, READ, bh); - } -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Write function & Support routines */ -/********************************************************/ - -/** - * drivelink_read_write: handles IO write operations to drivelink objects - * @node: drivelink object - * @bh: buffer head targetting this object - * - * handles IO write operations to the drivelink objects. internally remaps the - * drivelink relative requests to the child relative requests and then routes - * it to the child for further processing. -**/ -static void -drivelink_write(struct evms_logical_node *node, struct buffer_head *bh) -{ - struct evms_logical_node *child; - u64 io_size, rsector; - - rsector = bh->b_rsector; - child = which_child(node, &rsector, &io_size); - if (child && ((bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) <= io_size)) { - bh->b_rsector = rsector; - W_IO(child, bh); - } else { - drivelink_io_error(node, WRITE, bh); - } -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Init I/O function */ -/********************************************************/ - -/** - * drivelink_init_io: performs synchronous IO to drivelink objects - * @node: drivelink object - * @io_flag: read/write flag - * @sect_nr: starting sector, object relative (512 byte units) - * @num_sects: count of sectors - * @buf_addr: buffer address to read from/write to - * - * This function must determine which child or children a - * specified I/O request must be passed to. Also if, when, - * and how a request must be broken up. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -drivelink_init_io(struct evms_logical_node *node, int io_flag, - u64 sect_nr, - u64 num_sects, - void *buf_addr) -{ - int rc = 0; - - if (!node) - rc = -EINVAL; - else { - u64 starting_sector, remaining_sectors; - void *io_buf; - struct runtime_data *rd; - - if ((sect_nr + num_sects) > node->total_vsectors) { - LOG_SERIOUS - ("attempted out of bound("PFU64") %s on '%s' at sector("PFU64"), count("PFU64").\n", - node->total_vsectors, (io_flag) ? "WRITE" : "READ", - node->name, sect_nr, num_sects); - rc = -EINVAL; - } else { - rd = (struct runtime_data *) node->private; - /* make working copies of input parameters */ - starting_sector = sect_nr; - remaining_sectors = num_sects; - io_buf = buf_addr; - /* loop until all I/O is performed */ - while (remaining_sectors) { - u64 io_start, io_size; - struct evms_logical_node *child; - - /* compute the child relative io_start - * and max io_size. - */ - io_start = starting_sector; - child = which_child(node, &io_start, &io_size); - /* adjust io_size based on - * original remaining sectors - * in this io. - */ - if (io_size > remaining_sectors) - io_size = remaining_sectors; - if (child) { - rc = INIT_IO(child, - io_flag, - io_start, io_size, io_buf); - } else { - /* if partial volume, return 0's - * for missing children. - */ - if (io_flag == READ) { - memset(io_buf, 0, - io_size << - EVMS_VSECTOR_SIZE_SHIFT); - } - } - if (!rc) { - /* adjust working copies */ - starting_sector += io_size; - remaining_sectors -= io_size; - io_buf += io_size << - EVMS_VSECTOR_SIZE_SHIFT; - } else - break; - } - } - } - - return (rc); -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* IOCTL function & Support routines */ -/********************************************************/ - -/** - * drivelink_ioctl_cmd_plugin_ioctl: drivelink support for the 'plugin ioctl' command - * @node: drivelink object - * @inode: VFS supplied parameter - * @file: VFS supplied parameter - * @cmd: the specific ioctl command - * @arg: the specific ioctl arguments - * - * this function handles 'plugin ioctl' commands. currently there is no specific - * commands for this plugin. however, this plugin must broadcast some commands so - * lower layers can receive them. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -drivelink_ioctl_cmd_plugin_ioctl(struct evms_logical_node *node, - struct inode *inode, struct file *file, - unsigned long cmd, unsigned long arg) -{ - int i, rc = 0; - struct runtime_data *rd; - struct evms_plugin_ioctl_pkt tmp, *user_parms; - - user_parms = (struct evms_plugin_ioctl_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - rd = (struct runtime_data *) node->private; - /* is this cmd targetted at this feature ? */ - if (tmp.feature_id == node->plugin->id) { - switch (tmp.feature_command) { - default: - break; - } - } else { /* broadcast this cmd to all children */ - for (i = 0; i < rd->child_count; i++) { - struct evms_logical_node *child_node; - - child_node = rd->child_table[i].child_node; - if (child_node) { - rc = IOCTL(child_node, inode, file, - cmd, arg); - if (rc) - break; - } - } - } - /* copy info to userspace */ - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - } - return (rc); -} - -/** - * drivelink_ioctl_cmd_broadcast: broadcast ioctls to your children - * @node: drivelink object - * @inode: VFS supplied parameter - * @file: VFS supplied parameter - * @cmd: the specific ioctl command - * @arg: the specific ioctl arguments - * - * broadcast the specified ioctl command and arguments to all this objects - * children. OR (logical opeation) the return values from all the children - * and return the OR'd value to the caller. - * - * Return value: 0 on success - * otherwise error code -**/ -static int -drivelink_ioctl_cmd_broadcast(struct evms_logical_node *node, - struct inode *inode, struct file *file, - unsigned long cmd, unsigned long arg) -{ - int i, rc = 0; - struct runtime_data *rd; - - rd = (struct runtime_data *) node->private; - /* broadcast this cmd to all children */ - for (i = 0; i < rd->child_count; i++) { - struct evms_logical_node *child_node; - - child_node = rd->child_table[i].child_node; - if (child_node) { - rc |= IOCTL(child_node, inode, file, cmd, arg); - } - } - return (rc); -} - -/** - * drivelink_ioctl: main ioctl entry point and handler - * @node: drivelink object - * @inode: VFS supplied parameter - * @file: VFS supplied parameter - * @cmd: a specific ioctl command - * @arg: a specific ioctl argument - * - * handles specific ioctl command internally and routes other ioctls commands to - * the appropriate entry points. - * - * Returns: 0 on success - * otherwise error code - **/ -static int -drivelink_ioctl(struct evms_logical_node *node, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct runtime_data *rd = NULL; - struct hd_geometry hdgeo; - - if ((!node) || (!inode)) - rc = -EINVAL; - - if (!rc) { - rd = (struct runtime_data *) node->private; - switch (cmd) { - case HDIO_GETGEO: - hdgeo.heads = 255; - hdgeo.sectors = 63; - hdgeo.cylinders = - ((unsigned int) node->total_vsectors) / - hdgeo.heads / hdgeo.sectors; - hdgeo.start = 0; - if (copy_to_user((int *) arg, &hdgeo, sizeof (hdgeo))) - rc = -EFAULT; - break; - case EVMS_QUIESCE_VOLUME: - case EVMS_GET_DISK_LIST: - case EVMS_CHECK_MEDIA_CHANGE: - case EVMS_REVALIDATE_DISK: - case EVMS_OPEN_VOLUME: - case EVMS_CLOSE_VOLUME: - case EVMS_CHECK_DEVICE_STATUS: - rc = drivelink_ioctl_cmd_broadcast(node, inode, file, - cmd, arg); - break; - case EVMS_PLUGIN_IOCTL: - rc = drivelink_ioctl_cmd_plugin_ioctl(node, inode, file, - cmd, arg); - break; - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap; - u64 io_start, io_size; - struct evms_logical_node *child; - - bmap = (struct evms_get_bmap_pkt *) arg; - io_start = bmap->rsector; - child = which_child(node, &io_start, &io_size); - if (child) { - if (node->block_size != - child->block_size) { - bmap->status = -EPERM; - } else { - bmap->rsector = io_start; - rc = IOCTL(child, - inode, - file, cmd, arg); - } - } - } - break; - default: - rc = -EINVAL; - break; - } - } - return (rc); -} - -/********************************************************/ -/* Required Module Entry Point: */ -/* drivelink_init */ -/********************************************************/ - -/** - * drivelink_init: register this module for use within the EVMS framework - * - * Return value: 0 on success - * otherwise error code. -**/ -int __init -drivelink_init(void) -{ - return evms_cs_register_plugin(&plugin_header); -} - -/** - * drivelink_exit: unregister this module from use within the EVMS framework - * - * Return value: 0 on success - * otherwise error code. -**/ -void __exit -drivelink_exit(void) -{ - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(drivelink_init); -module_exit(drivelink_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms_passthru.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms_passthru.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/evms_passthru.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/evms_passthru.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,298 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ -/* - * linux/drivers/evms/evms_passthru.c - * - * EVMS System Data Manager - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define EVMS_PASSTHRU_ID 0 -#define LOG_PREFIX "passthru: " - -static int passthru_mgr_discover(struct evms_logical_node **); -static int passthru_mgr_delete(struct evms_logical_node *); -static void passthru_mgr_read(struct evms_logical_node *, struct buffer_head *); -static void passthru_mgr_write(struct evms_logical_node *, struct buffer_head *); -static int passthru_mgr_ioctl(struct evms_logical_node *, - struct inode *, - struct file *, unsigned int, unsigned long); -static int passthru_mgr_init_io(struct evms_logical_node *, - int, u64, u64, void *); - -static struct evms_plugin_fops fops = { - .discover = passthru_mgr_discover, - .delete = passthru_mgr_delete, - .read = passthru_mgr_read, - .write = passthru_mgr_write, - .init_io = passthru_mgr_init_io, - .ioctl = passthru_mgr_ioctl -}; - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_FEATURE, - EVMS_PASSTHRU_ID), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2 - }, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0 - }, - .fops = &fops -}; - -/*******************************/ -/* discovery support functions */ -/*******************************/ - -static int -process_passthru_data(struct evms_logical_node **pp) -{ - int rc, size_in_sectors; - struct evms_logical_node *node, *new_node; - - node = *pp; - - size_in_sectors = - evms_cs_size_in_vsectors(sizeof (struct evms_feature_header)); - - /* allocate "parent" node */ - rc = evms_cs_allocate_logical_node(&new_node); - if (!rc) { - /* initialize "parent" node */ - new_node->private = node; - new_node->flags = node->flags; - new_node->plugin = &plugin_header; - new_node->system_id = node->system_id; - new_node->block_size = node->block_size; - new_node->hardsector_size = node->hardsector_size; - new_node->total_vsectors = node->total_vsectors; - new_node->total_vsectors -= - (size_in_sectors << 1) + - node->feature_header->alignment_padding; - new_node->volume_info = node->volume_info; - strcpy(new_node->name, node->name); - if (strlen(node->feature_header->object_name)) - strcat(new_node->name, - node->feature_header->object_name); - else - strcat(new_node->name, "_Passthru"); - - /* return "parent" node to caller */ - *pp = new_node; - - MOD_INC_USE_COUNT; - - LOG_DETAILS("feature header found on '%s', created '%s'.\n", - node->name, new_node->name); - /* we're done with the passthru feature headers - * so lets delete them now. - */ - kfree(node->feature_header); - node->feature_header = NULL; - } else { - /* on any fatal error, delete the node */ - int rc2 = DELETE(node); - if (rc2) { - LOG_DEFAULT - ("error(%d) attempting to delete node(%p,%s).\n", - rc2, node, node->name); - } - } - return (rc); -} - -/********** Required Plugin Functions **********/ - -/* - * Function: passthru_mgr_discover - * - */ -static int -passthru_mgr_discover(struct evms_logical_node **discover_list) -{ - int rc = 0; - struct evms_logical_node *node, *tmp_list_head; - - MOD_INC_USE_COUNT; - tmp_list_head = *discover_list; - *discover_list = NULL; - - while (tmp_list_head) { - node = tmp_list_head; - rc = evms_cs_remove_logical_node_from_list(&tmp_list_head, - node); - if (!rc) - rc = process_passthru_data(&node); - if (!rc) - if (node) - rc = evms_cs_add_logical_node_to_list - (discover_list, node); - } - MOD_DEC_USE_COUNT; - return (rc); -} - -/* - * Function: passthru_mgr_delete - * - */ -static int -passthru_mgr_delete(struct evms_logical_node *node) -{ - int rc; - struct evms_logical_node *p; - - LOG_DETAILS("deleting '%s'.\n", node->name); - - p = node->private; - rc = DELETE(p); - if (!rc) { - evms_cs_deallocate_logical_node(node); - MOD_DEC_USE_COUNT; - } - return (rc); -} - -/* - * function: passthru_io_error - * - * this function was primarily created because the function - * buffer_IO_error is inline and kgdb doesn't allow breakpoints - * to be set on inline functions. Since this was an error path - * and not mainline, I decided to add a trace statement to help - * report on the failing condition. - * - */ -static void -passthru_io_error(struct evms_logical_node *node, int io_flag, struct buffer_head *bh) -{ - LOG_SERIOUS - ("attempt to %s beyond boundary("PFU64") on (%s), rsector("PFU64").\n", - (io_flag) ? "WRITE" : "READ", node->total_vsectors - 1, - node->name, (u64) bh->b_rsector); - - bh->b_end_io(bh, 0); -} - -/* - * Function: passthru_mgr_read - */ -static void -passthru_mgr_read(struct evms_logical_node *node, struct buffer_head *bh) -{ - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) <= - node->total_vsectors) { - R_IO(((struct evms_logical_node *) (node->private)), bh); - } else - passthru_io_error(node, READ, bh); -} - -/* - * Function: passthru_mgr_write - * - */ -static void -passthru_mgr_write(struct evms_logical_node *node, struct buffer_head *bh) -{ - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) <= - node->total_vsectors) { - W_IO(((struct evms_logical_node *) (node->private)), bh); - } else - passthru_io_error(node, WRITE, bh); -} - -/* - * Function: passthru_mgr_ioctl - * - */ -static int -passthru_mgr_ioctl(struct evms_logical_node *node, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc; - - if ((!node) || (!inode)) - rc = -EINVAL; - else - rc = IOCTL(((struct evms_logical_node *) (node->private)), - inode, file, cmd, arg); - return (rc); -} - -static int -passthru_mgr_init_io(struct evms_logical_node *node, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr) -{ /* buffer address */ - int rc; - if ((sect_nr + num_sects) <= node->total_vsectors) { - rc = INIT_IO(((struct evms_logical_node *) (node-> - private)), - io_flag, sect_nr, num_sects, buf_addr); - } else - rc = -EINVAL; - return (rc); -} - -/* - * Function: passthru_init - * - */ -int __init -evms_passthru_manager_init(void) -{ - return evms_cs_register_plugin(&plugin_header); /* register with EVMS */ -} - -void __exit -evms_passthru_manager_exit(void) -{ - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(evms_passthru_manager_init); -module_exit(evms_passthru_manager_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/gpt_part.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/gpt_part.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/gpt_part.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/gpt_part.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1015 +0,0 @@ -/* -*- linux-c -*- */ -/* - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ - -/* linux/driver/evms/gpt_part.c - * - * EVMS - EFI GPT segment manager plugin - * - * This plugin provides support for the GUID Partition Table format specified - * by the Extensible Firmware Interface documentation ... version 1.02 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* prefix used in logging messages */ -#define LOG_PREFIX "gpt_part: " - -/** - * struct gpt_private - Private data structure for this plugin - * @source_object: object this IO will get remapped to - * @start_sect: source object relative starting address in 512 byte units - * @nr_sect: partition size in 512 bytes units - * @type: partition type or filesystem format indicator - * - * private copy of the just the fields we require to remap IO requests - * to the underlying object. - **/ -struct gpt_private { - struct evms_logical_node *source_disk; - u64 start_sect; - u64 nr_sects; - unsigned char type; -}; - -#define GPT_DISKMAGIC 0x5452415020494645 // "EFI PART" -#define GPT_PNAME_SIZE 36 // max unicode partition name size - -/** - * struct guid - GUID structure - * @time_low: timestamp - low order 32 bits - * @time_mid: timestamp - mid 16 bits - * @time_high: timestamp - high 16 bits - * @clock_seq_high: clock - high order 8 bits - * @clock_seq_low: clock - low order 8 bits - * @node: spatial reference - unique id (ie. mac address of nic) - * - * GUID structure - **/ -struct guid { - u32 time_low; - u16 time_mid; - u16 time_high; - u8 clock_seq_high; - u8 clock_seq_low; - u8 node[6]; -}; - -/** - * struct gpt_partition - GPT partition record definition - * @type: partition type - * @part_id: partition record id - * @start: address of 1st block of partition - * @end: address of last block of partition - * @attributes: bit field reserved by EFI spec - * @name: unicode name of partition - * - * GPT partition record definition - **/ -struct gpt_partition { - struct guid type; - struct guid part_id; - u64 start; - u64 end; - u64 attributes; - u16 name[GPT_PNAME_SIZE]; -}; - -/** - * struct gpt_header - GPT header - * @signature: EFI compatible header signature - * @version: spec revision number - * @size: size (bytes) of gpt header - * @crc: crc of gpt header - * @reserve: reserved by spec ... must be zero - * @my_lba: lba of gpt header - * @alternate_lba: lba of 2nd copy of gpt header - * @start_useable: lba of 1st block of useable area on disk - * @end_useable: lba of last block of useable area on disk - * @disk_id: GUID - identifies this disk - * @ptable_lba: lba of partition table - * @ptable_count: number of entries in the partition table - * @ptable_entry_size: size of partition table entry - * @ptable_crc: crc of partition table - * - * GPT header - **/ -struct gpt_header { - u64 signature; - u32 version; - u32 size; - u32 crc; - u32 reserve; - u64 my_lba; - u64 alternate_lba; - u64 start_useable; - u64 end_useable; - struct guid disk_id; - u64 ptable_lba; - u32 ptable_count; - u32 ptable_entry_size; - u32 ptable_crc; -}; - -struct guid EFI_SYSTEM_PARTITION = { - 0xC12A7328, - 0xF81F, - 0x11D2, - 0xBA, - 0x4B, - {0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B} -}; - -struct guid BASIC_DATA_PARTITION = { - 0xEBD0A0A2, - 0xB9E5, - 0x4433, - 0x87, - 0xC0, - {0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7} -}; - -struct guid LEGACY_MBR_PARTITION = { - 0x024DEE41, - 0x33E7, - 0x11D3, - 0x9D, - 0x69, - {0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F} -}; - -struct guid GPT_SWAP_PARTITION = { - 0x0657FD6D, - 0xA4AB, - 0x43C4, - 0x84, - 0xE5, - {0x09, 0x33, 0xC8, 0x4B, 0x4F, 0x4F} -}; - -struct guid UNUSED_GPT_PARTITION = { - 0, 0, 0, 0, 0, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -static int exported_nodes; /* total # of exported segments - * produced during this discovery. - */ - -/* Prototypes */ -static int partition_discover(struct evms_logical_node **); -static int partition_delete(struct evms_logical_node *); -static void partition_read(struct evms_logical_node *, struct buffer_head *); -static void partition_write(struct evms_logical_node *, struct buffer_head *); -static int partition_ioctl(struct evms_logical_node *, - struct inode *, - struct file *, unsigned int, unsigned long); -static int partition_init_io(struct evms_logical_node *, - int, u64, u64, void *); - -static struct evms_plugin_fops fops = { - .discover = partition_discover, - .delete = partition_delete, - .read = partition_read, - .write = partition_write, - .init_io = partition_init_io, - .ioctl = partition_ioctl -}; - -#define EVMS_GPT_PARTITION_MANAGER_ID 3 - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_SEGMENT_MANAGER, - EVMS_GPT_PARTITION_MANAGER_ID), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2 - }, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0 - }, - .fops = &fops -}; - -/***************************************************/ -/* List Support - Typedefs, Variables, & Functions */ -/***************************************************/ - -/* Typedefs */ - -struct segment_list_node { - struct evms_logical_node *segment; - struct segment_list_node *next; -}; - -struct disk_list_node { - struct evms_logical_node *disk; - struct segment_list_node *segment_list; - struct disk_list_node *next; -}; - -/* Variables */ - -static struct disk_list_node *my_disk_list; - -/* Functions */ - -/* - * Function: Convert a GPT header from disk format to the arch specific - * format. - */ -static void -disk_gpt_header_to_cpu(struct gpt_header *gh) -{ - gh->signature = le64_to_cpu(gh->signature); - gh->version = le32_to_cpu(gh->version); - gh->size = le32_to_cpu(gh->size); - gh->crc = le32_to_cpu(gh->crc); - gh->reserve = le32_to_cpu(gh->reserve); - gh->my_lba = le64_to_cpu(gh->my_lba); - gh->alternate_lba = le64_to_cpu(gh->alternate_lba); - gh->start_useable = le64_to_cpu(gh->start_useable); - gh->end_useable = le64_to_cpu(gh->end_useable); - gh->disk_id.time_low = le32_to_cpu(gh->disk_id.time_low); - gh->disk_id.time_mid = le16_to_cpu(gh->disk_id.time_mid); - gh->disk_id.time_high = le16_to_cpu(gh->disk_id.time_high); - gh->ptable_lba = le64_to_cpu(gh->ptable_lba); - gh->ptable_count = le32_to_cpu(gh->ptable_count); - gh->ptable_entry_size = le32_to_cpu(gh->ptable_entry_size); - gh->ptable_crc = le32_to_cpu(gh->ptable_crc); -} - -static int -matching_guids(struct guid *g1, struct guid *g2) -{ - if ((le32_to_cpu(g1->time_low) == g2->time_low) && - (le16_to_cpu(g1->time_mid) == g2->time_mid) && - (le16_to_cpu(g1->time_high) == g2->time_high) && - (g1->clock_seq_high == g2->clock_seq_high) && - (g1->clock_seq_low == g2->clock_seq_low)) { - return 1; - } - return 0; -} -static inline int -isa_basic_data_gpt_partition_record(struct gpt_partition *p) -{ - return (matching_guids(&p->type, &BASIC_DATA_PARTITION)); -} -static inline int -isa_legacy_mbr_gpt_partition_record(struct gpt_partition *p) -{ - return (matching_guids(&p->type, &LEGACY_MBR_PARTITION)); -} -static inline int -isa_esp_gpt_partition_record(struct gpt_partition *p) -{ - return (matching_guids(&p->type, &EFI_SYSTEM_PARTITION)); -} -static inline int -isa_gpt_swap_partition_record(struct gpt_partition *p) -{ - return (matching_guids(&p->type, &GPT_SWAP_PARTITION)); -} -static inline int -isa_unused_gpt_partition_record(struct gpt_partition *p) -{ - return (matching_guids(&p->type, &UNUSED_GPT_PARTITION)); -} - -static struct disk_list_node ** -lookup_disk(struct evms_logical_node *disk) -{ - struct disk_list_node **ldln; - - ldln = &my_disk_list; - while (*ldln) { - if ((*ldln)->disk == disk) - break; - ldln = &(*ldln)->next; - } - return (ldln); -} - -static struct segment_list_node ** -lookup_segment(struct disk_list_node *disk, struct evms_logical_node *segment) -{ - struct segment_list_node **lsln; - - lsln = &disk->segment_list; - while (*lsln) { - if ((*lsln)->segment == segment) - break; - lsln = &(*lsln)->next; - } - return (lsln); -} - -static struct evms_logical_node * -find_segment_on_disk(struct evms_logical_node *disk, - u64 start_sect, u64 nr_sects) -{ - struct evms_logical_node *rc = NULL; - struct disk_list_node **ldln; - struct segment_list_node **lsln; - struct gpt_private *gpt_prv; - - ldln = lookup_disk(disk); - if (*ldln) { - /* disk found in list */ - /* attempt to find segment */ - - lsln = &(*ldln)->segment_list; - while (*lsln) { - gpt_prv = (*lsln)->segment->private; - if (gpt_prv->start_sect == start_sect) - if (gpt_prv->nr_sects == nr_sects) - break; - lsln = &(*lsln)->next; - } - if (*lsln) - rc = (*lsln)->segment; - } - return (rc); -} - -/* function description: add_segment_to_disk - * - * this function attempts to add a segment to the segment - * list of a disk. if the specified disk is not found, it - * will be added to the global disk list. this function will - * return a pointer to the matching segment in the disk's - * segment list. the caller must compare the returned pointer - * to the specified segment to see if the - * specified segment was already present in the disk's segment - * list. if the return pointer matches the specified segment, - * then the specified segment was added to the list. if the - * return segment pointer to does not match the specified - * segment pointer, then the specified segment pointer was - * a duplicate and can be thrown away. - */ -static int -add_segment_to_disk(struct evms_logical_node *disk, - struct evms_logical_node *segment) -{ - int rc = 0; - struct disk_list_node **ldln, *new_disk; - struct segment_list_node **lsln, *new_segment; - - ldln = lookup_disk(disk); - if (*ldln == NULL) { - /* disk not in list, add disk */ - new_disk = kmalloc(sizeof (*new_disk), GFP_KERNEL); - if (new_disk) { - memset(new_disk, 0, sizeof (*new_disk)); - new_disk->disk = disk; - *ldln = new_disk; - } else { - rc = -ENOMEM; - } - } - if (!rc) { - /* attempt to add segment */ - lsln = lookup_segment(*ldln, segment); - if (*lsln == NULL) { - /* segment not in list, add segment */ - new_segment = - kmalloc(sizeof (*new_segment), GFP_KERNEL); - if (new_segment) { - memset(new_segment, 0, sizeof (*new_segment)); - new_segment->segment = segment; - *lsln = new_segment; - } else { - rc = -ENOMEM; - } - } else - rc = -1; - } - return (rc); -} - -static int -remove_segment_from_disk(struct evms_logical_node *disk, - struct evms_logical_node *segment, - struct evms_logical_node **empty_disk) -{ - int rc = 0; - struct disk_list_node **ldln, *tmp_disk_node; - struct segment_list_node **lsln, *tmp_segment_node; - - *empty_disk = NULL; - ldln = lookup_disk(disk); - if (*ldln == NULL) { - rc = -1; - } else { - /* disk found in list */ - /* attempt to add segment */ - lsln = lookup_segment(*ldln, segment); - if (*lsln == NULL) { - rc = -2; - } else { - tmp_segment_node = *lsln; - /* remove segment from list */ - *lsln = (*lsln)->next; - /* free the segment list node */ - kfree(tmp_segment_node); - - if ((*ldln)->segment_list == NULL) { - tmp_disk_node = *ldln; - *empty_disk = tmp_disk_node->disk; - /* remove disk from list */ - *ldln = (*ldln)->next; - /* free the disk list node */ - kfree(tmp_disk_node); - } - } - } - return (rc); -} - -/* - * Function: add_segment - */ -static int -process_segment(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - u64 start_sect, - u64 nr_sects, - int type, int part_num, int evms_top_segment) -{ - struct gpt_private *gpt_prv = NULL; - struct evms_logical_node *segment; - int rc = 0; - - segment = find_segment_on_disk(node, start_sect, nr_sects); - if (segment) { - LOG_DETAILS("exporting segment '%s'.\n", segment->name); - } else { - gpt_prv = kmalloc(sizeof (*gpt_prv), GFP_KERNEL); - if (gpt_prv) { - gpt_prv->source_disk = node; - gpt_prv->start_sect = start_sect; - gpt_prv->nr_sects = nr_sects; - gpt_prv->type = type; - rc = evms_cs_allocate_logical_node(&segment); - } else { - rc = -ENOMEM; - } - if (!rc) { - segment->plugin = &plugin_header; - segment->system_id = (unsigned int) type; - segment->total_vsectors = nr_sects; - segment->block_size = node->block_size; - segment->hardsector_size = node->hardsector_size; - segment->private = gpt_prv; - segment->flags = node->flags; - if (evms_top_segment) - segment->iflags |= EVMS_TOP_SEGMENT; - strcpy(segment->name, node->name); - if (GetPluginType(node->plugin->id) == - EVMS_SEGMENT_MANAGER) { - strcat(segment->name, "."); - } - sprintf(segment->name + strlen(segment->name), "%d", - part_num); - LOG_DETAILS("creating segment '%s'.\n", segment->name); - rc = add_segment_to_disk(node, segment); - if (rc) { - LOG_ERROR - ("%s: error(%d) adding segment '%s'!\n", - __FUNCTION__, rc, segment->name); - rc = 0; - } else { - MOD_INC_USE_COUNT; - } - } - if (rc) { - if (gpt_prv) - kfree(gpt_prv); - if (segment) - evms_cs_deallocate_logical_node(segment); - } - } - if (!rc) { - evms_cs_add_logical_node_to_list(discover_list, segment); - exported_nodes++; - } - return rc; -} - -void -print_mem(void *buffer, int length) -{ - int i, done; - unsigned char *bufptr; - - bufptr = (unsigned char *) buffer; - i = done = 0; - while (!done) { - if ((i % 16) == 0) - printk(KERN_INFO "\n0x%p->", buffer + i); - printk(KERN_INFO "%02x ", bufptr[i]); - if (++i >= length) - done++; - } - printk(KERN_INFO "\n"); -} - -/* - * Function: get GPT Partition Table - reads partition table - * into memory and performs crc check. - * - */ -static struct gpt_partition * -get_gpt_partition_table(struct evms_logical_node *node, struct gpt_header *gh) -{ - int rc; - struct gpt_partition *pt; - u32 sector_count, calculated_crc; - - sector_count = - evms_cs_size_in_vsectors(gh->ptable_count * gh->ptable_entry_size); - - pt = kmalloc(sector_count * EVMS_VSECTOR_SIZE, GFP_KERNEL); - if (pt) { - - rc = INIT_IO(node, 0, gh->ptable_lba, sector_count, pt); - if (!rc) { - - calculated_crc = evms_cs_calculate_crc(EVMS_INITIAL_CRC, - pt, - gh-> - ptable_count * - gh-> - ptable_entry_size); - - if (~calculated_crc != gh->ptable_crc) { - rc = -ENODATA; - } - - } - } else { - rc = -ENOMEM; - } - - if (rc) { - if (pt) - kfree(pt); - pt = NULL; - } - - return (pt); -} - -/* - * Function: Validate GPT Header - runs basic checks to - * sanity check a gpt header. - * - */ -static int -isa_valid_gpt_header(struct evms_logical_node *node, u64 lsn, - struct gpt_header *gh) -{ - u32 crc; - u32 calculated_crc; - u64 sector_count; - - /* signature */ - if (le64_to_cpu(gh->signature) != GPT_DISKMAGIC) - return 0; - - /* crc */ - crc = le32_to_cpu(gh->crc); - gh->crc = 0; - calculated_crc = - ~(evms_cs_calculate_crc(EVMS_INITIAL_CRC, gh, le32_to_cpu(gh->size))); - gh->crc = cpu_to_le32(crc); - - if (calculated_crc != crc) - return 0; - - /* spec says lba reported by header must match actual location on disk */ - if (lsn != le64_to_cpu(gh->my_lba)) - return 0; - - /* sanity check partition table info found in header */ - if (gh->ptable_count == 0 || gh->ptable_entry_size == 0) - return 0; - - sector_count = - evms_cs_size_in_vsectors(le64_to_cpu(gh->ptable_count) * - le64_to_cpu(gh->ptable_entry_size)); - - if ((le64_to_cpu(gh->ptable_lba) + sector_count - 1) >= - node->total_vsectors - 1) - return 0; - - return 1; -} - -/* - * Function: get GPT Partition Table Header - * - */ -static struct gpt_header * -get_gpt_header(struct evms_logical_node *node, u64 lsn) -{ - int rc; - struct gpt_header *gh = NULL; - - gh = kmalloc(EVMS_VSECTOR_SIZE, GFP_KERNEL); - if (gh) { - rc = INIT_IO(node, 0, lsn, 1, gh); - if (!rc) { - if (isa_valid_gpt_header(node, lsn, gh)) { - disk_gpt_header_to_cpu(gh); - } else { - rc = -ENODATA; - } - - } - if (rc) { - kfree(gh); - gh = NULL; - } - } - - return (gh); -} - -/* - * Function: Get GPT Information - * - */ -static int -get_gpt_info(struct evms_logical_node *node, - struct gpt_header **gh, struct gpt_partition **ptable) -{ - struct gpt_header *gh1 = NULL, *gh2 = NULL; - - *gh = NULL; - *ptable = NULL; - - gh1 = get_gpt_header(node, 1); // offset past protective mbr - - if (gh1) { - *gh = gh1; - gh2 = get_gpt_header(node, gh1->alternate_lba); - if (gh2) - kfree(gh2); - else - LOG_WARNING - ("alternate guid partition table header is invalid, using primary copy.\n"); - } else { - gh2 = get_gpt_header(node, node->total_vsectors - 1); - if (gh2) { - *gh = gh2; - LOG_WARNING - ("primary guid partition table header is invalid, using alternate copy\n"); - } else { - LOG_DETAILS("no gpt header discovered on node %s\n", - node->name); - return 0; - } - } - - *ptable = get_gpt_partition_table(node, *gh); - if (!*ptable) { - kfree(*gh); - *gh = NULL; - return 0; - } - - return 1; -} - -/* - * Function: Probe for GPT segments on logical node - * - */ -static int -probe_for_segments(struct evms_logical_node **discover_list, - struct evms_logical_node *node) -{ - int rc; - int evms_top_segment; - u32 i; - u64 pstart,pend; - struct gpt_header *gh = NULL; - struct gpt_partition *ptable = NULL; - struct gpt_partition *part = NULL; - - /* no need to inspect our own nodes */ - if (node->plugin->id == plugin_header.id) - return 0; - - /* nor nodes marked as EVMS_TOP_SEGMENT */ - if (node->iflags & EVMS_TOP_SEGMENT) - return 0; - - /* look for guid partition table & header */ - if (!get_gpt_info(node, &gh, &ptable)) { - if (gh) - kfree(gh); - if (ptable) - kfree(ptable); - return 0; - } - - /* walk the guid partition table, producing segment storage objects */ - for (i = 0, part = ptable; i < gh->ptable_count; i++, part++) { - - if (!isa_unused_gpt_partition_record(part)) { - - pstart = le64_to_cpu(part->start); - pend = le64_to_cpu(part->end); - - LOG_DETAILS - ("gpt partition start="PFU64" end="PFU64"\n", - pstart, (pend - pstart + 1)); - - /* stop other seg mgrs from recursive discovery on a gpt system partition */ - if (isa_esp_gpt_partition_record(part)) - evms_top_segment = 1; - else - evms_top_segment = 0; - - rc = process_segment(discover_list, - node, - pstart, - (pend - pstart + 1), - 0, i+1, evms_top_segment); - - } - - } - - /* remove node we just consumed */ - evms_cs_remove_logical_node_from_list(discover_list, node); - - kfree(ptable); - kfree(gh); - return 1; -} - -/* - * Function: partition_discover - * - */ -static int -partition_discover(struct evms_logical_node **discover_list) -{ - int rc = 0; - struct evms_logical_node *node, *next_node; - - MOD_INC_USE_COUNT; - LOG_ENTRY_EXIT("%s: ENTRY\n", __FUNCTION__); - - /* initialize global variable */ - exported_nodes = 0; - - /* examine each node on the discover list */ - next_node = *discover_list; - while (next_node) { - node = next_node; - next_node = node->next; - probe_for_segments(discover_list, node); - } - - LOG_ENTRY_EXIT("%s: EXIT(exported nodes:%d, error code:%d)\n", - __FUNCTION__, exported_nodes, rc); - if (exported_nodes) - rc = exported_nodes; - MOD_DEC_USE_COUNT; - return (rc); -} - -/* - * Function: partition_delete - * - */ -static int -partition_delete(struct evms_logical_node *segment) -{ - int rc = 0; - struct gpt_private *gpt_prv; - struct evms_logical_node *empty_disk = NULL; - - LOG_DETAILS("deleting segment '%s'.\n", segment->name); - - if (!segment) { - rc = -ENODEV; - } else { - gpt_prv = segment->private; - if (gpt_prv) { - /* remove the segment from the - * disk's segment list - */ - rc = remove_segment_from_disk(gpt_prv->source_disk, - segment, &empty_disk); - /* free the local instance data */ - kfree(gpt_prv); - } - /* free the segment node */ - evms_cs_deallocate_logical_node(segment); - MOD_DEC_USE_COUNT; - /* if the last segment on the disk was - * deleted, delete the disk node too - */ - if (empty_disk) - DELETE(empty_disk); - } - return (rc); -} - -/* - * function: partition_io_error - * - * this function was primarily created because the function - * buffer_IO_error is inline and kgdb doesn't allow breakpoints - * to be set on inline functions. Since this was an error path - * and not mainline, I decided to add a trace statement to help - * report on the failing condition. - * - */ -static void -partition_io_error(struct evms_logical_node *node, int io_flag, - struct buffer_head *bh) -{ - LOG_SERIOUS - ("attempt to %s beyond partition boundary("PFU64") on (%s), rsector(%ld).\n", - (io_flag) ? "WRITE" : "READ", node->total_vsectors - 1, node->name, - bh->b_rsector); - - bh->b_end_io(bh, 0); -} - -/* - * Function: partition_read - * - */ -static void -partition_read(struct evms_logical_node *partition, struct buffer_head *bh) -{ - struct gpt_private *gpt_prv = partition->private; - - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) <= - partition->total_vsectors) { - bh->b_rsector += gpt_prv->start_sect; - R_IO(gpt_prv->source_disk, bh); - } else - partition_io_error(partition, READ, bh); -} - -/* - * Function: partition_write - * - */ -static void -partition_write(struct evms_logical_node *partition, struct buffer_head *bh) -{ - struct gpt_private *gpt_prv = partition->private; - - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) <= - partition->total_vsectors) { - bh->b_rsector += gpt_prv->start_sect; - W_IO(gpt_prv->source_disk, bh); - } else - partition_io_error(partition, WRITE, bh); -} - -/* - * Function: partition_init_io - * - */ -static int -partition_init_io(struct evms_logical_node *partition, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr) -{ /* buffer address */ - int rc; - struct gpt_private *gpt_prv = partition->private; - - if ((sect_nr + num_sects) <= partition->total_vsectors) { - rc = INIT_IO(gpt_prv->source_disk, io_flag, - sect_nr + gpt_prv->start_sect, num_sects, - buf_addr); - } else { - LOG_SERIOUS - ("init_io: attempt to %s beyond partition(%s) boundary("PFU64") at sector("PFU64") for count("PFU64").\n", - (io_flag) ? "WRITE" : "READ", partition->name, - (gpt_prv->nr_sects - 1), sect_nr, num_sects); - rc = -EINVAL; - } - - return (rc); -} - -/* - * Function: partition_ioctl - * - */ -static int -partition_ioctl(struct evms_logical_node *partition, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - struct gpt_private *gpt_prv; - struct hd_geometry hd_geo; - int rc; - - rc = 0; - gpt_prv = partition->private; - if (!inode) - return -EINVAL; - switch (cmd) { - case HDIO_GETGEO: - { - rc = IOCTL(gpt_prv->source_disk, inode, file, cmd, arg); - if (rc) - break; - if (copy_from_user - (&hd_geo, (void *) arg, - sizeof (struct hd_geometry))) - rc = -EFAULT; - if (rc) - break; - hd_geo.start = gpt_prv->start_sect; - if (copy_to_user - ((void *) arg, &hd_geo, - sizeof (struct hd_geometry))) - rc = -EFAULT; - } - break; - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = - (struct evms_get_bmap_pkt *) arg; - bmap->rsector += gpt_prv->start_sect; - /* intentionally fall thru to - * default ioctl down to device - * manager. - */ - } - default: - rc = IOCTL(gpt_prv->source_disk, inode, file, cmd, arg); - } - return rc; -} - -/* - * Function: gpt_module_init - * - */ -static int __init -gpt_module_init(void) -{ - return evms_cs_register_plugin(&plugin_header); /* register with EVMS */ -} - -/* - * Function: gpt module exit - */ -static void __exit -gpt_module_exit(void) -{ - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(gpt_module_init); -module_exit(gpt_module_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/ldev_mgr.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/ldev_mgr.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/ldev_mgr.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/ldev_mgr.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1500 +0,0 @@ -/* -*- linux-c -*- */ -/* - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ - -/* linux/driver/evms/ldev_mgr.c - * - * EVMS - Local Device (Hard Drive) Manager - * - * This plugin walks the gendisk list and creates logical disk structures for each - * local ide or scsi device. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* must be included by all block drivers */ -#include -#include -#include -#include "../scsi/scsi.h" -#include "../scsi/sd.h" -#include -#include -#include - -#define LOG_PREFIX "ldev_mgr: " - -#define EVMS_LOCAL_DEVICE_MANAGER_ID 1 - -/** - * struct ldev_private - private data used by this plugin - * @major: major device number - * @minor: minor device number - * @bdev: block_device record for this device - * @gd: gendisk entry for this device - * @media_changed: media changed status field - * - * private data maintained for each device by this plugin - **/ -struct ldev_private { - int major, minor; - struct block_device *bdev; - struct gendisk *gd; - int media_changed; -}; - -/* prototypes for mandatory plugin interface functions */ -static int discover_disks(struct evms_logical_node **); -static int ldev_mgr_delete(struct evms_logical_node *); -static void ldev_mgr_read(struct evms_logical_node *, struct buffer_head *); -static void ldev_mgr_write(struct evms_logical_node *, struct buffer_head *); -static int ldev_mgr_ioctl(struct evms_logical_node *, - struct inode *, - struct file *, unsigned int, unsigned long); -static int ldev_init_io(struct evms_logical_node *, - int, u64, u64, void *); -static int ldev_mgr_direct_ioctl(struct inode *, - struct file *, unsigned int, unsigned long); - -/* plugin function table definition */ -static struct evms_plugin_fops fops = { - .discover = discover_disks, - .delete = ldev_mgr_delete, - .read = ldev_mgr_read, - .write = ldev_mgr_write, - .init_io = ldev_init_io, - .ioctl = ldev_mgr_ioctl, - .direct_ioctl = ldev_mgr_direct_ioctl -}; - -/* plugin header definition */ -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_DEVICE_MANAGER, - EVMS_LOCAL_DEVICE_MANAGER_ID), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2 - }, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0 - }, - .fops = &fops -}; - -#define TYPE_NONE 0 -#define TYPE_GENERIC 1 -#define TYPE_IDE 2 -#define TYPE_SCSI 3 - -#define INDEX_ALPHA 0 -#define INDEX_NUMERIC 1 - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Discover function & Support routines */ -/********************************************************/ - -#define MAX_NAME_BASE_SIZE 10 -#define MAX_NAME_MODIFIER_SIZE 4 -/** - * struct blk_device_info - block device info - * @devnode_name_base: base name (ie. hd or sd) for device - * @null1: guaranteed end-of-string NULL - * @devnode_name_modifier: name suffix (ie. ag for sdag) for device - * @null2: guaranteed end-of-string NULL - * @devnode_name_index: numeric device index (ie. 1 for hda1) - * @devnode_name_type: indicates numeric or alpha modifier - * @devnode_type: device type, IDE, SCSI, or GENERIC - * - * generic block device naming descriptor structure - **/ -struct blk_device_info { - char devnode_name_base[MAX_NAME_BASE_SIZE]; - char null1; - char devnode_name_modifier[MAX_NAME_MODIFIER_SIZE]; - char null2; - int devnode_name_index; - int devnode_name_type; - int device_type; -}; - -static struct blk_device_info *blk_dev_info = NULL; - -#define BLK_DEV_INFO(a,b,c,d,e) \ - strncpy(blk_dev_info[a].devnode_name_base, b, MAX_NAME_BASE_SIZE); \ - blk_dev_info[a].null1 = 0; \ - strncpy(blk_dev_info[a].devnode_name_modifier, c, MAX_NAME_MODIFIER_SIZE); \ - blk_dev_info[a].null2 = 0; \ - blk_dev_info[a].devnode_name_index = 0; \ - blk_dev_info[a].device_type = d; \ - blk_dev_info[a].devnode_name_type = e; - -static void -init_blk_dev_info(struct blk_device_info *blk_dev_info) -{ - BLK_DEV_INFO(IDE0_MAJOR, "hd", "a", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE1_MAJOR, "hd", "c", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE2_MAJOR, "hd", "e", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE3_MAJOR, "hd", "g", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE4_MAJOR, "hd", "i", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE5_MAJOR, "hd", "k", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE6_MAJOR, "hd", "m", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE7_MAJOR, "hd", "o", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE8_MAJOR, "hd", "q", TYPE_IDE, INDEX_ALPHA); - BLK_DEV_INFO(IDE9_MAJOR, "hd", "s", TYPE_IDE, INDEX_ALPHA); - - BLK_DEV_INFO(SCSI_DISK0_MAJOR, "sd", "a", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK1_MAJOR, "sd", "q", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK2_MAJOR, "sd", "ag", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK3_MAJOR, "sd", "aw", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK4_MAJOR, "sd", "bm", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK5_MAJOR, "sd", "cc", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK6_MAJOR, "sd", "cs", TYPE_SCSI, INDEX_ALPHA); - BLK_DEV_INFO(SCSI_DISK7_MAJOR, "sd", "di", TYPE_SCSI, INDEX_ALPHA); - - BLK_DEV_INFO(XT_DISK_MAJOR, "xd", "a", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(CYCLADES_MAJOR, "double", "0", TYPE_GENERIC, - INDEX_NUMERIC); - - BLK_DEV_INFO(MFM_ACORN_MAJOR, "mfm", "a", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(ACSI_MAJOR, "ad", "a", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(PS2ESDI_MAJOR, "ed", "a", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(40, "ez", "a", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(43, "nb", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(44, "ftl", "a", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(45, "pd", "a", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(47, "pf", "0", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(DAC960_MAJOR + 0, "rd/c0d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 1, "rd/c1d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 2, "rd/c2d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 3, "rd/c3d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 4, "rd/c4d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 5, "rd/c5d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 6, "rd/c6d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(DAC960_MAJOR + 7, "rd/c7d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR, "ida/c0d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR1, "ida/c1d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR2, "ida/c2d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR3, "ida/c3d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR4, "ida/c4d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR5, "ida/c5d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR6, "ida/c6d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - BLK_DEV_INFO(COMPAQ_SMART2_MAJOR7, "ida/c7d", "0", TYPE_GENERIC, - INDEX_NUMERIC); - - BLK_DEV_INFO(I2O_MAJOR + 0, "i2o/hd", "a", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 1, "i2o/hd", "q", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 2, "i2o/hd", "ag", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 3, "i2o/hd", "aw", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 4, "i2o/hd", "bm", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 5, "i2o/hd", "cc", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 6, "i2o/hd", "cs", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(I2O_MAJOR + 7, "i2o/hd", "di", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(92, "ppdd", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(93, "nftl", "a", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(DASD_MAJOR, "dasd", "a", TYPE_GENERIC, INDEX_ALPHA); - BLK_DEV_INFO(MDISK_MAJOR, "mdisk", "a", TYPE_GENERIC, INDEX_ALPHA); - - BLK_DEV_INFO(96, "msd", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(97, "pktcdvd", "0", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(UBD_MAJOR, "ubd", "0", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(JSFD_MAJOR, "jsfd", "", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(101, "amiraid/ar", "0", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(104, "cciss/c0d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(105, "cciss/c1d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(106, "cciss/c2d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(107, "cciss/c3d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(108, "cciss/c4d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(108, "cciss/c5d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(110, "cciss/c6d", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(111, "cciss/c7d", "0", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(RAW_MAJOR, "raw", "0", TYPE_GENERIC, INDEX_NUMERIC); - - BLK_DEV_INFO(VXVM_MAJOR, "vx/dsk", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(VXDMP_MAJOR, "vx/dmp", "0", TYPE_GENERIC, INDEX_NUMERIC); - BLK_DEV_INFO(LOOP_MAJOR, "loop", "0", TYPE_GENERIC, INDEX_NUMERIC); -} - -static int -is_in_device_list(struct gendisk *gd, int major, int minor) -{ - int found, done, rc; - struct evms_logical_node *device = NULL; - struct ldev_private *ldev_prv; - - done = found = FALSE; - while (done == FALSE) { - rc = evms_cs_find_next_device(device, &device); - if (rc || !device) - done = TRUE; - else { - ldev_prv = device->private; - if (ldev_prv->gd == gd) - if (ldev_prv->major == major) - if (ldev_prv->minor == minor) - done = found = TRUE; - } - } - return (found); -} - -static void -build_devnode_name(char *name_buf, int major) -{ - char buf[11], *modifier, *buf_ptr; - int int_mod, done; - struct blk_device_info *bdi; - - bdi = &blk_dev_info[major]; - - /* convert the base name modifier to an integer */ - modifier = bdi->devnode_name_modifier; - int_mod = 0; - while (*modifier) { - if (bdi->devnode_name_type == INDEX_ALPHA) { - int_mod *= 26; - int_mod += *modifier - 'a'; - } else { - int_mod *= 10; - int_mod += *modifier - '0'; - } - modifier++; - if (*modifier) { - int_mod++; - } - } - /* add in device_index_value */ - int_mod += bdi->devnode_name_index; - bdi->devnode_name_index++; - - /* convert integer modifier back to ALPHA/NUMERIC chars */ - memset(buf, 0, sizeof (buf)); - /* fill the buffer from the rear to front with the - * ascii version of the modifier, leaving space for - * NULL terminator at the end. - */ - buf_ptr = &buf[sizeof (buf) - 2]; - done = FALSE; - do { - if (bdi->devnode_name_type == INDEX_ALPHA) { - *buf_ptr = (int_mod % 26) + 'a'; - int_mod /= 26; - } else { - *buf_ptr = (int_mod % 10) + '0'; - int_mod /= 10; - } - if (int_mod) { - int_mod--; - } else { - done = TRUE; - } - buf_ptr--; - } while (!done); - - /* find beginning of modifier in buffer */ - modifier = buf; - while (!*modifier) - modifier++; - - /* build the final device devnode name */ - sprintf(name_buf, "%s%s", bdi->devnode_name_base, modifier); -} - -static int -ldev_mgr_lock_device(struct ldev_private *ldev_prv) -{ - int rc; - struct block_device *bdev; - - bdev = bdget(MKDEV(ldev_prv->major, ldev_prv->minor)); - if (!bdev) - return -ENOMEM; - rc = blkdev_get(bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW); - if (rc) - return rc; - ldev_prv->bdev = bdev; - return 0; -} - -static void -ldev_mgr_unlock_device(struct ldev_private *ldev_prv) -{ - struct block_device *bdev = ldev_prv->bdev; - ldev_prv->bdev = NULL; - if (!bdev) { - LOG_ERROR("error: NULL bdev field detected!\n"); - BUG(); - } - blkdev_put(bdev, BDEV_RAW); -} - -#define DEVICE_KNOWN 1234 -#define DEVICE_UNINITIALIZED 1235 -#define DEVICE_MEDIA_NOT_PRESENT 1236 -static int -create_logical_disk(struct evms_logical_node **disk_list, - struct gendisk *gd, int device_index) -{ - int rc = 0, major, minor; - struct evms_logical_node *new_disk = NULL; - struct ldev_private *ldev_prv = NULL; - char device_name[EVMS_VOLUME_NAME_SIZE + 1]; - - major = gd->major; - minor = device_index << gd->minor_shift; - - /* skip uninitialized devices */ - if (!blk_size[major]) - rc = DEVICE_UNINITIALIZED; - else if (!blk_size[major][minor]) - rc = DEVICE_UNINITIALIZED; - if (!rc) { - /* construct the devnode name for this device */ - build_devnode_name(device_name, major); - - /* skip devices we already know about */ - if (is_in_device_list(gd, major, minor) == TRUE) - rc = DEVICE_KNOWN; - } - /* allocate the new node */ - if (!rc) { - rc = evms_cs_allocate_logical_node(&new_disk); - } - /* allocate new nodes's instance data */ - if (!rc) { - ldev_prv = kmalloc(sizeof(struct ldev_private), GFP_KERNEL); - if (!ldev_prv) - rc = -ENOMEM; - } - /* initialize the new node */ - if (!rc) { - memset(ldev_prv, 0, sizeof(struct ldev_private)); - new_disk->plugin = &plugin_header; - - /* initialize the instance data */ - new_disk->private = ldev_prv; - ldev_prv->gd = gd; - ldev_prv->major = major; - ldev_prv->minor = minor; - rc = ldev_mgr_lock_device(ldev_prv); - if (rc) { - LOG_ERROR("error(%d): unable to lock device(%d,%d)!\n", - rc, major, minor); - } - } - if (!rc) { - /* determine hardsector size */ - new_disk->hardsector_size = 512; - if (hardsect_size[major]) { - new_disk->hardsector_size = hardsect_size[major][minor]; - } - /* save the block size */ - new_disk->block_size = 1024; - if (blksize_size[major]) { - new_disk->block_size = blksize_size[major][minor]; - } - /* obtain the device size in sectors - * - * try 64bit size first, if that fails - * fall back on the 32bit size. - */ - /* try 64bit size */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) - rc = evms_cs_kernel_ioctl(new_disk, BLKGETSIZE64, - (ulong) & new_disk->total_vsectors); - if (!rc) { - /* convert bytes to 512 byte sectors */ - new_disk->total_vsectors >>= EVMS_VSECTOR_SIZE_SHIFT; - } else -#endif - { - /* try 32bit size */ - ulong dev_size = 0; - rc = evms_cs_kernel_ioctl(new_disk, BLKGETSIZE, - (ulong) & dev_size); - new_disk->total_vsectors = dev_size; - } - if (!rc && !new_disk->total_vsectors) { - rc = -ENOSPC; - } - } - if (!rc) { - /* remember removable devices */ - if (gd->flags) - if (gd->flags[device_index] & GENHD_FL_REMOVABLE) - new_disk->flags |= EVMS_DEVICE_REMOVABLE; - - /* save the devnode name for this device */ - strcpy(new_disk->name, device_name); - - /* register this device with evms */ - evms_cs_register_device(new_disk); - MOD_INC_USE_COUNT; - - /* append this record the linked list */ - evms_cs_add_logical_node_to_list(disk_list, new_disk); - LOG_DETAILS - ("added logical disk(%s) for physical disk(%u,%u,%s), size("PFU64") in 512 byte units\n", - new_disk->name, major, minor, new_disk->name, - new_disk->total_vsectors); - - } - /* reset the "benign" error codes for the caller */ - switch (rc) { - case DEVICE_UNINITIALIZED: - case DEVICE_KNOWN: - case DEVICE_MEDIA_NOT_PRESENT: - rc = 0; - case 0: - break; - default: - LOG_ERROR - ("error(%d): creating logical disk for device(%d,%d).\n", - rc, major, minor); - if (new_disk) { - evms_cs_deallocate_logical_node(new_disk); - } - if (ldev_prv) { - kfree(ldev_prv); - } - break; - } - return (rc); -} - -static int -create_logical_generic_disks(struct evms_logical_node **disk_list, - struct gendisk *gd) -{ - int rc, i; - - /* This is a generic device */ - - rc = 0; - LOG_EXTRA("major name = %s\n", gd->major_name); - LOG_EXTRA("number of real devices = %i\n", gd->nr_real); - for (i = 0; i < gd->nr_real; i++) { - LOG_EXTRA("device %d:\n", i); - rc = create_logical_disk(disk_list, gd, i); - if (rc) - break; - } - return (rc); -} - -static int -create_logical_ide_disks(struct evms_logical_node **disk_list, - struct gendisk *gd) -{ - int rc = 0, i; - ide_hwif_t *ide_hwif; - ide_drive_t *drive; - - /* This is an IDE device */ - LOG_EXTRA("found IDE major : %i - searching for disks\n", gd->major); - - ide_hwif = gd->real_devices; /* IDE internal data */ - for (i = 0; i < MAX_DRIVES; i++) { - drive = &(ide_hwif->drives[i]); - if (drive->present && (drive->media == ide_disk)) { - /* force the name index value on ide drives */ - blk_dev_info[gd->major].devnode_name_index = i; - rc = create_logical_disk(disk_list, gd, i); - } - if (rc) - break; - } - return (rc); -} - -static int -create_logical_scsi_disks(struct evms_logical_node **disk_list, - struct gendisk *gd) -{ - int rc = 0, i; - Scsi_Disk *SDisks; - Scsi_Device *SDev; - - /* This is an SCSI device */ - LOG_EXTRA("found SCSI major : %i - searching for disks\n", gd->major); - LOG_EXTRA("scsi: major name = %s\n", gd->major_name); - LOG_EXTRA("scsi: number of real devices = %i\n", gd->nr_real); - SDisks = gd->real_devices; /* SCSI internal data */ - for (i = 0; i < gd->nr_real; i++) { - SDev = SDisks[i].device; - LOG_EXTRA - ("scsi: Channel = %i, Id = %i, Lun = %i, Capacity = %i\n", - SDev->channel, SDev->id, SDev->lun, SDisks[i].capacity); - rc = create_logical_disk(disk_list, gd, i); - if (rc) - break; - } - return (rc); -} - -static int -create_logical_disks(struct gendisk *gd, void *p_disk_list) -{ - int rc = 0; - struct evms_logical_node **disk_list = p_disk_list; - - /* create logical disks from all IDE & SCSI devices */ - switch (blk_dev_info[gd->major].device_type) { - case TYPE_IDE: - rc = create_logical_ide_disks(disk_list, gd); - break; - case TYPE_SCSI: - rc = create_logical_scsi_disks(disk_list, gd); - break; - case TYPE_GENERIC: - rc = create_logical_generic_disks(disk_list, gd); - break; - default: - LOG_EXTRA("unrecognized device major : %i\n", gd->major); - break; - } - - return (rc); -} - -static int -discover_disks(struct evms_logical_node **disk_list) -{ - int rc = 0; - - MOD_INC_USE_COUNT; - LOG_ENTRY_EXIT("%s Entry\n", __FUNCTION__); - - if (blk_dev_info == NULL) { - /* allocate space for device info array */ - blk_dev_info = kmalloc(sizeof (struct blk_device_info) - * (MAX_BLKDEV + 1), GFP_KERNEL); - if (blk_dev_info) { - /* initialize device info array */ - memset(blk_dev_info, 0, - sizeof (struct blk_device_info) * (MAX_BLKDEV + 1)); - init_blk_dev_info(blk_dev_info); - } else { - rc = -ENOMEM; - } - } - if (!rc) - /* create logical disks from the raw devices */ - rc = walk_gendisk(create_logical_disks, disk_list); - - /* free blk_dev_info table and null the ptr to it */ - kfree(blk_dev_info); - blk_dev_info = NULL; - - LOG_ENTRY_EXIT("%s Exit\n", __FUNCTION__); - MOD_DEC_USE_COUNT; - return (rc); -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Delete function */ -/********************************************************/ - -static int -ldev_mgr_delete(struct evms_logical_node *disk) -{ - struct ldev_private *ldev_prv; - - /* reset any evms volume related info from - * the device node, because we can't predict - * how this node will be used in the future. - */ - - /* removed the feature header if its been used - */ - if (disk->feature_header) { - kfree(disk->feature_header); - disk->feature_header = NULL; - } - /* remove the volume_info structure and flag - * if this has been used directly by an evms - * feature. - */ - evms_cs_deallocate_volume_info(disk); - /* reset the flags field to the appropriate state - */ - disk->flags &= ~EVMS_VOLUME_FLAG; - - /* disk nodes only get deleted when: - * 1) there are no references to the disk node - * in memory. - * 2) the device is removable - * 3) the device reported a media change - * - * All three of these conditions must be true - * before the disk node can be deleted. - * evms_check_for_device_changes should set - * and ensure these conditions before issuing - * deletes. - * - * Newly installed removable media will be - * picked up in this modules discover code. - * - * OR disk nodes can will be deleted if the - * devices they represent go away, for example - * in the case of a hotunplugged device or a - * required driver having been unloaded. - */ - if (disk->flags & (EVMS_MEDIA_CHANGED | EVMS_DEVICE_UNAVAILABLE)) { - LOG_DETAILS("deleting '%s'.\n", disk->name); - - evms_cs_unregister_device(disk); - MOD_DEC_USE_COUNT; - ldev_prv = disk->private; - ldev_mgr_unlock_device(ldev_prv); - if (ldev_prv) { - kfree(ldev_prv); - } - evms_cs_deallocate_logical_node(disk); - } - return 0; -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Read function */ -/********************************************************/ - -/* - * function: ldev_mgr_io_error - * - * this function was primarily created because the function - * buffer_IO_error is inline and kgdb doesn't allow breakpoints - * to be set on inline functions. Since this was an error path - * and not mainline, I decided to add a trace statement to help - * report on the failing condition. - * - */ -static void -ldev_mgr_io_error(struct evms_logical_node *disk, int io_flag, struct buffer_head *bh, int rc) -{ - if (rc == -EOVERFLOW) { - LOG_SERIOUS - ("attempt to %s beyond boundary("PFU64") on (%s), rsector(%ld).\n", - (io_flag) ? "WRITE" : "READ", disk->total_vsectors - 1, - disk->name, bh->b_rsector); - } else if (rc == -ENXIO) { - LOG_SERIOUS("attempt to access a non-existent device(%s).\n", - disk->name); - } - bh->b_end_io(bh, 0); -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Read function */ -/********************************************************/ - -static void -ldev_mgr_read(struct evms_logical_node *disk, struct buffer_head *bh) -{ - int rc = 0; - request_queue_t *q; - struct ldev_private *ldev_prv; - - ldev_prv = disk->private; - if (bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) <= - disk->total_vsectors) { - bh->b_rdev = MKDEV(ldev_prv->major, ldev_prv->minor); - q = blk_get_queue(bh->b_rdev); - if (q) { - disk->flags &= ~EVMS_DEVICE_UNAVAILABLE; - q->make_request_fn(q, READ, bh); - return; - } else { - rc = -ENXIO; - disk->flags |= EVMS_DEVICE_UNAVAILABLE; - } - } else { - rc = -EOVERFLOW; - } - if (rc) { - ldev_mgr_io_error(disk, READ, bh, rc); - } -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Write function */ -/********************************************************/ - -static void -ldev_mgr_write(struct evms_logical_node *disk, struct buffer_head *bh) -{ - int rc = 0; - request_queue_t *q; - struct ldev_private *ldev_prv; - - ldev_prv = disk->private; - if (bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) <= - disk->total_vsectors) { - bh->b_rdev = MKDEV(ldev_prv->major, ldev_prv->minor); - q = blk_get_queue(bh->b_rdev); - if (q) { - disk->flags &= ~EVMS_DEVICE_UNAVAILABLE; - q->make_request_fn(q, WRITE, bh); - return; - } else { - rc = -ENXIO; - disk->flags |= EVMS_DEVICE_UNAVAILABLE; - } - } else { - rc = -EOVERFLOW; - } - if (rc) { - ldev_mgr_io_error(disk, WRITE, bh, rc); - } -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* Init_io function & Support routines */ -/********************************************************/ - -/* - * function: allocate_bh - * - * This function obtains a buffer head from the private - * buffer head pool (pre-allocated at EVMS initial - * discovery time). - * - * NOTE: All access to the buffer head pool are protected - * by a private spinlock. - * - */ -static inline struct buffer_head * -allocate_bh(void) -{ - struct buffer_head *bh = - evms_cs_allocate_from_pool(evms_bh_pool, FALSE); - if (bh) { - init_waitqueue_head(&bh->b_wait); - } - return (bh); -} - -/* - * function: deallocate_bh - * - * This function returns a buffer head to the private - * buffer head pool (pre-allocated at EVMS initial - * discovery time). - * - * NOTE: All access to the buffer head pool are protected - * by a private spinlock. - * - */ -static inline void -deallocate_bh(struct buffer_head *bh) -{ - evms_cs_deallocate_to_pool(evms_bh_pool, bh); -} - -/* this is the buffer head control block structure definition */ -typedef struct bh_cb_s { - int rc; - atomic_t blks_allocated; - wait_queue_head_t cb_wait; -} bh_cb_t; - -/* - * function: __wait_on_bh_cb - * - * This is a worker function to wait_on_bh_cb. - * This function waits for a set of private buffer heads - * associated to the specified buffer head control block - * to return from I/O completion. On completion of the - * last buffer head, the calling function is awakened - * and continues running. - * - * This is the worker function to the function wait_on_bh_cb. - * - */ -static void -__wait_on_bh_cb(bh_cb_t * bh_cb) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&bh_cb->cb_wait, &wait); - do { - run_task_queue(&tq_disk); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!atomic_read(&bh_cb->blks_allocated)) - break; - schedule(); - } while (atomic_read(&bh_cb->blks_allocated)); -#ifdef O1_SCHEDULER - set_task_state(tsk, TASK_RUNNING); -#else - tsk->state = TASK_RUNNING; -#endif - remove_wait_queue(&bh_cb->cb_wait, &wait); -} - -/* - * function: wait_on_bh_cb - * - * This function waits for a set of private buffer heads - * associated to the specified buffer head control block - * to return from I/O completion. On completion of the - * last buffer head, the calling function is awakened - * and continues running. - * - */ -static void -wait_on_bh_cb(bh_cb_t * bh_cb) -{ - if (atomic_read(&bh_cb->blks_allocated)) - __wait_on_bh_cb(bh_cb); - else - /* if we ended up with no buffer heads on - * this pass, lets wait a until a few buffer - * heads have been freed and try again. This - * should provide a reasonable delay. - */ - schedule(); -} - -/* - * function: end_bh_cb_io - * - * This is the I/O completion function that is called for - * each private buffer head obtained from the buffer head - * pool. Control is return thru this routine so we can track - * all outstanding requests to know when to awaken the caller, - * and to regain control after all I/Os have been performed. - * - */ -static void -end_bh_cb_io_sync(struct buffer_head *bh, int uptodate) -{ - bh_cb_t *bh_cb = (bh_cb_t *) bh->b_private; - - /* record that errors occurred */ - if (!uptodate) { - bh_cb->rc = -EIO; - } - mark_buffer_uptodate(bh, uptodate); - unlock_buffer(bh); - - deallocate_bh(bh); - atomic_dec(&bh_cb->blks_allocated); - if (!atomic_read(&bh_cb->blks_allocated)) - if (waitqueue_active(&bh_cb->cb_wait)) - wake_up(&bh_cb->cb_wait); -} - -/* - * function: ldev_partial_sector_init_io - * - * This function is a support function for ldev_init_io, - * which handles the cases of performing I/O to only a part - * of non-standard sized hardsector. This function is not - * designed to be called directly, but via ldev_init_io. - * - */ -static int -ldev_partial_sector_init_io(struct evms_logical_node *node, - int io_flag, - bh_cb_t * bh_cb, - u64 next_lsn, - u64 sector_lsn, - u64 io_size, - void *bufptr, unsigned char **sector_buf) -{ - int rc = 0; - struct ldev_private *ldev_prv = node->private; - kdev_t dev = MKDEV(ldev_prv->major, ldev_prv->minor); - struct buffer_head *bh; - - if (*sector_buf == NULL) { - /* allocate buffer for incoming sector */ - *sector_buf = kmalloc(node->hardsector_size, GFP_KERNEL); - if (!*sector_buf) - return -ENOMEM; - } - /* allocate a buffer head from the pool */ - while ((bh = allocate_bh()) == NULL) - /* yielding the cpu is playing it - * safe. it might be wiser to just - * spin. requires more thought. - */ - schedule(); - - /* set up the buffer head for this sector */ - bh->b_end_io = end_bh_cb_io_sync; - bh->b_size = node->hardsector_size; - bh->b_rdev = dev; - bh->b_rsector = next_lsn - sector_lsn; - bh->b_data = *sector_buf; - bh->b_page = virt_to_page(*sector_buf); /* this isn't handling the case of a block with more than 1 sector, that spans pages */ - bh->b_state = 0; - set_bit(BH_Dirty, &bh->b_state); - set_bit(BH_Lock, &bh->b_state); - set_bit(BH_Req, &bh->b_state); - set_bit(BH_Mapped, &bh->b_state); - bh->b_private = (void *) bh_cb; - atomic_inc(&bh_cb->blks_allocated); - - /* drive the buffer head down */ - /* to the device */ - generic_make_request(READ, bh); - - /* wait for all bh's I/O's to end */ - wait_on_bh_cb(bh_cb); - - /* copy data to/from user */ - if (io_flag != WRITE) - /* READ */ - memcpy(bufptr, - *sector_buf + (sector_lsn << EVMS_VSECTOR_SIZE_SHIFT), - io_size << EVMS_VSECTOR_SIZE_SHIFT); - else { - /* WRITE */ - memcpy(*sector_buf + (sector_lsn << EVMS_VSECTOR_SIZE_SHIFT), - bufptr, io_size << EVMS_VSECTOR_SIZE_SHIFT); - - /* allocate a buffer head from the pool */ - while ((bh = allocate_bh()) == NULL) - /* yielding the cpu is playing it - * safe. it might be wiser to just - * spin. requires more thought. - */ - schedule(); - - /* set up the buffer head for this sector */ - bh->b_end_io = end_bh_cb_io_sync; - bh->b_size = node->hardsector_size; - bh->b_rdev = dev; - bh->b_rsector = next_lsn - sector_lsn; - bh->b_data = *sector_buf; - bh->b_page = virt_to_page(*sector_buf); /* this isn't handling the case of a block with more than 1 sector, that spans pages */ - bh->b_state = 0; - set_bit(BH_Dirty, &bh->b_state); - set_bit(BH_Lock, &bh->b_state); - set_bit(BH_Req, &bh->b_state); - set_bit(BH_Mapped, &bh->b_state); - bh->b_private = (void *) bh_cb; - atomic_inc(&bh_cb->blks_allocated); - - /* drive the buffer head down */ - /* to the device */ - generic_make_request(WRITE, bh); - - /* wait for all bh's I/O's to end */ - wait_on_bh_cb(bh_cb); - } - return (rc); -} - -/* - * function: ldev_init_io - * - * This function provides support for synchronous I/O - * operations to the underlying devices. These I/O - * operations are NOT buffered in any way including the - * operating system's buffer cache. - * - * This function can work with any hardsector size that - * is a power of 2. - * - * node : logical node of the target logical disk - * io_flag : 0 = read, 1 = write, 2 = read-a-head - * starting_lsn : the 0-based (disk relative) logical - * : (512 byte) sector number (lsn) - * num_lsns : the total number of lsns in this I/O - * bufptr : address of the memory to read/write the data - * - */ -static int -ldev_init_io(struct evms_logical_node *node, - int io_flag, - u64 starting_lsn, u64 num_lsns, void *bufptr) -{ - int rc = 0, lsns_per_hardsector, lsns_per_blocksize; - unchar *sector_buf = NULL, *cur_bufptr; - u64 next_lsn, remaining_lsns, sector_lsn; - struct ldev_private *ldev_prv = node->private; - kdev_t dev = MKDEV(ldev_prv->major, ldev_prv->minor); - bh_cb_t bh_cb; - - LOG_EVERYTHING - ("%s Entry: Disk(%u,%u), ioflag(%u), start_lsn("PFU64"), num_lsns("PFU64"), bufptr(0x%p)\n", - __FUNCTION__, ldev_prv->major, ldev_prv->minor, io_flag, - starting_lsn, num_lsns, bufptr); - - /* check for valid device */ - if (!blk_size[ldev_prv->major][ldev_prv->minor]) { - node->flags |= EVMS_DEVICE_UNAVAILABLE; - return (-ENXIO); - } - /* check for 0 length request */ - if (num_lsns == 0) { - LOG_ERROR("%s: error requesting 0 sectors.\n", __FUNCTION__); - return (-EINVAL); - } - /* check for out of bound request */ - if ((starting_lsn + num_lsns) > node->total_vsectors) { - LOG_ERROR - ("%s: attempted %s beyond logical disk boundary("PFU64" LSNs), requesting LSN("PFU64"), total LSNs("PFU64").\n", - __FUNCTION__, (io_flag == WRITE) ? "WRITE" : "READ", - node->total_vsectors, starting_lsn, num_lsns); - return (-EINVAL); - } - /* check for invalid io_flag value */ - switch (io_flag) { - case READ: /* read... */ - case WRITE: /* write... */ - case READA: /* reada... */ - break; - default: - return (-EINVAL); - } - - /* compute some per device info once up-front */ - lsns_per_hardsector = node->hardsector_size / EVMS_VSECTOR_SIZE; - lsns_per_blocksize = node->block_size / EVMS_VSECTOR_SIZE; - - /* initialize the buffer head control block */ - memset(&bh_cb, 0, sizeof (bh_cb_t)); - init_waitqueue_head(&bh_cb.cb_wait); - atomic_set(&bh_cb.blks_allocated, 0); - - /* only update the local copy of variables */ - cur_bufptr = bufptr; - next_lsn = starting_lsn; - remaining_lsns = num_lsns; - - /* check for a mid-sector starting offset - * - * if found, perform I/O on part of that - * sector - */ - sector_lsn = next_lsn & (lsns_per_hardsector - 1); - if (sector_lsn) { - u64 io_size; - - /* determine bytes in IO to this sector */ - io_size = lsns_per_hardsector - sector_lsn; - if (io_size > remaining_lsns) - io_size = remaining_lsns; - - /* perform the partial sector io */ - rc = ldev_partial_sector_init_io(node, io_flag, &bh_cb, - next_lsn, - sector_lsn, io_size, - cur_bufptr, §or_buf); - - if (!rc) { - /* update progress in local variables */ - cur_bufptr += io_size << EVMS_VSECTOR_SIZE_SHIFT; - next_lsn += io_size; - remaining_lsns -= io_size; - } - } - - /* continue if no errors found */ - if (!rc) { - /* perform I/O on all the complete sectors - * in this request. - * - * loop until there are no more complete sectors - * to process. - */ - while (remaining_lsns >= lsns_per_hardsector) { - /* this inner loop attempts to drive as many - * bytes (in sector size multiples) down to - * the device as possible using the available - * buffer heads in the pool. - */ - while (remaining_lsns >= lsns_per_hardsector) { - struct buffer_head *bh; - - /* allocate a buffer head from the pool */ - bh = allocate_bh(); - if (bh == NULL) - break; - - /* set up the buffer head for this I/O */ - bh->b_end_io = end_bh_cb_io_sync; - bh->b_size = - (remaining_lsns >= lsns_per_blocksize) ? - node->block_size : node->hardsector_size; - bh->b_data = cur_bufptr; - bh->b_rdev = dev; - bh->b_rsector = next_lsn; - bh->b_page = virt_to_page(cur_bufptr); /* this isn't handling the case of a block with more than 1 sector, that spans pages */ - bh->b_state = 0; - set_bit(BH_Dirty, &bh->b_state); - set_bit(BH_Lock, &bh->b_state); - set_bit(BH_Req, &bh->b_state); - set_bit(BH_Mapped, &bh->b_state); - bh->b_private = (void *) &bh_cb; - atomic_inc(&bh_cb.blks_allocated); - - /* drive the buffer head down */ - /* to the device */ - generic_make_request(io_flag, bh); - - /* update progress in local variables */ - cur_bufptr += bh->b_size; - next_lsn += - bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - remaining_lsns -= - bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - } - /* wait for all bh's I/O's to end */ - wait_on_bh_cb(&bh_cb); - } - } - - /* continue if no errors found */ - if (!rc) - /* check for a mid-sector ending offset - * - * if found, perform I/O on part of that - * sector - */ - if (remaining_lsns) - /* perform the partial sector io */ - rc = ldev_partial_sector_init_io(node, io_flag, &bh_cb, - next_lsn, - 0, remaining_lsns, - cur_bufptr, - §or_buf); - - /* free the sector buffer if it was allocated */ - if (sector_buf) - kfree(sector_buf); - - /* coalesce return codes */ - rc |= bh_cb.rc; - - LOG_EVERYTHING("%s Exit: rc(%u)\n", __FUNCTION__, rc); - - return (rc); -} - -static int -ldev_mgr_direct_ioctl(struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct ldev_private *ldev_prv; - struct evms_plugin_ioctl_pkt tmp, *user_parms; - struct ldev_plugin_ioctl pi_data; - struct evms_logical_node *disk; - - MOD_INC_USE_COUNT; - - user_parms = (struct evms_plugin_ioctl_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - /* validate its meant for us */ - if (tmp.feature_id != plugin_header.id) { - rc = -EINVAL; - } - } - - if (!rc) { - /* copy feature ioctl data to kernel space */ - if (copy_from_user(&pi_data, tmp.feature_ioctl_data, - sizeof (pi_data))) { - rc = -EFAULT; - } - } - - if (!rc) { - /* find the disk node specified by the disk_handle */ - int done = FALSE; - disk = NULL; - while (!done) { - rc = evms_cs_find_next_device(disk, - &disk); - if (rc) { - break; - } - if (!disk) { - rc = -ENODATA; - break; - } - if (disk == - DEV_HANDLE_TO_NODE(pi_data.disk_handle)) { - done = TRUE; - } - } - } - - if (!rc) { - /* perform feature command */ - ldev_prv = (struct ldev_private *) disk->private; - switch (tmp.feature_command) { - kdev_t save_dev; - case LDEV_MGR_BROADCAST_IOCTL_CMD: - save_dev = inode->i_rdev; - inode->i_rdev = - MKDEV(ldev_prv->major, ldev_prv->minor); - rc = ldev_prv->bdev->bd_op->ioctl(inode, file, - pi_data.cmd, - pi_data.arg); - inode->i_rdev = save_dev; - break; - default: - rc = -EINVAL; - break; - } - } - - /* return status value */ - tmp.status = rc; - copy_to_user((struct evms_plugin_ioctl_pkt *) arg, &tmp, sizeof (tmp)); - MOD_DEC_USE_COUNT; - return rc; -} - -/********************************************************/ -/* Required Plugin Function Table Entry Point: */ -/* IOCTL function & Support routines */ -/********************************************************/ - -static int -ldev_mgr_ioctl(struct evms_logical_node *disk, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct ldev_private *ldev_prv = disk->private; - kdev_t save_dev; - struct block_device *save_bdev; - - if (!inode || !disk) - return -EINVAL; - - save_dev = inode->i_rdev; - inode->i_rdev = MKDEV(ldev_prv->major, ldev_prv->minor); - save_bdev = inode->i_bdev; - inode->i_bdev = ldev_prv->bdev; - /* check device availability */ - if (!blk_get_queue(MKDEV(ldev_prv->major, ldev_prv->minor))) { - disk->flags |= EVMS_DEVICE_UNAVAILABLE; - } - switch (cmd) { - case EVMS_QUIESCE_VOLUME: - case EVMS_PLUGIN_IOCTL: - break; - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = - (struct evms_get_bmap_pkt *) arg; - bmap->dev = MKDEV(ldev_prv->major, ldev_prv->minor); - bmap->status = 0; - } - break; - case EVMS_OPEN_VOLUME: - if (disk->flags & EVMS_DEVICE_UNAVAILABLE) { - rc = -ENXIO; - } else { - rc = ldev_prv->bdev->bd_op->open(inode, file); - } - break; - case EVMS_CLOSE_VOLUME: - if (disk->flags & EVMS_DEVICE_UNAVAILABLE) { - rc = -ENXIO; - } else { - rc = ldev_prv->bdev->bd_op->release(inode, file); - } - break; - case EVMS_CHECK_MEDIA_CHANGE: - if (disk->flags & EVMS_DEVICE_UNAVAILABLE) { - rc = -ENXIO; - } else { - /* once we detect that media changed - * is 'set', don't send any more ioctls - * down to the device, until the - * media change has been 'reset' by a - * revalidate disk ioctl. when already - * 'set', just return a 1 w/o actually - * performing another ioctl call to the - * device. - */ - if (ldev_prv->media_changed == TRUE) { - rc = 1; - break; - } - rc = ldev_prv->bdev->bd_op-> - check_media_change(MKDEV - (ldev_prv->major, - ldev_prv->minor)); - if (rc == 1) { - ldev_prv->media_changed = TRUE; - disk->flags |= EVMS_MEDIA_CHANGED; - } - } - break; - case EVMS_REVALIDATE_DISK: - if (disk->flags & EVMS_DEVICE_UNAVAILABLE) { - rc = -ENXIO; - } else { - /* don't actually send this ioctl down - * to the device, until we know that - * previous check media change ioctl - * has occurred. - * - * when we do actually send the ioctl - * down, reset the local media_changed - * flag. - */ - if (ldev_prv->media_changed == FALSE) - break; - rc = ldev_prv->bdev->bd_op-> - revalidate(MKDEV - (ldev_prv->major, ldev_prv->minor)); - ldev_prv->media_changed = FALSE; - } - break; - case EVMS_GET_DISK_LIST: - rc = evms_cs_add_item_to_list((struct evms_list_node **) arg, - disk); - if (rc > 0) - rc = 0; - break; - case EVMS_CHECK_DEVICE_STATUS: - if (arg) { - int *status = (int *) arg; - *status |= disk->flags; - } - break; - case EVMS_UPDATE_DEVICE_INFO: - /* determine hardsector size */ - disk->hardsector_size = 512; - if (hardsect_size[ldev_prv->major]) { - disk->hardsector_size = hardsect_size[ldev_prv->major][ldev_prv->minor]; - } - /* save the block size */ - disk->block_size = 1024; - if (blksize_size[ldev_prv->major]) { - disk->block_size = blksize_size[ldev_prv->major][ldev_prv->minor]; - } - /* device size in sectors - * - * try 64bit size first, if that fails - * fall back on the 32bit size. - */ - /* try 64bit size */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) - rc = evms_cs_kernel_ioctl(disk, BLKGETSIZE64, - (ulong) & disk->total_vsectors); - if (!rc) { - /* convert bytes to 512 byte sectors */ - disk->total_vsectors >>= EVMS_VSECTOR_SIZE_SHIFT; - } else -#endif - { - /* try 32bit size */ - ulong dev_size = 0; - rc = evms_cs_kernel_ioctl(disk, BLKGETSIZE, - (ulong) & dev_size); - disk->total_vsectors = dev_size; - } - break; - default: - if (disk->flags & EVMS_DEVICE_UNAVAILABLE) { - rc = -ENXIO; - } else { - rc = ldev_prv->bdev->bd_op->ioctl(inode, file, cmd, - arg); - } - break; - } - inode->i_bdev = save_bdev; - inode->i_rdev = save_dev; - - return (rc); -} - -/********************************************************/ -/* Required Module Entry Point: */ -/* ldev_mgr_init */ -/********************************************************/ - -static int __init -ldev_mgr_init(void) -{ - return evms_cs_register_plugin(&plugin_header); -} - -static void __exit -ldev_mgr_exit(void) -{ - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(ldev_mgr_init); -module_exit(ldev_mgr_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/lvm_vge.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/lvm_vge.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/lvm_vge.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/lvm_vge.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,3739 +0,0 @@ -/* -*- linux-c -*- */ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/drivers/evms/lvm_vge.c - * - * EVMS Linux LVM Region Manager - */ - -#define LOG_PREFIX "lvm: " - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Plugin API prototypes. */ -static int lvm_discover(struct evms_logical_node ** evms_node_list); -static int lvm_discover_end(struct evms_logical_node ** evms_node_list); -static int lvm_delete_node(struct evms_logical_node * logical_node); -static void lvm_read(struct evms_logical_node * node, struct buffer_head * bh); -static void lvm_write(struct evms_logical_node * node, struct buffer_head * bh); -static int lvm_init_io(struct evms_logical_node * node, - int io_flag, - u64 sect_nr, - u64 num_sects, - void * buf_addr); -static int lvm_ioctl(struct evms_logical_node * logical_node, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg); -static int lvm_direct_ioctl(struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long args); - -static struct snapshot_map_entry * allocate_snapshot_map_entry(u64 org_sector, - u64 snap_sector); - -/* LVM Plugin function table and header. */ -static struct evms_plugin_fops lvm_fops = { - .discover = lvm_discover, - .end_discover = lvm_discover_end, - .delete = lvm_delete_node, - .read = lvm_read, - .write = lvm_write, - .init_io = lvm_init_io, - .ioctl = lvm_ioctl, - .direct_ioctl = lvm_direct_ioctl -}; - -static struct evms_plugin_header lvm_plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_REGION_MANAGER, - 0x01), - .version = { - .major = EVMS_LVM_VERSION_MAJOR, - .minor = EVMS_LVM_VERSION_MINOR, - .patchlevel = EVMS_LVM_VERSION_PATCH - }, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0 - }, - .fops = &lvm_fops -}; - -static struct lvm_volume_group * lvm_group_list = NULL; -static struct proc_dir_entry * lvm_proc = NULL; - - -/********** Miscellaneous Functions **********/ - - -/** - * remap sector - * @node: - * @org_sector: Logical sector to remap. - * @size: Size (in sectors) or request to remap. - * @new_sector: Remapped sector. - * @new_size: New size (in sectors). - * @pe_start_sector: Starting sector of PE - needed for snapshotting. - * @pv_entry: New node for which new_sector is relative. - * - * Common function to remap LV lba to PV lba in appropriate PE. This - * function needs to deal with requests that span PEs and/or stripes. If - * this occurs, the request will simply be chopped off at the boundary of - * the first PE/stripe. It is up to the calling function to loop - * accordingly to finish the full remapping. This function is now partially - * 64-bit enabled. The striping section contains code that currently cannot - * eliminate at least one mod operation on 64 bit values. - **/ -static int remap_sector(struct evms_logical_node * node, - u64 org_sector, - u64 size, - u64 * new_sector, - u64 * new_size, - u64 * pe_start_sector, - struct lvm_physical_volume ** pv_entry) -{ - struct lvm_logical_volume * volume = node->private; - struct le_table_entry * le_entry; - u32 le, offset_in_le; - - *new_size = size; - - if ( volume->stripes > 1 ) { - /* Volume is striped. Reset the size if the request crosses - * a stripe boundary. Striping in LVM is not 64-bit enabled. - */ - u32 column, columns, sectors_per_column; - u32 sector_in_column, stripe_in_column, le_in_column; - u32 offset_in_stripe, stripe_in_le; - u32 org_sector32 = org_sector; - - sectors_per_column = volume->stripes * volume->pe_size; - column = org_sector32 / sectors_per_column; - sector_in_column = org_sector32 % sectors_per_column; - stripe_in_column = sector_in_column / volume->stripe_size; - le_in_column = stripe_in_column % volume->stripes; - columns = volume->num_le / volume->stripes; - le = column + (columns * le_in_column); - - offset_in_stripe = org_sector32 % volume->stripe_size; - stripe_in_le = stripe_in_column / volume->stripes; - offset_in_le = offset_in_stripe + - stripe_in_le * volume->stripe_size; - - if ( offset_in_stripe + size > volume->stripe_size ) { - *new_size = volume->stripe_size - offset_in_stripe; - } - } else { - /* Linear volume. Just find LE and offset. Reset the size if - * the request crosses an LE boundary. This path is 64-bit safe. - */ - le = org_sector >> volume->pe_size_shift; - offset_in_le = org_sector & (volume->pe_size - 1); - - if ( offset_in_le + size > volume->pe_size ) { - *new_size = volume->pe_size - offset_in_le; - } - } - - le_entry = &volume->le_map[le]; - *pe_start_sector = le_entry->pe_sector_offset; - *new_sector = le_entry->pe_sector_offset + offset_in_le; - *pv_entry = le_entry->owning_pv; - - return 0; -} - -/** - * add_group_to_list - * - * Add a volume group to the end of the LVM global group list. - **/ -static int add_group_to_list(struct lvm_volume_group * group) -{ - struct lvm_volume_group ** p_group; - - for ( p_group = &lvm_group_list; - *p_group; p_group = &(*p_group)->next_group ) { - ; - } - - *p_group = group; - group->next_group = NULL; - return 0; -} - -/** - * remove_group_from_list - * - * Remove an LVM volume group from the global LVM list. - **/ -static int remove_group_from_list(struct lvm_volume_group * group) -{ - struct lvm_volume_group ** p_group; - - for ( p_group = &lvm_group_list; - *p_group; p_group = &(*p_group)->next_group ) { - if ( *p_group == group ) { - *p_group = (*p_group)->next_group; - group->next_group = NULL; - break; - } - } - - return 0; -} - -/** - * find_group_by_uuid - * - * Use the vg_uuid to find the desired volume group. - **/ -static int find_group_by_uuid(u8 * vg_uuid, - struct lvm_volume_group ** group) -{ - struct lvm_volume_group * gp; - - for ( gp = lvm_group_list; gp; gp = gp->next_group ) { - if ( ! memcmp(vg_uuid, gp->vg_uuid, UUID_LEN) ) { - *group = gp; - return 0; - } - } - *group = NULL; - return -EINVAL; -} - -/** - * find_pv_by_number - * - * Search the PV list of the specified volume group, looking for the - * specified PV number. If found, return a pointer to that PV. - **/ -static struct lvm_physical_volume * -find_pv_by_number(u32 pv_number, - struct lvm_volume_group * group) -{ - struct lvm_physical_volume * pv_entry; - - for ( pv_entry = group->pv_list; pv_entry; pv_entry = pv_entry->next ) { - if ( pv_entry->pv_number == pv_number ) { - return pv_entry; - } - } - return NULL; -} - -/** - * translate_lv_name - * @lvm_lv_name: Input LVM-style name. - * @evms_node_name: Output EVMS-style name. - * - * In LVM, volumes have names based on their dev-node, which follow the - * pattern /dev/group_name/volume_name. In EVMS, the same volume needs - * to appear as /dev/evms/lvm/group_name/volume_name. Thus, the name from - * the lv_disk_t needs to be translated before copying to the associated - * node. evms_node_name must point to a NAME_LEN sized buffer. - **/ -static int translate_lv_name(char * lvm_lv_name, char * evms_node_name) -{ - char * ptr; - - memset(evms_node_name, 0, NAME_LEN); - - /* Make sure the string starts with /dev/, and skip over it. */ - ptr = strstr(lvm_lv_name, DEV_DIRECTORY); - if ( ptr != lvm_lv_name ) { - LOG_SERIOUS("Invalid LV name: %s\n", lvm_lv_name); - return -EINVAL; - } - ptr = &ptr[strlen(DEV_DIRECTORY)]; - - /* ptr now points to "group_name/volume_name". - * Use this to create the name for the EVMS node. - */ - strcpy(evms_node_name, LVM_DEV_DIRECTORY); - strncat(evms_node_name, ptr, NAME_LEN - strlen(evms_node_name) - 1); - - return 0; -} - -/** - * check_pv_for_lv - * - * Run through all LE maps of all LVs in this group, and make sure the - * specified PV is not being pointed to by any LEs. - **/ -static int check_pv_for_lv(struct lvm_physical_volume * pv_entry, - struct lvm_volume_group * group) -{ - struct lvm_logical_volume * volume; - int i, j; - - for ( i = 1; i <= MAX_LV; i++ ) { - if ( (volume = group->volume_list[i]) ) { - for ( j = 0; j < volume->num_le; j++ ) { - if ( volume->le_map[j].owning_pv == pv_entry ) { - return -EINVAL; - } - } - } - } - return 0; -} - - -/********** Metadata I/O Functions **********/ - - -/** - * endian_convert_pv - * - * Endian-neutral conversion for PV structures. - **/ -static inline void endian_convert_pv(struct pv_disk * pv) -{ - pv->version = le16_to_cpup(&pv->version); - pv->pv_on_disk.base = le32_to_cpup(&pv->pv_on_disk.base); - pv->pv_on_disk.size = le32_to_cpup(&pv->pv_on_disk.size); - pv->vg_on_disk.base = le32_to_cpup(&pv->vg_on_disk.base); - pv->vg_on_disk.size = le32_to_cpup(&pv->vg_on_disk.size); - pv->pv_uuidlist_on_disk.base = - le32_to_cpup(&pv->pv_uuidlist_on_disk.base); - pv->pv_uuidlist_on_disk.size = - le32_to_cpup(&pv->pv_uuidlist_on_disk.size); - pv->lv_on_disk.base = le32_to_cpup(&pv->lv_on_disk.base); - pv->lv_on_disk.size = le32_to_cpup(&pv->lv_on_disk.size); - pv->pe_on_disk.base = le32_to_cpup(&pv->pe_on_disk.base); - pv->pe_on_disk.size = le32_to_cpup(&pv->pe_on_disk.size); - pv->pv_major = le32_to_cpup(&pv->pv_major); - pv->pv_number = le32_to_cpup(&pv->pv_number); - pv->pv_status = le32_to_cpup(&pv->pv_status); - pv->pv_allocatable = le32_to_cpup(&pv->pv_allocatable); - pv->pv_size = le32_to_cpup(&pv->pv_size); - pv->lv_cur = le32_to_cpup(&pv->lv_cur); - pv->pe_size = le32_to_cpup(&pv->pe_size); - pv->pe_total = le32_to_cpup(&pv->pe_total); - pv->pe_allocated = le32_to_cpup(&pv->pe_allocated); - pv->pe_start = le32_to_cpup(&pv->pe_start); -} - -/** - * read_pv - * - * Read in the PV structure from the specified node. If it contains a - * valid PV signature, allocate a new struct pv_disk and copy the data. - **/ -static int read_pv(struct evms_logical_node * node, struct pv_disk ** pv) -{ - struct pv_disk * pv_buffer; - int rc = -ENOMEM; - - *pv = NULL; - - /* Buffer for reading the PV metadata. */ - pv_buffer = kmalloc(LVM_PV_DISK_SIZE, GFP_NOIO); - if (!pv_buffer) { - LOG_CRITICAL("Error allocating PV metadata buffer for %s\n", - node->name); - goto out; - } - - /* Read the first two sectors. */ - rc = INIT_IO(node, 0, evms_cs_size_in_vsectors(LVM_PV_DISK_BASE), - evms_cs_size_in_vsectors(LVM_PV_DISK_SIZE), pv_buffer); - if (rc) { - LOG_SERIOUS("Error reading PV metadata from %s\n", node->name); - goto out_kfree; - } - - /* Endian-neutral conversion of PV metadata. */ - endian_convert_pv(pv_buffer); - - /* Check for an LVM signature and make sure the sizes match. - * Versions 1 and 2 are both valid now. Thanks LVM! :) - */ - if ( !(pv_buffer->id[0] == 'H' && - pv_buffer->id[1] == 'M' && - (pv_buffer->version == 1 || pv_buffer->version == 2) && - pv_buffer->pv_size == node->total_vsectors) ) { - LOG_EXTRA("%s is not an LVM PV\n", node->name); - rc = -EINVAL; - goto out_kfree; - } - - /* This is a valid PV. Allocate a new pv_disk. */ - *pv = kmalloc(sizeof(struct pv_disk), GFP_NOIO); - if (!*pv) { - LOG_CRITICAL("Error allocating new PV for %s\n", node->name); - rc = -ENOMEM; - goto out_kfree; - } - - /* Copy the metadata. */ - memcpy(*pv, pv_buffer, sizeof(struct pv_disk)); - -out_kfree: - kfree(pv_buffer); -out: - return rc; -} - -/** - * endian_convert_vg - * - * Endian-neutral conversion for VG structures - **/ -static inline void endian_convert_vg(struct vg_disk * vg) -{ - vg->vg_number = le32_to_cpup(&vg->vg_number); - vg->vg_access = le32_to_cpup(&vg->vg_access); - vg->vg_status = le32_to_cpup(&vg->vg_status); - vg->lv_max = le32_to_cpup(&vg->lv_max); - vg->lv_cur = le32_to_cpup(&vg->lv_cur); - vg->lv_open = le32_to_cpup(&vg->lv_open); - vg->pv_max = le32_to_cpup(&vg->pv_max); - vg->pv_cur = le32_to_cpup(&vg->pv_cur); - vg->pv_act = le32_to_cpup(&vg->pv_act); - vg->dummy = le32_to_cpup(&vg->dummy); - vg->vgda = le32_to_cpup(&vg->vgda); - vg->pe_size = le32_to_cpup(&vg->pe_size); - vg->pe_total = le32_to_cpup(&vg->pe_total); - vg->pe_allocated = le32_to_cpup(&vg->pe_allocated); - vg->pvg_total = le32_to_cpup(&vg->pvg_total); -} - -/** - * read_vg - * - * Read in the VG structure from the specified node. Allocate a new - * struct vg_disk and copy the data. - **/ -static int read_vg(struct evms_logical_node * node, - struct pv_disk * pv, - struct vg_disk ** vg) -{ - struct vg_disk * vg_buffer; - unsigned long vg_sectors; - int rc = -ENOMEM; - - /* Allocate a buffer to read the VG metadata. */ - vg_sectors = evms_cs_size_in_vsectors(pv->vg_on_disk.size); - vg_buffer = kmalloc(vg_sectors << EVMS_VSECTOR_SIZE_SHIFT, GFP_NOIO); - if (!vg_buffer) { - LOG_CRITICAL("Error allocating VG metadata buffer for %s\n", - node->name); - goto out; - } - - /* Read the VG metadata. */ - rc = INIT_IO(node, 0, evms_cs_size_in_vsectors(pv->vg_on_disk.base), - vg_sectors, vg_buffer); - if (rc) { - LOG_SERIOUS("Error reading VG metadata from %s\n", node->name); - goto out_kfree; - } - - /* Endian-neutral conversion of VG metadata. */ - endian_convert_vg(vg_buffer); - - /* Allocate a new struct vg_disk. */ - *vg = kmalloc(sizeof(struct vg_disk), GFP_NOIO); - if (!*vg) { - LOG_CRITICAL("Error allocating new VG for %s\n", node->name); - rc = -ENOMEM; - goto out_kfree; - } - - /* Copy the metadata. */ - memcpy(*vg, vg_buffer, sizeof(struct vg_disk)); - -out_kfree: - kfree(vg_buffer); -out: - return rc; -} - -/** - * read_uuid_list - **/ -static int read_uuid_list(struct evms_logical_node * node, - struct pv_disk * pv, - struct lvm_volume_group * group) -{ - u64 start_sector; - unsigned long total_sectors; - unsigned char * uuid_buffer; - unsigned long buffer_size = IO_BUFFER_SECTORS * EVMS_VSECTOR_SIZE; - unsigned long uuid_list_size; - int i, rc = 0; - - if (group->uuid_list) { - LOG_EXTRA("Already read PV UUIDs for group %s\n", - group->vg_name); - goto out; - } - - start_sector = evms_cs_size_in_vsectors(pv->pv_uuidlist_on_disk.base); - total_sectors = evms_cs_size_in_vsectors(pv->pv_uuidlist_on_disk.size); - uuid_list_size = round_up(total_sectors * EVMS_VSECTOR_SIZE, - buffer_size); - - /* Allocate a buffer to perform the I/Os. */ - uuid_buffer = kmalloc(buffer_size, GFP_NOIO); - if (!uuid_buffer) { - LOG_CRITICAL("Error allocating buffer for UUID list in group %s\n", - group->vg_name); - rc = -ENOMEM; - goto out; - } - - /* Allocate memory for the UUID array for this group. */ - group->uuid_list = vmalloc(uuid_list_size); - if (!group->uuid_list) { - LOG_CRITICAL("Error allocating UUID list for group %s\n", - group->vg_name); - rc = -ENOMEM; - goto out_kfree; - } - memset(group->uuid_list, 0, uuid_list_size); - - for ( i = 0; i < total_sectors; i += IO_BUFFER_SECTORS ) { - rc = INIT_IO(node, 0, start_sector + i, - IO_BUFFER_SECTORS, uuid_buffer); - if (rc) { - LOG_SERIOUS("Error reading PV UUID list from %s\n", - node->name); - goto out_vfree; - } - /* Copy the I/O buffer into the UUID array. */ - memcpy(&(group->uuid_list[i * EVMS_VSECTOR_SIZE]), - uuid_buffer, buffer_size); - } - - /* Clear out the unused portion at the end of the uuid_list. */ - memset(&(group->uuid_list[pv->pv_uuidlist_on_disk.size]), 0, - uuid_list_size - pv->pv_uuidlist_on_disk.size); - -out_kfree: - kfree(uuid_buffer); -out: - return rc; - -out_vfree: - vfree(group->uuid_list); - group->uuid_list = NULL; - goto out_kfree; -} - -/** - * endian_convert_lv - * - * Endian-neutral conversion for LV structures - **/ -static inline void endian_convert_lv(struct lv_disk * lv) -{ - lv->lv_access = le32_to_cpup(&lv->lv_access); - lv->lv_status = le32_to_cpup(&lv->lv_status); - lv->lv_open = le32_to_cpup(&lv->lv_open); - lv->lv_dev = le32_to_cpup(&lv->lv_dev); - lv->lv_number = le32_to_cpup(&lv->lv_number); - lv->lv_mirror_copies = le32_to_cpup(&lv->lv_mirror_copies); - lv->lv_recovery = le32_to_cpup(&lv->lv_recovery); - lv->lv_schedule = le32_to_cpup(&lv->lv_schedule); - lv->lv_size = le32_to_cpup(&lv->lv_size); - lv->lv_snapshot_minor = le32_to_cpup(&lv->lv_snapshot_minor); - lv->lv_chunk_size = le16_to_cpup(&lv->lv_chunk_size); - lv->dummy = le16_to_cpup(&lv->dummy); - lv->lv_allocated_le = le32_to_cpup(&lv->lv_allocated_le); - lv->lv_stripes = le32_to_cpup(&lv->lv_stripes); - lv->lv_stripesize = le32_to_cpup(&lv->lv_stripesize); - lv->lv_badblock = le32_to_cpup(&lv->lv_badblock); - lv->lv_allocation = le32_to_cpup(&lv->lv_allocation); - lv->lv_io_timeout = le32_to_cpup(&lv->lv_io_timeout); - lv->lv_read_ahead = le32_to_cpup(&lv->lv_read_ahead); -} - -static inline void endian_convert_lvs(struct lvm_volume_group * group) -{ - int i; - for ( i = 0; i < group->vg->lv_max; i++ ) { - endian_convert_lv(&(group->lv_array[i])); - } -} - -/** - * read_lv - * - * Read in the LV structures for the specified group. Do the read from - * the first PV in the group. If that one fails, keep trying on the - * remaining PVs until one works. This function will allocate a buffer - * for the group to read in the structures. - **/ -static int read_lv(struct lvm_volume_group * group) -{ - struct lvm_physical_volume * pv_entry = group->pv_list; - unsigned char * lv_buffer = NULL; - u64 start_sector; - unsigned long total_sectors, lv_array_size = 0; - unsigned long buffer_size = IO_BUFFER_SECTORS * EVMS_VSECTOR_SIZE; - int i, rc = 1; - - if (group->lv_array_disk) { - return 0; - } - - if (!pv_entry) { - LOG_ERROR("Group %s has no PVs. Cannot read LV structures.\n", - group->vg_name); - return -EINVAL; - } - - /* Allocate a buffer to do the actual I/Os. */ - lv_buffer = kmalloc(buffer_size, GFP_NOIO); - if (!lv_buffer) { - LOG_CRITICAL("Error allocating buffer for LV structs for Group %s\n", - group->vg_name); - return -ENOMEM; - } - - /* Read in the LV structures 4k at a time. If one PV returns errors, - * start over with the next PV in the group. - */ - while (rc && pv_entry) { - //start_sector = evms_cs_size_in_vsectors(pv_entry->pv->lv_on_disk.base); - start_sector = pv_entry->pv->lv_on_disk.base >> EVMS_VSECTOR_SIZE_SHIFT; - total_sectors = evms_cs_size_in_vsectors(pv_entry->pv->lv_on_disk.size); - lv_array_size = round_up(total_sectors * EVMS_VSECTOR_SIZE, - buffer_size); - - /* Allocate the buffer for this group to - * hold the entire LV array. - */ - if (group->lv_array_disk) { - vfree(group->lv_array_disk); - group->lv_array_disk = group->lv_array = NULL; - } - group->lv_array_disk = vmalloc(lv_array_size); - if (!group->lv_array_disk) { - LOG_CRITICAL("Error allocating lv_array buffer for Group %s\n", - group->vg_name); - rc = -ENOMEM; - goto out_kfree; - } - memset(group->lv_array_disk, 0, lv_array_size); - group->lv_array = (struct lv_disk*)((unsigned long)group->lv_array_disk + - (pv_entry->pv->lv_on_disk.base & (EVMS_VSECTOR_SIZE - 1))); - - for ( i = 0; i < total_sectors; i += IO_BUFFER_SECTORS ) { - rc = INIT_IO(pv_entry->logical_node, 0, - start_sector + i, IO_BUFFER_SECTORS, - lv_buffer); - if (rc) { - LOG_SERIOUS("Error reading LV metadata from %s in Group %s\n", - pv_entry->logical_node->name, - group->vg_name); - - /* Try the next PV if the current one - * caused any errors. - */ - pv_entry = pv_entry->next; - break; - } - /* Copy the I/O buffer into the lv_array. */ - memcpy(&(((char *)(group->lv_array_disk))[i * EVMS_VSECTOR_SIZE]), - lv_buffer, buffer_size); - } - } - - if (rc) { - LOG_SERIOUS("Unable to read LV metadata from any PV in Group %s\n", - group->vg_name); - goto out_vfree; - } - - /* Clear out the unused portion at the end of the lv_array. */ - memset(&(((char *)(group->lv_array_disk))[pv_entry->pv->lv_on_disk.size]), - 0, lv_array_size - pv_entry->pv->lv_on_disk.size); - - /* Endian-neutral conversion of the LV metadata. */ - endian_convert_lvs(group); - -out_kfree: - kfree(lv_buffer); - return rc; - -out_vfree: - vfree(group->lv_array_disk); - group->lv_array_disk = group->lv_array = NULL; - goto out_kfree; -} - -/** - * endian_convert_pe_map - * - * Endian-neutral conversion for PE structures - **/ -static inline void endian_convert_pe_map(struct lvm_physical_volume * pv_entry) -{ - int i; - for ( i = 0; i < pv_entry->pv->pe_total; i++ ) { - pv_entry->pe_map[i].lv_num = - le16_to_cpup(&pv_entry->pe_map[i].lv_num); - pv_entry->pe_map[i].le_num = - le16_to_cpup(&pv_entry->pe_map[i].le_num); - } -} - -/** - * read_pe_map - * - * Read in the PE map for the specified PV. This function will allocate a - * buffer to read in the data. - **/ -static int read_pe_map(struct lvm_physical_volume * pv_entry) -{ - struct evms_logical_node * node = pv_entry->logical_node; - struct pv_disk * pv = pv_entry->pv; - unsigned char * pe_buffer; - u64 start_sector; - unsigned long total_sectors, pe_map_size; - unsigned long buffer_size = IO_BUFFER_SECTORS * EVMS_VSECTOR_SIZE; - int i, rc = -ENOMEM; - - if (pv_entry->pe_map) { - return 0; - } - - start_sector = evms_cs_size_in_vsectors(pv->pe_on_disk.base); - total_sectors = evms_cs_size_in_vsectors(pv->pe_total * - sizeof(struct pe_disk)); - pe_map_size = round_up(total_sectors * EVMS_VSECTOR_SIZE, buffer_size); - - /* Allocate a buffer for performing the I/O. */ - pe_buffer = kmalloc(buffer_size, GFP_NOIO); - if (!pe_buffer) { - LOG_CRITICAL("Error allocating buffer for PE maps for %s\n", - node->name); - goto out; - } - - /* Allocate a buffer to hold the PE map for this PV. */ - pv_entry->pe_map = vmalloc(pe_map_size); - if (!pv_entry->pe_map) { - LOG_CRITICAL("Error allocating PE map for %s\n", node->name); - goto out_kfree; - } - memset(pv_entry->pe_map, 0, pe_map_size); - - for ( i = 0; i < total_sectors; i += IO_BUFFER_SECTORS ) { - rc = INIT_IO(node, 0, start_sector + i, - IO_BUFFER_SECTORS, pe_buffer); - if (rc) { - LOG_SERIOUS("Error reading PE maps from %s.\n", - node->name); - goto out_vfree; - } - /* Copy the data to the actual PE map. */ - memcpy(&(((char *)(pv_entry->pe_map))[i * EVMS_VSECTOR_SIZE]), - pe_buffer, buffer_size); - } - - /* Clear out the unused portion at the end of the PE map. */ - memset(&(((char *)(pv_entry->pe_map))[total_sectors * EVMS_VSECTOR_SIZE]), - 0, pe_map_size - total_sectors * EVMS_VSECTOR_SIZE); - - /* Endian-neutral conversion of the PE metadata. */ - endian_convert_pe_map(pv_entry); - -out_kfree: - kfree(pe_buffer); -out: - return rc; - -out_vfree: - vfree(pv_entry->pe_map); - pv_entry->pe_map = NULL; - goto out_kfree; -} - - -/********** Snapshot Manipulation Functions **********/ - - -/** - * snapshot_check_quiesce_original - * - * For this snapshot LV, check that both it and its original are quiesced. - **/ -static int -snapshot_check_quiesce_original(struct lvm_logical_volume * snap_volume) -{ - struct lvm_logical_volume * org_volume = snap_volume->snapshot_org; - - if ( ! (snap_volume->lv_access & EVMS_LV_QUIESCED) ) { - return -EINVAL; - } - - if ( org_volume && !(org_volume->lv_access & EVMS_LV_QUIESCED) ) { - return -EINVAL; - } - - return 0; -} - -/** - * snapshot_check_quiesce_all - * - * Go through the list of all snapshots for an original volume, and make - * sure everyone is in a quiesced state. - **/ -static int snapshot_check_quiesce_all(struct lvm_logical_volume * org_volume) -{ - struct lvm_logical_volume * snap; - - if ( ! (org_volume->lv_access & EVMS_LV_QUIESCED) ) { - return -EINVAL; - } - - for ( snap = org_volume->snapshot_next; - snap; snap = snap->snapshot_next ) { - if ( ! (snap->lv_access & EVMS_LV_QUIESCED) ) { - return -EINVAL; - } - } - - return 0; -} - -/** - * invalidate_snapshot_volume - * - * In the event a snapshot volume becomes full or corrupted, its metadata - * must be altered in order to prevent it from being used again. Write some - * invalid data into the first entry of the COW table. If this volume is - * not fully deleted by the user/engine, this invalid COW entry will be - * detected by build_snapshot_maps(), and will cause the volume to be - * deleted before being exported to EVMS during discover. This is obviously - * a hack, but it is the same hack currently used by LVM. We're just trying - * to be compatible. :) - **/ -static int invalidate_snapshot_volume(struct lvm_logical_volume * snap_volume) -{ - struct evms_logical_node tmp_node; - - tmp_node.private = snap_volume; - tmp_node.total_vsectors = snap_volume->lv_size; - - if ( ! (snap_volume->lv_access & LV_SNAPSHOT) ) { - LOG_WARNING("Volume %s is not a snapshot. Cannot invalidate\n", - snap_volume->name); - return -EINVAL; - } - - LOG_WARNING("Invalidating full/corrupt snapshot %s\n", - snap_volume->name); - LOG_WARNING("Run the EVMS administration tools to remove this snapshot.\n"); - - if (snap_volume->cow_table) { - snap_volume->cow_table[0].pv_org_rsector = - cpu_to_le64(((u64)1)); - if ( lvm_init_io(&tmp_node, 4, 0, 1, snap_volume->cow_table) ) { - LOG_SERIOUS("Unable to invalidate snapshot %s\n", - snap_volume->name); - } - } else { - LOG_SERIOUS("Unable to invalidate snapshot %s\n", - snap_volume->name); - } - - snap_volume->lv_status &= ~LV_ACTIVE; - return 0; -} - -/** - * remove_snapshot_from_chain - * - * Remove a snapshot volume from its original's chain of snapshots. This - * does not delete the snapshot volume. At runtime, we cannot delete - * volumes at the region-manager level, because EVMS may have this volume - * exported, and there is no way to notify EVMS of the deletion. It will - * eventually need to be deleted in the engine, which will then tell the - * EVMS kernel services to delete the volume in the kernel. - **/ -static int remove_snapshot_from_chain(struct lvm_logical_volume * snap_volume) -{ - struct lvm_logical_volume * org_volume = snap_volume->snapshot_org; - struct lvm_logical_volume ** p_volume; - - if (org_volume) { - for ( p_volume = &org_volume->snapshot_next; - *p_volume; - p_volume = &(*p_volume)->snapshot_next ) { - if ( *p_volume == snap_volume ) { - *p_volume = snap_volume->snapshot_next; - break; - } - } - } - - snap_volume->snapshot_org = NULL; - snap_volume->snapshot_next = NULL; - return 0; -} - -/** - * snapshot_hash - * - * The snapshot hash tables are NEVER going to have 4 billion entries, so - * we can safely cast the org_sector to 32 bits and just mod it by the - * hash table size. - **/ -static u32 snapshot_hash(u64 org_sector, - struct lvm_logical_volume * snap_volume) -{ - return (((u32)org_sector) % snap_volume->hash_table_size); -} - -/** - * snapshot_search_hash_chain - * - * Search the hash chain that is anchored at the specified head pointer. - * If the sector number is found, the result pointer is set to that entry - * in the chain, and a 1 is returned. If the sector is not found, the - * result pointer is set to the previous entry and 0 is returned. If the - * result pointer is NULL, this means either the list is empty, or the - * specified sector should become the first list item. - **/ -static int snapshot_search_hash_chain(u64 org_sector, - struct snapshot_map_entry * head, - struct snapshot_map_entry ** result) -{ - struct snapshot_map_entry * curr = head; - struct snapshot_map_entry * prev = head; - while ( curr && curr->org_sector < org_sector ) { - prev = curr; - curr = curr->next; - } - if (!curr) { - /* Either an empty chain or went off the end of the chain. */ - *result = prev; - return 0; - } else if ( curr->org_sector != org_sector ) { - *result = curr->prev; - return 0; - } else { - /* Found the desired sector. */ - *result = curr; - return 1; - } -} - -/** - * insert_snapshot_map_entry - * - * Insert a new entry into a snapshot hash chain, immediately following the - * specified entry. This function should not be used to add an entry into - * an empty list, or as the first entry in an existing list. For that case, - * use insert_snapshot_map_entry_at_head(). - **/ -static int insert_snapshot_map_entry(struct snapshot_map_entry * entry, - struct snapshot_map_entry * base) -{ - entry->next = base->next; - entry->prev = base; - base->next = entry; - if (entry->next) { - entry->next->prev = entry; - } - return 0; -} - -/** - * insert_snapshot_map_entry_at_head - * - * Insert a new entry into a snapshot chain as the first entry. - **/ -static int insert_snapshot_map_entry_at_head(struct snapshot_map_entry * entry, - struct snapshot_map_entry ** head) -{ - entry->next = *head; - entry->prev = NULL; - *head = entry; - if (entry->next) { - entry->next->prev = entry; - } - return 0; -} - -/** - * add_cow_entry_to_snapshot_map - * - * Convert a cow table entry (from the on-disk data) into an appropriate - * entry for the snapshot map. Insert this new entry into the appropriate - * map for the specified volume. - * - * The cow_entry passed into this function must have already been - * endian-converted from disk-order to cpu-order. - **/ -static int add_cow_entry_to_snapshot_map(struct lv_COW_table_disk * cow_entry, - struct lvm_logical_volume * volume) -{ - struct snapshot_map_entry * new_entry, * target_entry; - struct snapshot_map_entry ** hash_table, * chain_head; - u32 hash_value; - - if ( cow_entry->pv_org_number == 0 ) { - return -EINVAL; - } - - new_entry = allocate_snapshot_map_entry(cow_entry->pv_org_rsector, - cow_entry->pv_snap_rsector); - if (!new_entry) { - return -ENOMEM; - } - - new_entry->snap_pv = find_pv_by_number(cow_entry->pv_snap_number, - volume->group); - if (!new_entry->snap_pv) { - kfree(new_entry); - return -EINVAL; - } - - hash_value = snapshot_hash(new_entry->org_sector, volume); - hash_table = volume->snapshot_map[cow_entry->pv_org_number]; - chain_head = hash_table[hash_value]; - if ( snapshot_search_hash_chain(new_entry->org_sector, - chain_head, &target_entry) ) { - /* In general, we should not find this entry in the snapshot - * map already. However, it could happen on a re-discover, but - * the build_snapshot_maps function should weed out those cases. - * In either event, we can simply ignore duplicates. - */ - LOG_WARNING("Detected a duplicate snapshot map entry\n"); - LOG_WARNING("Snap PV "PFU64":"PFU64", Org PV "PFU64":"PFU64"\n", - cow_entry->pv_snap_number, - cow_entry->pv_snap_rsector, - cow_entry->pv_org_number, - cow_entry->pv_org_rsector); - kfree(new_entry); - } else { - if (target_entry) { - insert_snapshot_map_entry(new_entry, target_entry); - } else { - insert_snapshot_map_entry_at_head(new_entry, - &hash_table[hash_value]); - } - } - - return 0; -} - -/** - * snapshot_remap_sector - * - * Perform a sector remap on a snapshot volume. This should be called from - * the I/O read path, after the LE-to-PE translation has already been - * performed. First, determine the base sector of the chunk containing the - * specified sector, and save the remainder. Then, perform a search through - * the snapshot map for the specified volume. If an match is found, change - * the PV and sector numbers to the new values. If no match is found, leave - * the values alone, meaning the read should proceed down the original - * volume. - **/ -static void -snapshot_remap_sector(struct lvm_logical_volume * snap_volume, - u64 pe_start_sector, - u64 * sector, - struct lvm_physical_volume ** pv_entry) -{ - struct snapshot_map_entry ** hash_table; - struct snapshot_map_entry * chain_head, * result; - u32 hash_value; - u64 chunk_sector, remainder; - - if ( ! (snap_volume->lv_access & LV_SNAPSHOT) ) { - return; - } - - chunk_sector = ((*sector - pe_start_sector) & - ((u64)(~(snap_volume->chunk_size - 1)))) + - pe_start_sector; - remainder = *sector - chunk_sector; - hash_value = snapshot_hash(chunk_sector, snap_volume); - hash_table = snap_volume->snapshot_map[(*pv_entry)->pv_number]; - chain_head = hash_table[hash_value]; - - if ( snapshot_search_hash_chain(chunk_sector, chain_head, &result) ) { - *pv_entry = result->snap_pv; - *sector = result->snap_sector + remainder; - } -} - -/** - * snapshot_read_write_chunk - * - * This function takes care of reading one chunk of data from the - * original, and writing it to the snapshot. Since the original now has - * a fixed sized buffer for this data, we may have to loop to get the - * whole chunk copied. - **/ -static int snapshot_read_write_chunk(struct lvm_logical_volume * org_volume, - struct lvm_physical_volume * org_pv, - u64 chunk_sector, - struct lvm_logical_volume * snap_volume, - struct lvm_physical_volume ** snap_pv, - u64 * snap_sector) -{ - u32 io_size = snap_volume->chunk_size; - u64 snap_pe_start_sector, size; - int i, iterations = 1; - - if ( org_volume->chunk_size < snap_volume->chunk_size ) { - iterations = snap_volume->chunk_size / org_volume->chunk_size; - io_size = org_volume->chunk_size; - } - - remap_sector(snap_volume->volume_node, snap_volume->next_free_chunk, 1, - snap_sector, &size, &snap_pe_start_sector, snap_pv); - - /* Check for an incomplete volume. */ - if (!*snap_sector || !*snap_pv) { - invalidate_snapshot_volume(snap_volume); - return -1; - } - - for ( i = 0; i < iterations; i++ ) { - - /* Read the chunk from the original volume. This is a physical - * read, not logical. Thus, stripe boundary considerations are - * unnecessary. Also, chunks are always aligned with PEs, so PE - * boundary considerations are unnecessary. - */ - if ( INIT_IO(org_pv->logical_node, 0, - chunk_sector + i * io_size, io_size, - org_volume->chunk_data_buffer) ) { - return 1; - } - - /* Write this chunk to the snapshot volume. This does duplicate - * the local init_io code, but we need to have the remapped - * sector later on, so this is slightly more efficient. Snapshot - * volumes cannot be striped, so there is no need to consider - * stripe-boundary conditions. And just like the read in the - * previous line, chunks are always aligned with PEs, so we - * don't have to consider PE-boundary conditions. - */ - if ( INIT_IO((*snap_pv)->logical_node, 1, - *snap_sector + i * io_size, io_size, - org_volume->chunk_data_buffer) ) { - /* An error writing the chunk to the snapshot is the - * same situation as the snapshot being full. - */ - invalidate_snapshot_volume(snap_volume); - return -1; - } - } - - return 0; -} - -/** - * snapshot_copy_data - * - * On a write to a snapshotted volume, check all snapshots to see if the - * specified chunk has already been remapped. If it has not, read the - * original data from the volume, write the data to the next available - * chunk on the snapshot, update the COW table, write the COW table to - * the snapshot, and insert a new entry into the snapshot map. - * - * Now converted to copy data to a single snapshot. The looping is left - * up to lvm_write. - **/ -static int snapshot_copy_data(struct lvm_logical_volume * org_volume, - struct lvm_logical_volume * snap_volume, - u64 pe_start_sector, - u64 org_sector, - struct lvm_physical_volume * org_pv) -{ - struct lvm_physical_volume * snap_pv; - struct snapshot_map_entry ** hash_table, * chain_head; - struct snapshot_map_entry * target_entry, * new_map_entry; - u64 chunk_sector, snap_sector; - u32 hash_value; - int rc = 0; - - /* Lock out this snapshot while we are remapping. */ - down(&snap_volume->snap_semaphore); - - /* Make sure the snapshot has not been deactivated. */ - if ( ! (snap_volume->lv_status & LV_ACTIVE) ) { - goto out; - } - - /* Search the hash table to see if this sector has already been - * remapped on this snapshot. - */ - chunk_sector = ((org_sector - pe_start_sector) & - ((u64)(~(snap_volume->chunk_size - 1)))) + - pe_start_sector; - hash_value = snapshot_hash(chunk_sector, snap_volume); - hash_table = snap_volume->snapshot_map[org_pv->pv_number]; - chain_head = hash_table[hash_value]; - - if ( snapshot_search_hash_chain(chunk_sector, - chain_head, &target_entry) ) { - /* Chunk is already remapped. */ - goto out; - } - - /* Is there room on the snapshot to remap this chunk? */ - if ( snap_volume->next_free_chunk >= snap_volume->lv_size ) { - /* At this point, the snapshot is full. Any further - * writes to the original will cause the snapshot to - * become "corrupt" because they can't be remapped. - * Take this snapshot permanently offline. - */ - goto out_invalidate; - } - - rc = snapshot_read_write_chunk(org_volume, org_pv, chunk_sector, - snap_volume, &snap_pv, &snap_sector); - if (rc) { - rc = (rc > 0) ? -EIO : 0; - goto out; - } - - /* Fill in the appropriate COW table entry and write that - * metadata sector back to the snapshot volume. Since we are - * only writing one sector, there are no boundary conditions. - * Must endian-convert each entry as it is added. - */ - snap_volume->cow_table[snap_volume->next_cow_entry].pv_org_number = - cpu_to_le64((u64)(org_pv->pv_number)); - snap_volume->cow_table[snap_volume->next_cow_entry].pv_org_rsector = - cpu_to_le64p(&chunk_sector); - snap_volume->cow_table[snap_volume->next_cow_entry].pv_snap_number = - cpu_to_le64((u64)(snap_pv->pv_number)); - snap_volume->cow_table[snap_volume->next_cow_entry].pv_snap_rsector = - cpu_to_le64p(&snap_sector); - - if ( lvm_init_io(snap_volume->volume_node, 4, - snap_volume->current_cow_sector, - 1, snap_volume->cow_table) ) { - /* The data was written to the snapshot, but - * writing the metadata failed. - */ - goto out_invalidate; - } - - snap_volume->next_cow_entry++; - if ( snap_volume->next_cow_entry >= - (EVMS_VSECTOR_SIZE / sizeof (struct lv_COW_table_disk)) ) { - snap_volume->next_cow_entry = 0; - snap_volume->current_cow_sector++; - memset(snap_volume->cow_table, 0, EVMS_VSECTOR_SIZE); - if ( lvm_init_io(snap_volume->volume_node, 4, - snap_volume->current_cow_sector, - 1, snap_volume->cow_table) ) { - /* Can't clear out the next sector of metadata. */ - goto out_invalidate; - } - } - snap_volume->next_free_chunk += snap_volume->chunk_size; - - /* Create a new snapshot map entry and add it in the appropriate - * place in the map. - */ - new_map_entry = allocate_snapshot_map_entry(chunk_sector, snap_sector); - if (!new_map_entry) { - rc = -ENOMEM; - goto out_invalidate; - } - new_map_entry->snap_pv = snap_pv; - if (target_entry) { - insert_snapshot_map_entry(new_map_entry, target_entry); - } else { - insert_snapshot_map_entry_at_head(new_map_entry, - &(hash_table[hash_value])); - } - -out: - up(&snap_volume->snap_semaphore); - return rc; - -out_invalidate: - invalidate_snapshot_volume(snap_volume); - goto out; -} - -/** - * get_snapshot_stats - **/ -static int get_snapshot_stats(struct lvm_snapshot_stat_ioctl * snap_stats) -{ - struct lvm_logical_volume * volume; - struct lvm_volume_group * group; - - /* Make sure the parameters are in range. */ - if ( snap_stats->lv_number < 1 || snap_stats->lv_number > MAX_LV ) { - return 1; - } - - /* Make sure the specified group and volume exist, and that - * this is a snapshot volume. - */ - find_group_by_uuid(snap_stats->vg_uuid, &group); - if ( ! group || - ! (volume = group->volume_list[snap_stats->lv_number]) || - ! (volume->lv_access & LV_SNAPSHOT) ) { - return 1; - } - - /* Return the starting LBA of the next available chunk. */ - snap_stats->next_free_chunk = volume->next_free_chunk; - snap_stats->lv_status = volume->lv_status; - - return 0; -} - - -/********** Memory Allocation/Deallocation Functions **********/ - - -/** - * deallocate_physical_volume - * - * Free the memory used by this physical volume. Do not delete the EVMS - * node in this function, since this could be called during an error - * path when we want to save the logical node. - **/ -static int deallocate_physical_volume(struct lvm_physical_volume * pv_entry) -{ - if (pv_entry->pv) { - kfree(pv_entry->pv); - pv_entry->pv = NULL; - } - - if (pv_entry->pe_map) { - vfree(pv_entry->pe_map); - pv_entry->pe_map = NULL; - } - - kfree(pv_entry); - return 0; -} - -/** - * allocate_physical_volume - * - * Create a new struct lvm_physical_volume for the specified volume group. - * Initialize the new PV with the evms node and lvm pv information. - **/ -static struct lvm_physical_volume * -allocate_physical_volume(struct evms_logical_node * node, struct pv_disk * pv) -{ - struct lvm_physical_volume * new_pv; - - new_pv = kmalloc(sizeof(struct lvm_physical_volume), GFP_NOIO); - if (!new_pv) { - LOG_CRITICAL("Error allocating physical volume for %s.\n", - node->name); - kfree(pv); - goto out; - } - - /* Initialize the PV. */ - memset(new_pv, 0, sizeof(struct lvm_physical_volume)); - new_pv->logical_node = node; - new_pv->pv = pv; - new_pv->pv_number = pv->pv_number; - -out: - return new_pv; -} - -/** - * allocate_snapshot_map_entry - * - * Allocate memory for a new entry in the snapshot map and fill in the - * sector values. The PV pointer is not filled in here, but can easily - * be found by using the find_pv_by_number function. - **/ -static struct snapshot_map_entry * allocate_snapshot_map_entry(u64 org_sector, - u64 snap_sector) -{ - struct snapshot_map_entry * new_entry; - - new_entry = kmalloc(sizeof(struct snapshot_map_entry), GFP_NOIO); - if (!new_entry) { - goto out; - } - memset(new_entry, 0, sizeof(struct snapshot_map_entry)); - new_entry->org_sector = org_sector; - new_entry->snap_sector = snap_sector; -out: - return new_entry; -} - -/** - * deallocate_snapshot_map - * - * This function will delete one hash table, which is part of the whole - * snapshot remapping structure. Each hash table is an array of pointers - * to linked lists of struct snapshot_map_entry's. - **/ -static int deallocate_snapshot_map(struct snapshot_map_entry ** table, - u32 table_size) -{ - struct snapshot_map_entry * entry, * next; - int i; - - if (table) { - for ( i = 0; i < table_size; i++ ) { - for ( entry = table[i]; entry; entry = next ) { - next = entry->next; - kfree(entry); - } - } - vfree(table); - } - return 0; -} - -/** - * deallocate_logical_volume - * - * Delete the in-memory representation of a single LVM logical volume, - * including its PE map and any snapshot data. Do not alter the parent - * volume group, except to remove this volume from its volume list. - **/ -static int deallocate_logical_volume(struct lvm_logical_volume * volume) -{ - struct lvm_volume_group * group = volume->group; - struct lvm_logical_volume * org_volume, * snap_volume; - int i; - - if ( volume->lv_access & LV_SNAPSHOT ) { - /* This volume is a snapshot. Remove it from the linked - * list of volumes that are snapshotting the original. - * First, the original volume must be quiesced. - */ - org_volume = volume->snapshot_org; - - if ( snapshot_check_quiesce_original(volume) ) { - return -EINVAL; - } - - remove_snapshot_from_chain(volume); - - /* If the snapshot that was just removed was the last/only - * volume snapshotting the original, then mark the original - * as no longer being snapshotted. - */ - if ( org_volume && !org_volume->snapshot_next ) { - org_volume->lv_access &= ~LV_SNAPSHOT_ORG; - } - } else if ( volume->lv_access & LV_SNAPSHOT_ORG ) { - /* If this volume is a snapshot original, all of its snapshots - * must also be deleted. However, Those deletions need to be - * taken care of by the engine. So just check that they have - * all been quiesced before removing the original. - */ - if ( snapshot_check_quiesce_all(volume) ) { - return -EINVAL; - } - - /* In case there are any snapshots remaining, we must clear out - * their pointers to this original to prevent errors when those - * snapshots are accessed or deleted. - */ - for ( snap_volume = volume->snapshot_next; - snap_volume; snap_volume = snap_volume->snapshot_next ) { - snap_volume->snapshot_org = NULL; - } - } - - if (volume->name) { - LOG_DEBUG("Deleting volume %s\n", volume->name); - } - - /* Free all the memory. This includes the LE-to-PE map, any snapshot - * hash tables, the COW table, and chunk data buffer. - */ - if (volume->le_map) { - vfree(volume->le_map); - volume->le_map = NULL; - } - if (volume->snapshot_map) { - for ( i = 1; i <= group->pv_count; i++ ) { - deallocate_snapshot_map(volume->snapshot_map[i], - volume->hash_table_size); - } - kfree(volume->snapshot_map); - volume->snapshot_map = NULL; - } - if (volume->cow_table) { - kfree(volume->cow_table); - volume->cow_table = NULL; - } - if (volume->chunk_data_buffer) { - kfree(volume->chunk_data_buffer); - volume->chunk_data_buffer = NULL; - } - - /* Remove this volume from the group's list. */ - if ( group && group->volume_list[volume->lv_number] == volume ) { - group->volume_list[volume->lv_number] = NULL; - group->volume_count--; - } - - kfree(volume); - return 0; -} - -/** - * allocate_logical_volume - * - * Allocate space for a new LVM logical volume, including space for the - * LE-to-PE map and any necessary snapshot data. - **/ -static struct lvm_logical_volume * -allocate_logical_volume(struct lv_disk * lv, struct lvm_volume_group * group) -{ - struct lvm_logical_volume * new_volume; - u32 table_entries_per_chunk, table_chunks; - int i; - - /* Allocate space for the new logical volume. */ - new_volume = kmalloc(sizeof(struct lvm_logical_volume), GFP_NOIO); - if (!new_volume) { - LOG_CRITICAL("Error allocating new logical volume %s\n", - lv->lv_name); - goto out; - } - memset(new_volume, 0, sizeof(struct lvm_logical_volume)); - - /* Allocate space for the LE to PE mapping table. */ - new_volume->le_map = vmalloc(lv->lv_allocated_le * - sizeof(struct le_table_entry)); - if (!new_volume->le_map) { - LOG_CRITICAL("Error creating LE map for logical volume %s\n", - lv->lv_name); - goto error; - } - memset(new_volume->le_map, 0, - lv->lv_allocated_le * sizeof(struct le_table_entry)); - - /* Initialize the rest of the new volume. - * Need the +1 on lv_number to match the PE Map entries on the PV. - */ - new_volume->lv_number = lv->lv_number + 1; - new_volume->lv_size = lv->lv_size; - new_volume->lv_access = lv->lv_access | EVMS_LV_NEW | EVMS_LV_QUIESCED; - new_volume->lv_status = lv->lv_status | LV_ACTIVE; - new_volume->lv_minor = MINOR(lv->lv_dev); - new_volume->stripes = lv->lv_stripes; - new_volume->stripe_size = lv->lv_stripesize; - new_volume->stripe_size_shift = evms_cs_log2(lv->lv_stripesize); - new_volume->pe_size = group->vg->pe_size; - new_volume->pe_size_shift = evms_cs_log2(group->vg->pe_size); - new_volume->num_le = lv->lv_allocated_le; - new_volume->group = group; - /* Different naming scheme for EVMS nodes. */ - if ( translate_lv_name(lv->lv_name, new_volume->name) ) { - goto error; - } - - if ( new_volume->lv_access & LV_SNAPSHOT ) { - /* This volume is a snapshot, initialize the remaining data, - * and allocate space for the remapping structures, and one - * sector's worth of COW tables. - */ - new_volume->chunk_size = lv->lv_chunk_size; - new_volume->num_chunks = lv->lv_size / lv->lv_chunk_size; - new_volume->snap_org_minor = lv->lv_snapshot_minor; - new_volume->next_cow_entry = 0; - new_volume->current_cow_sector = 0; - table_entries_per_chunk = (new_volume->chunk_size << - EVMS_VSECTOR_SIZE_SHIFT) / - sizeof(struct lv_COW_table_disk); - table_chunks = (new_volume->num_chunks + - table_entries_per_chunk - 1) / - table_entries_per_chunk; - new_volume->next_free_chunk = table_chunks * - new_volume->chunk_size; - new_volume->hash_table_size = (lv->lv_size / lv->lv_chunk_size / - MAX_HASH_CHAIN_ENTRIES) + 1; - - new_volume->cow_table = kmalloc(EVMS_VSECTOR_SIZE, GFP_NOIO); - if (!new_volume->cow_table) { - LOG_CRITICAL("Error allocating COW table for logical volume %s\n", - lv->lv_name); - goto error; - } - memset(new_volume->cow_table, 0, EVMS_VSECTOR_SIZE); - - new_volume->snapshot_map = kmalloc((group->pv_count + 1) * - sizeof(struct snapshot_map_entry **), - GFP_NOIO); - if (!new_volume->snapshot_map) { - LOG_CRITICAL("Error allocating snapshot map for logical volume %s\n", - lv->lv_name); - goto error; - } - - new_volume->snapshot_map[0] = NULL; - for ( i = 1; i <= group->pv_count; i++ ) { - new_volume->snapshot_map[i] = - vmalloc(new_volume->hash_table_size * - sizeof(struct snapshot_map_entry *)); - if (!new_volume->snapshot_map[i]) { - LOG_CRITICAL("Error allocating snapshot sub-map for logical volume %s\n", - lv->lv_name); - goto error; - } - memset(new_volume->snapshot_map[i], 0, - new_volume->hash_table_size * - sizeof(struct snapshot_map_entry *)); - } - init_MUTEX(&new_volume->snap_semaphore); - } else if ( new_volume->lv_access & LV_SNAPSHOT_ORG ) { - /* This volume is a snapshot original, allocate space to use for - * copying snapshot chunks. This will now be a fixed size - * instead of being based on the chunk size of the snapshots. - */ - new_volume->chunk_size = CHUNK_DATA_BUFFER_SIZE; - new_volume->chunk_data_buffer = - kmalloc(new_volume->chunk_size << - EVMS_VSECTOR_SIZE_SHIFT, GFP_NOIO); - if (!new_volume->chunk_data_buffer) { - LOG_SERIOUS("Error allocating snapshot chunk buffer for logical volume %s\n", - lv->lv_name); - goto error; - } - memset(new_volume->chunk_data_buffer, 0, - new_volume->chunk_size << EVMS_VSECTOR_SIZE_SHIFT); - } - -out: - return new_volume; -error: - deallocate_logical_volume(new_volume); - new_volume = NULL; - goto out; -} - -/** - * deallocate_volume_group - * - * Delete the entire in-memory representation of an LVM volume group, - * including all PVs and logical volumes. If this group is on LVM's - * volume group list, remove it. - **/ -static int deallocate_volume_group(struct lvm_volume_group * group) -{ - struct lvm_physical_volume * pv_entry, * next_pv; - int i; - - LOG_DEBUG("Deleting volume group %s\n", group->vg_name); - - /* Remove the group from the global list. */ - remove_group_from_list(group); - - /* Delete the LV metadata array. */ - if (group->lv_array_disk) { - vfree(group->lv_array_disk); - group->lv_array_disk = group->lv_array = NULL; - } - - /* Delete the PV UUID list. */ - if (group->uuid_list) { - vfree(group->uuid_list); - group->uuid_list = NULL; - } - - /* Delete all logical volumes. */ - for ( i = 1; i <= MAX_LV; i++ ) { - if (group->volume_list[i]) { - deallocate_logical_volume(group->volume_list[i]); - group->volume_list[i] = NULL; - } - } - - /* Delete all PVs from the group's list. */ - for ( pv_entry = group->pv_list; pv_entry; pv_entry = next_pv ) { - next_pv = pv_entry->next; - if (pv_entry->logical_node) { - /* Send a delete command down to the segment manager. */ - LOG_DEBUG("Deleting PV %s from group %s\n", - pv_entry->logical_node->name, group->vg_name); - DELETE(pv_entry->logical_node); - pv_entry->logical_node = NULL; - } - deallocate_physical_volume(pv_entry); - } - - /* Delete the VG metadata. */ - if (group->vg) { - kfree(group->vg); - group->vg = NULL; - } - - kfree(group); - return 0; -} - -/** - * allocate_volume_group - * - * Allocate space for a new LVM volume group and all of its sub-fields. - * Initialize the appropriate fields. - * vg parameter should already have an allocate/initialized struct vg_disk. - **/ -static struct lvm_volume_group * allocate_volume_group(struct vg_disk * vg, - u8 * vg_name) -{ - struct lvm_volume_group * new_group; - - /* The volume group itself. */ - new_group = kmalloc(sizeof(struct lvm_volume_group), GFP_NOIO); - if (!new_group) { - kfree(vg); - goto out; - } - - /* Initialize the new group. */ - memset(new_group, 0, sizeof(struct lvm_volume_group)); - memcpy(new_group->vg_uuid, vg->vg_uuid, UUID_LEN); - strncpy(new_group->vg_name, vg_name, NAME_LEN - 1); - new_group->vg = vg; - /* Default sector and block sizes. */ - new_group->hard_sect_size = 512; - new_group->block_size = 1024; - new_group->flags = EVMS_VG_DIRTY; - - LOG_DETAILS("Discovered volume group %s\n", new_group->vg_name); - -out: - return new_group; -} - -/** - * remove_pv_from_group - * - * In the engine, when a PV is removed from a group (on a vgreduce), that - * same PV must be removed from that group in the kernel. Otherwise, when - * the rediscover occurs, that PV will still appear in the group, and - * will cause segfaults when we try to read metadata from it. - **/ -static int remove_pv_from_group(int pv_number, unsigned char * vg_uuid) -{ - struct lvm_volume_group * group; - struct lvm_physical_volume * pv_entry; - struct lvm_physical_volume ** p_pv_entry; - - /* Make sure the numbers are in range. */ - if ( pv_number < 0 || pv_number > MAX_PV ) { - return 0; - } - - /* Make sure the group exists. */ - find_group_by_uuid(vg_uuid, &group); - if (!group) { - return 0; - } - - /* Make sure the PV is in this group. */ - pv_entry = find_pv_by_number(pv_number, group); - if (!pv_entry) { - LOG_WARNING("Did not find PV %d in group %s\n", - pv_number, group->vg_name); - return 0; - } - - /* Make sure the PV is not in use by any volumes. */ - if ( check_pv_for_lv(pv_entry, group) ) { - LOG_SERIOUS("PV %d in group %s still contains LVs\n", - pv_number, group->vg_name); - return -EINVAL; - } - - /* Take this PV out of the group's list. */ - for ( p_pv_entry = &group->pv_list; - *p_pv_entry; p_pv_entry = &(*p_pv_entry)->next ) { - if ( *p_pv_entry == pv_entry ) { - *p_pv_entry = (*p_pv_entry)->next; - pv_entry->next = NULL; - break; - } - } - - group->pv_count--; - - /* There is no way that this PV was the last in this group, so the - * group never needs to be deleted at this point. The only way this - * group will exist in the kernel is if there are volumes exported from - * it. If this was the last PV, then those volumes must be on that PV, - * and it wouldn't be allowed to be removed from the group (above). - */ - - /* Free up the memory for this PV. Just drop the node. */ - deallocate_physical_volume(pv_entry); - - LOG_DEBUG("PV %d removed from group %s\n", pv_number, group->vg_name); - return 0; -} - - -/********** Consistency Checking Functions **********/ - - -/** - * clear_le_entries_for_missing_pv - * - * In the event that a PV turns up missing during a rediscover, we - * need to erase any LE map entries that might point to it. - **/ -static void -clear_le_entries_for_missing_pv(struct lvm_volume_group * group, - struct lvm_physical_volume * pv_entry) -{ - struct lvm_logical_volume * volume; - int i, j; - - for ( i = 1; i <= MAX_LV; i++ ) { - if (group->volume_list[i]) { - volume = group->volume_list[i]; - for ( j = 0; j < volume->num_le; j++ ) { - if ( volume->le_map[j].owning_pv == pv_entry ) { - volume->le_map[j].owning_pv = NULL; - volume->le_map[j].pe_sector_offset = 0; - } - } - } - } -} - -/** - * check_volume_groups - * - * This function performs some simple consistency checks on all dirty - * volume groups. Any groups that have no PVs are deleted. If any metadata - * structures (PV or VG) are missing, they are read in from disk. - **/ -static int check_volume_groups(void) -{ - struct lvm_volume_group * group, * next_group; - struct lvm_physical_volume * pv_entry, * next_pv; - int rc = 0; - - for ( group = lvm_group_list; group; group = next_group ) { - next_group = group->next_group; - - LOG_DEBUG("Checking Group %s\n", group->vg_name); - - /* If a group has no PVs, it can be safely deleted, - * because we can't find any volumes on it. - */ - if (!group->pv_count) { - LOG_WARNING("No PVs found for Group %s.\n", - group->vg_name); - if (!group->volume_count) { - deallocate_volume_group(group); - } - continue; - } - - /* Make sure all metadata for the PVs is present. On a - * rediscover, it may be missing, because we delete it at the - * end of discovery. If any is missing, read it in from disk. - * This is only necessary in the kernel. It can't happen in - * the engine. - */ - for ( pv_entry = group->pv_list; - pv_entry; pv_entry = next_pv ) { - next_pv = pv_entry->next; - if (!pv_entry->pv) { - LOG_DEBUG("Re-reading PV metadata for %s\n", - pv_entry->logical_node->name); - rc = read_pv(pv_entry->logical_node, - &pv_entry->pv); - if (rc) { - /* What happens if we can't re-read the - * PV metadata? This PV must be removed - * from the group. Need to also clear - * all LE entries in all LVs that are - * pointing to this PV before it can be - * removed from the list. - */ - LOG_SERIOUS("PV metadata is missing or cannot be read from %s\n", - pv_entry->logical_node->name); - clear_le_entries_for_missing_pv(group, - pv_entry); - remove_pv_from_group(pv_entry->pv_number, - group->vg_uuid); - continue; - } - pv_entry->pv_number = pv_entry->pv->pv_number; - - /* Check for a "stale" PV. This case should be - * already be covered, as long as the Engine is - * calling the PV_REMOVE ioctl when it does a - * vgreduce or a pvremove. If this is the last - * PV in the group, the group will be deleted. - */ - if (!pv_entry->pv_number) { - remove_pv_from_group(0, group->vg_uuid); - continue; - } - } - - if (!pv_entry->pe_map) { - LOG_DEBUG("Re-reading PE maps for %s\n", - pv_entry->logical_node->name); - rc = read_pe_map(pv_entry); - if (rc) { - LOG_WARNING("Error reading PE maps for %s\n", - pv_entry->logical_node->name); - LOG_WARNING("Any volumes residing on %s will be incomplete!\n", - pv_entry->logical_node->name); - } - } - } - - /* Make sure the metadata for the VG is present. If it's - * missing, read it in from the first PV in the VG. - */ - if (!group->vg && group->pv_count) { - LOG_DEBUG("Re-reading VG metadata for Group %s\n", - group->vg_name); - pv_entry = group->pv_list; - rc = read_vg(pv_entry->logical_node, - pv_entry->pv, &group->vg); - if (rc) { - /* What happens if we can't re-read the - * VG metadata? It's definitely bad - * news. Should we delete the VG? - */ - continue; - } - } - - /* Display a warning if the number of PVs found for the group - * doesn't match the number of PVs recorded for the VG. - */ - if ( group->vg && group->pv_count != group->vg->pv_cur ) { - LOG_WARNING("Group %s is incomplete.\n", - group->vg_name); - LOG_WARNING(" Only %d of %d PVs found.\n", - group->pv_count, group->vg->pv_cur); - LOG_WARNING(" Volumes in this group may be incomplete.\n"); - } - } - - return 0; -} - -/** - * check_le_maps - * - * Make sure all volumes in this group have valid LE-to-PE maps. Any - * volume that doesn't is marked as incomplete. This is safe for - * re-discovery because only new volumes could have corrupted LE maps. - **/ -static int check_le_maps(struct lvm_volume_group * group) -{ - struct lvm_logical_volume * volume; - int i, j, count; - - for ( i = 1; i <= MAX_LV; i++ ) { - volume = group->volume_list[i]; - if (!volume) { - continue; - } - - if (!volume->le_map) { - /* No point in keeping the volume around if it has - * no LE map at all. - */ - LOG_SERIOUS("Volume %s has no LE map.\n", volume->name); - deallocate_logical_volume(volume); - continue; - } - - /* If any entries in the LE map are missing, mark this volume - * as incomplete. - */ - for ( j = 0, count = 0; j < volume->num_le; j++ ) { - if ( !volume->le_map[j].owning_pv || - !volume->le_map[j].pe_sector_offset) { - count++; - } - } - if (count) { - LOG_SERIOUS("Volume %s has incomplete LE map.\n", - volume->name); - LOG_SERIOUS(" Missing %d out of %d LEs.\n", - count, volume->num_le); - volume->lv_access |= EVMS_LV_INCOMPLETE; - } - } - return 0; -} - -/** - * check_snapshot_map - * - * For snapshot volumes, make sure the snapshot map is intact, and that - * any existing entries in the map are in the correct order and there - * are no duplicate entries. - **/ -static int check_snapshot_map(struct lvm_logical_volume * snap_volume) -{ - struct snapshot_map_entry ** table, * curr; - int i, j; - - if ( ! (snap_volume->lv_access & LV_SNAPSHOT) ) { - return 0; - } - if (!snap_volume->snapshot_map) { - snap_volume->lv_access |= EVMS_LV_INVALID; - return -EINVAL; - } - - for ( i = 1; i <= snap_volume->group->pv_count; i++ ) { - if (!snap_volume->snapshot_map[i]) { - snap_volume->lv_access |= EVMS_LV_INVALID; - return -EINVAL; - } - table = snap_volume->snapshot_map[i]; - for ( j = 0; j < snap_volume->hash_table_size; j++ ) { - for ( curr = table[j]; curr; curr = curr->next ) { - if ( curr->next && - curr->org_sector >= - curr->next->org_sector) { - snap_volume->lv_access |= - EVMS_LV_INVALID; - return -EINVAL; - } - } - } - } - return 0; -} - -/** - * check_logical_volumes - * - * Perform a consistency check on all of the logical volumes that have been - * discovered. Any volume that has any inconsistencies will be marked as - * incomplete or invalid, depending on the severity of the problem. At the - * end, all invalid volumes are deleted. If the deleted_incompletes - * parameter is set, those will also be deleted. - **/ -static int check_logical_volumes(int final_discovery) -{ - struct lvm_volume_group * group; - struct lvm_logical_volume * volume, * snap, * next; - int count, i, j; - - /* Check every valid, dirty volume group. */ - for ( group = lvm_group_list; group; group = group->next_group ) { - if ( ! (group->flags & EVMS_VG_DIRTY) ) { - continue; - } - /* Check every valid volume in this group. */ - for ( i = 1; i <= MAX_LV; i++ ) { - volume = group->volume_list[i]; - if (!volume) { - continue; - } - - LOG_DEBUG("Checking logical volume %s\n", volume->name); - - if (!volume->group) { - volume->group = group; - } - - /* All LE-map entries must have valid values. The I/O - * paths now detect missing LE entries. - */ - if (volume->le_map) { - for ( j = 0, count = 0; - j < volume->num_le; j++ ) { - if ( !volume->le_map[j].owning_pv || - !volume->le_map[j].pe_sector_offset ) { - count++; - } - } - if (count) { - LOG_SERIOUS("Volume %s has incomplete LE map.\n", - volume->name); - LOG_SERIOUS(" Missing %d out of %d LEs.\n", - count, volume->num_le); - volume->lv_access |= EVMS_LV_INCOMPLETE; - } else { - /* In case this volume was previously - * marked incomplete. - */ - volume->lv_access &= - ~EVMS_LV_INCOMPLETE; - } - } else { - /* This should only ever happen due to - * memory corruption. - */ - LOG_SERIOUS("Volume %s has no LE map.\n", - volume->name); - volume->lv_access |= EVMS_LV_INVALID; - } - - if ( volume->lv_access & LV_SNAPSHOT_ORG ) { - /* For a snapshot original, check all snapshots - * in the chain, to make sure they point back to - * the original. Also, make sure there is memory - * for the chunk buffer. - */ - for ( snap = volume->snapshot_next, count = 0; - snap; - snap = snap->snapshot_next, count++ ) { - if ( snap->snapshot_org != volume ) { - LOG_SERIOUS("Snapshot volume %s not pointing at correct original\n", - volume->name); - snap->snapshot_org = NULL; - snap->lv_access |= - EVMS_LV_INVALID; - } - } - if (!count) { - LOG_WARNING("No snapshots found for volume %s\n", - volume->name); - if (final_discovery) { - volume->lv_access &= - ~LV_SNAPSHOT_ORG; - } - } else if (!volume->chunk_data_buffer) { - volume->lv_access |= EVMS_LV_INVALID; - } - } else if ( volume->lv_access & LV_SNAPSHOT ) { - /* For a snapshot volume, make sure it points - * back to its original. Also make sure there is - * memory for the cow table, and that any - * existing snapshot entries in the snapshot map - * are correctly ordered. - */ - /* Is there a COW table? */ - if (!volume->cow_table) { - LOG_SERIOUS("Snapshot volume %s has no COW table\n", - volume->name); - volume->lv_access |= EVMS_LV_INVALID; - } - /* Is the snapshot map in order? */ - if ( check_snapshot_map(volume) ) { - LOG_SERIOUS("Snapshot volume %s has snapshot map inconsistency\n", - volume->name); - volume->lv_access |= EVMS_LV_INVALID; - } - /* Is there an original volume? This is only - * a real problem during final discovery. - */ - if (!volume->snapshot_org) { - LOG_SERIOUS("Snapshot volume %s not pointing at an original\n", - volume->name); - if (final_discovery) { - volume->lv_access |= - EVMS_LV_INVALID; - } - } - /* Is the original the correct one? */ - else if ( volume->snap_org_minor != - volume->snapshot_org->lv_minor ) { - LOG_SERIOUS("Snapshot volume %s not pointing at correct original\n", - volume->name); - volume->lv_access |= EVMS_LV_INVALID; - } - } - /* Delete any invalid volumes from use. Delete - * incomplete volumes as well if this is not final - * discovery. If a snapshot original is bad, delete all - * of its snapshots. - */ - if ( volume->lv_access & EVMS_LV_INVALID || - (!final_discovery && - (volume->lv_access & EVMS_LV_INCOMPLETE) && - (volume->lv_access & EVMS_LV_NEW)) ) { - if ( volume->lv_access & LV_SNAPSHOT_ORG ) { - for ( snap = volume->snapshot_next; - snap; snap = next ) { - next = snap->snapshot_next; - snap->snapshot_next = NULL; - snap->snapshot_org = NULL; - invalidate_snapshot_volume(snap); - deallocate_logical_volume(snap); - } - volume->snapshot_next = NULL; - } else if ( volume->lv_access & LV_SNAPSHOT ) { - invalidate_snapshot_volume(volume); - } - deallocate_logical_volume(volume); - } - } - } - - return 0; -} - - -/********** Volume Group Discovery Functions **********/ - - -/** - * find_group_for_pv - * - * This is a discover-time function. It reads the VG metadata info for the - * specified node, and locates the appropriate group that owns that - * node. If that group does not already exist, it is created and - * initialized. - **/ -static int find_group_for_pv(struct evms_logical_node * node, - struct pv_disk * pv, - struct lvm_volume_group ** group) -{ - struct vg_disk * vg; - int rc; - - *group = NULL; - - /* Check for an unassigned PV. */ - if ( pv->vg_name[0] == 0 ) { - return 0; - } - - /* Read the VG on-disk info for this PV. If this succeeds, it - * allocates a new VG metadata structure. - */ - rc = read_vg(node, pv, &vg); - if (rc) { - return rc; - } - - /* Use the UUID from the VG metadata to determine if this group - * has already been discovered and constructed. - */ - find_group_by_uuid(vg->vg_uuid, group); - - if (!*group) { - /* Create a new group entry and add to the global list. */ - *group = allocate_volume_group(vg, pv->vg_name); - if (!*group) { - return -ENOMEM; - } - add_group_to_list(*group); - } else if (!(*group)->vg) { - /* On a rediscover, the VG metadata for an existing group might - * be missing. Fill it in if necessary. This check is also not - * necessary in the engine, since the metadata is never deleted. - */ -/* Should we re-copy vg_name? (vg_uuid can not be allowed to change). - * Or should vg_name changes be done through direct ioctl only? - */ - (*group)->vg = vg; - } else { - kfree(vg); - } - - /* Read in the UUID list for this group, if it isn't present. */ - rc = read_uuid_list(node, pv, *group); - if (rc) { - LOG_WARNING("Error reading UUID list for group %s.\n", - (*group)->vg_name); - LOG_WARNING("May not be able to verify PV UUIDs for group %s\n", - (*group)->vg_name); - } - - /* In the kernel, any time we even see a PV for a group, that group - * must be marked dirty so its volumes will be re-exported. - */ - (*group)->flags |= EVMS_VG_DIRTY; - - return 0; -} - -/** - * check_for_duplicate_pv - * - * Search the list of PVs in the specified volume group. If the - * specified node already exists in the list, we can discard it. - **/ -static int check_for_duplicate_pv(struct evms_logical_node * node, - struct pv_disk * pv, - struct lvm_volume_group * group) -{ - struct lvm_physical_volume * pv_entry; - - /* For re-discovery, we need to search all existing PVs in this VG to - * make sure we didn't get a duplicate from the plugin below us. The - * plugins below us should be re-exporting the same node on - * re-discovery, instead of creating a new node to represent the same - * objects, so just check the memory location. - */ - for ( pv_entry = group->pv_list; pv_entry; pv_entry = pv_entry->next ) { - if ( pv_entry->logical_node == node ) { - - /* We found a duplicate. Just ignore the duplicate. */ - LOG_DEBUG("PV %s is already in Group %s.\n", - node->name, group->vg_name); - - /* Even if the node was a duplicate, we may need to - * fill in the pv entry for this partition, since we - * always delete those at the end of discovery. - */ - if (!pv_entry->pv) { - pv_entry->pv = pv; - pv_entry->pv_number = pv->pv_number; - } else { - kfree(pv); - } - - return 1; - } - } - - /* No duplicate was found. */ - return 0; -} - -/** - * verify_pv_uuid - * - * Verify that the specified PV belongs in the specified group by - * searching for the PV's UUID in the group's list. - **/ -static int verify_pv_uuid(struct lvm_physical_volume * pv_entry, - struct lvm_volume_group * group) -{ - int i; - - /* Obviously the UUID list must be present in order to search. */ - if (!group->uuid_list) { - LOG_WARNING("UUID list is missing from group %s.\n", - group->vg_name); - LOG_WARNING("Cannot verify UUID for PV %s\n", - pv_entry->logical_node->name); - return 0; - } - - /* Start with the UUID entry for this PV's number. */ - if ( ! memcmp(pv_entry->pv->pv_uuid, - &(group->uuid_list[(pv_entry->pv_number - 1) * NAME_LEN]), - UUID_LEN) ) { - return 0; - } - - /* If it wasn't found there, then search the entire group's list. */ - for ( i = 0; i < group->vg->pv_cur; i++ ) { - if ( ! memcmp(pv_entry->pv->pv_uuid, - &(group->uuid_list[i * NAME_LEN]), UUID_LEN) ) { - /* Found the UUID. */ - LOG_WARNING("Detected UUID mismatch for PV %s!\n", - pv_entry->logical_node->name); - LOG_WARNING("PV %s is recorded as being at index %d,\n", - pv_entry->logical_node->name, - pv_entry->pv_number); - LOG_WARNING(" but Group %s has it recorded at index %d.\n", - group->vg_name, i + 1); - LOG_WARNING("Run the EVMS Engine to correct the problem.\n"); - LOG_WARNING("If you have any snapshot regions in group %s\n", - group->vg_name); - LOG_WARNING(" it is recommended that you delete them immediately!\n"); - return 0; - } - } - - LOG_SERIOUS("Could not find UUID for PV %s in group %s\n", - pv_entry->logical_node->name, group->vg_name); - return -EINVAL; -} - -/** - * add_pv_to_group - * - * Adds the physical volume to the appropriate volume group. The PV - * passed into this function MUST be part of a valid VG. - **/ -static int add_pv_to_group(struct lvm_physical_volume * pv_entry, - struct lvm_volume_group * group) -{ - int rc; - - /* Make sure this PV's UUID is listed in the group. */ - rc = verify_pv_uuid(pv_entry, group); - if (rc) { - LOG_SERIOUS("PV %s does not belong in group %s!\n", - pv_entry->logical_node->name, group->vg_name); - return rc; - } - - /* Add this PV to the beginning of its group's list. */ - pv_entry->next = group->pv_list; - group->pv_list = pv_entry; - group->pv_count++; - - /* Update the group's block and hardsector sizes as appropriate. */ - group->block_size = max(pv_entry->logical_node->block_size, - group->block_size); - group->hard_sect_size = max(pv_entry->logical_node->hardsector_size, - group->hard_sect_size); - - /* Check for the Partial or Removable flag on the PV. */ - if ( pv_entry->logical_node->flags & EVMS_VOLUME_PARTIAL ) { - group->flags |= EVMS_VG_PARTIAL_PVS; - } - if ( pv_entry->logical_node->flags & EVMS_DEVICE_REMOVABLE ) { - group->flags |= EVMS_VG_REMOVABLE_PVS; - } - - LOG_DETAILS("PV %s added to Group %s\n", - pv_entry->logical_node->name, group->vg_name); - - return 0; -} - -/** - * discover_volume_groups - * - * Examine the list of logical nodes. Any node that contains a valid PV - * structure is consumed and added to the appropriate volume group. PVs - * which do not belong to any group are deleted. Everything else is left - * on the discovery list. - **/ -static int discover_volume_groups(struct evms_logical_node ** evms_node_list) -{ - struct evms_logical_node * node, * next_node; - struct pv_disk * pv; - struct lvm_volume_group * group; - struct lvm_physical_volume * pv_entry; - int rc; - - LOG_EXTRA("Searching for PVs in the node list.\n"); - - /* Run through the discovery list. */ - for ( node = *evms_node_list; node; node = next_node ) { - /* Save the next node. We may remove this one from the list. */ - next_node = node->next; - - /* Read the PV metadata. This will also create a new struct pv_disk - * if it finds the correct LVM signatures. - */ - rc = read_pv(node, &pv); - if (rc) { - /* This node is not an LVM PV, or an error occurred. - * Just leave the node on the discovery list. - */ - continue; - } - - rc = find_group_for_pv(node, pv, &group); - if (rc) { - /* Error getting the group for this PV. */ - kfree(pv); - continue; - } - - if (!group) { - /* This node is an unassigned PV. */ - LOG_DETAILS("PV %s is unassigned.\n", node->name); - kfree(pv); - continue; - } - - rc = check_for_duplicate_pv(node, pv, group); - if (rc) { - /* This node is already in the group. This check is also - * only in the kernel because the engine has no notion - * of rediscover, and thus can never get a duplicate. - */ - evms_cs_remove_logical_node_from_list(evms_node_list, - node); - continue; - } - - /* Allocate a PV entry for this node. */ - pv_entry = allocate_physical_volume(node, pv); - if (!pv_entry) { - continue; - } - - /* Add this PV to the appropriate volume group. */ - rc = add_pv_to_group(pv_entry, group); - if (rc) { - deallocate_physical_volume(pv_entry); - continue; - } - - rc = read_pe_map(pv_entry); - if (rc) { - LOG_WARNING("Error reading PE maps for node %s\n", - node->name); - LOG_WARNING("Any volumes residing on this node will be incomplete!\n"); - } - - evms_cs_remove_logical_node_from_list(evms_node_list, node); - } - - LOG_EXTRA("Group discovery complete.\n"); - return 0; -} - - -/********** Logical Volume Discovery Functions **********/ - - -/** - * build_le_maps - * - * After all logical volumes have been discovered, the mappings from - * logical extents to physical extents must be constructed. Each PV - * contains a map on-disk of its PEs. Each PE map entry contains the - * logical volume number and the logical extent number on that volume. - * Our internal map is the reverse of this map for each volume, listing - * the PV node and sector offset for every logical extent on the volume. - **/ -static int build_le_maps(struct lvm_volume_group * group) -{ - struct lvm_logical_volume ** volume_list = group->volume_list; - struct lvm_physical_volume * pv_entry; - struct evms_logical_node * node; - struct pv_disk * pv; - struct pe_disk * pe_map; - u64 offset; - u32 lv_number, le_number, first_pe_sector; - int i; - - LOG_DEBUG("Building LE maps for new volumes in group %s.\n", - group->vg_name); - - /* For every PV in this VG. */ - for ( pv_entry = group->pv_list; pv_entry; pv_entry = pv_entry->next ) { - node = pv_entry->logical_node; - pv = pv_entry->pv; - pe_map = pv_entry->pe_map; - - /* Version 1 metadata uses pe_on_disk.base + .size to find start - * of first PE. Version 2 uses pe_start. - */ - if (pv->version == 1) { - first_pe_sector = - evms_cs_size_in_vsectors(pv->pe_on_disk.base + - pv->pe_on_disk.size); - } else { - first_pe_sector = pv->pe_start; - if (!first_pe_sector) { - first_pe_sector = - evms_cs_size_in_vsectors(pv->pe_on_disk.base + - pv->pe_on_disk.size); - } - } - - /* For every entry in the PE map, calculate the PE's sector offset - * and update the correct LV's PE map. LV number of 0 marks an unused PE. - * For re-discovery, only compute entries for new volumes. If a PV - * is read-only, all LVs on that PV will also be read-only. - */ - for ( i = 0; i < pv->pe_total; i++ ) { - lv_number = pe_map[i].lv_num; - if ( lv_number && - volume_list[lv_number] && - volume_list[lv_number]->lv_access & - (EVMS_LV_NEW | EVMS_LV_INCOMPLETE) ) { - le_number = pe_map[i].le_num; - offset = i * pv->pe_size + first_pe_sector; - volume_list[lv_number]->le_map[le_number].owning_pv = - pv_entry; - volume_list[lv_number]->le_map[le_number].pe_sector_offset = - offset; - if ( node->flags & EVMS_VOLUME_SET_READ_ONLY ) { - volume_list[lv_number]->lv_access &= - ~LV_WRITE; - } - } - } - } - - return 0; -} - -/** - * build_snapshot_maps - * - * For every volume in this group that is a snapshot, read all of the - * existing entries in the COW table, and build up the snapshot mapping - * structures accordingly. - * - * For reference, the COW tables attached to the snapshot volumes will - * always be in disk-order (little-endian), so that it can always be - * immediately written to disk. Therefore, endian conversions are necessary - * any time the COW table is accessed. This function will make a local - * copy of each COW table sector, and convert the local copy before - * building the snapshot maps. - **/ -static int build_snapshot_maps(struct lvm_volume_group * group) -{ - struct lvm_logical_volume * volume; - struct evms_logical_node tmp_node; - struct lv_COW_table_disk cow_table[EVMS_VSECTOR_SIZE / - sizeof(struct lv_COW_table_disk)]; - unsigned long max_entries = EVMS_VSECTOR_SIZE / - sizeof(struct lv_COW_table_disk); - int i, j; - - /* Check every volume in the group to see if it is a snapshot. Also - * check to make sure it is a new volume in the case of re-discovery. - */ - for ( i = 1; i <= MAX_LV; i++ ) { - - /* The volume must exist, must be new, and must be a snapshot. - */ - volume = group->volume_list[i]; - if ( !volume || - !(volume->lv_access & EVMS_LV_NEW) || - !(volume->lv_access & LV_SNAPSHOT)) { - continue; - } - - /* Set up a temporary EVMS node. */ - tmp_node.private = volume; - - LOG_DEBUG("Building snapshot map for volume %s\n", - volume->name); - - while (1) { - /* Read in one sector's worth of COW tables. */ - if ( lvm_init_io(&tmp_node, 0, - volume->current_cow_sector, - 1, volume->cow_table) ) { - goto error; - } - - /* Endian-conversion of this COW table - * to a local table. - */ - for ( j = 0; j < max_entries; j++ ) { - cow_table[j].pv_org_number = - le64_to_cpu(volume->cow_table[j].pv_org_number); - cow_table[j].pv_org_rsector = - le64_to_cpu(volume->cow_table[j].pv_org_rsector); - cow_table[j].pv_snap_number = - le64_to_cpu(volume->cow_table[j].pv_snap_number); - cow_table[j].pv_snap_rsector = - le64_to_cpu(volume->cow_table[j].pv_snap_rsector); - } - - /* Translate every valid COW table entry into - * a snapshot map entry. - */ - for ( volume->next_cow_entry = 0; - volume->next_cow_entry < max_entries && - cow_table[volume->next_cow_entry].pv_org_number; - volume->next_cow_entry++ ) { - /* org_rsector must be a valid sector number, - * i.e. it can't be within a PVs metadata. This - * is how we detect invalidated snapshots. - */ - if ( cow_table[volume->next_cow_entry].pv_org_rsector < 10 || - cow_table[volume->next_cow_entry].pv_org_number > group->pv_count || - add_cow_entry_to_snapshot_map(&(cow_table[volume->next_cow_entry]), volume) ) { - /* This volume either has an invalid COW entry, - * or had an error adding that COW entry to the - * snapshot map. This snapshot is done. - */ - goto error; - } - volume->next_free_chunk += volume->chunk_size; - } - - /* Move on to the next sector if necessary. */ - if ( volume->next_cow_entry == max_entries ) { - volume->current_cow_sector++; - } else { - break; - } - } - } - -out: - return 0; -error: - invalidate_snapshot_volume(volume); - deallocate_logical_volume(volume); - goto out; -} - -/** - * link_snapshot_volumes - * - * This function examines the list of logical volumes in this group and - * sets up the necessary pointers to link snapshots and their originals. - * A singly-linked list is created starting with the original volume. Also, - * all snapshot volumes point directly back to their original. This - * function should not be run until all volumes have been discovered. - * In the case of re-discovery, all of these links/lists get rebuilt as if - * they were not already there. Currently this should not pose a problem. - **/ -static int link_snapshot_volumes(struct lvm_volume_group * group) -{ - struct lvm_logical_volume * org_volume, * snap_volume; - u32 org_minor, buffer_size = 0; - int i, j; - - for ( i = 1; i <= MAX_LV; i++ ) { - - /* Only process snapshot-originals. */ - org_volume = group->volume_list[i]; - if ( !org_volume || !(org_volume->lv_access & LV_SNAPSHOT_ORG) ) { - continue; - } - - /* For snapshot-originals, look for all other volumes that - * claim to be snapshotting it. For each one that is found, - * insert it at the start of the original's list of snapshots. - * Need to start with a NULL snapshot_next, otherwise could - * wind up with circular lists. - */ - org_minor = org_volume->lv_minor; - org_volume->snapshot_next = NULL; - - for ( j = 1; j <= MAX_LV; j++ ) { - snap_volume = group->volume_list[j]; - if ( snap_volume && - snap_volume->lv_access & LV_SNAPSHOT && - (snap_volume->snap_org_minor == org_minor) ) { - snap_volume->snapshot_org = org_volume; - snap_volume->snapshot_next = - org_volume->snapshot_next; - org_volume->snapshot_next = snap_volume; - if ( snap_volume->chunk_size > buffer_size ) { - buffer_size = snap_volume->chunk_size; - } - LOG_DEBUG("Linking snapshot (%s) to original (%s)\n", - snap_volume->name, org_volume->name); - } - } - - /* If no snapshots were found for a volume that claims to be - * under snapshot, mark the group dirty. If this is final - * discovery, the original will have the snapshot flag turned - * off in check_logical_volumes(). - */ - if (!org_volume->snapshot_next) { - LOG_WARNING("No snapshots found for original (%s)\n", - org_volume->name); - group->flags |= EVMS_VG_DIRTY; - } - } - return 0; -} - -/** - * discover_volumes_in_group - **/ -static int discover_volumes_in_group(struct lvm_volume_group * group) -{ - struct lv_disk * lv_array = group->lv_array; - struct lvm_logical_volume * new_volume; - int i; - - /* Search through the LV structs for valid LV entries. */ - for ( i = 0; i < group->vg->lv_max; i++ ) { - - /* Only discover valid, active volumes. */ - if ( !lv_array[i].lv_name[0] || - lv_array[i].lv_number >= MAX_LV ) { - continue; - } - - /* Make sure this volume isn't already in the list. */ - if (group->volume_list[lv_array[i].lv_number + 1]) { - continue; - } - - /* Create a new logical volume and place it in the appropriate - * spot in this VG's volume list. - */ - new_volume = allocate_logical_volume(&(lv_array[i]), group); - if (!new_volume) { - /* This volume will be missing, but other - * volumes in this group can still be built. - */ - LOG_CRITICAL("Error allocating LV %s in Group %s\n", - lv_array[i].lv_name, group->vg_name); - continue; - } - - group->volume_list[new_volume->lv_number] = new_volume; - group->volume_count++; - group->flags |= EVMS_VG_DIRTY; - - LOG_DEBUG("Discovered volume %s in group %s.\n", - new_volume->name, group->vg_name); - } - - return 0; -} - -/** - * discover_logical_volumes - * - * After all PVs have been claimed and added to the appropriate VG list, - * the volumes for each VG must be constructed. For each group, read all - * the LV structs off the first PV in the list. Search this list of - * structs for valid LVs. For each valid LV, create a new volume and add - * it to the group. - **/ -static int discover_logical_volumes(int final_discovery) -{ - struct lvm_volume_group *group; - int rc; - - /* Look for volumes in each valid VG entry. We even need to check ones - * that aren't dirty - We could have deleted an incomplete volume on - * the previous pass, and need to rediscover it in case this is final - * discovery and we now want to export it. - */ - for ( group = lvm_group_list; group; group = group->next_group ) { - - if ( ! group->vg || - (! final_discovery && - ! (group->flags & EVMS_VG_DIRTY)) ) { - continue; - } - - LOG_DEBUG("Searching for volumes in group %s\n", - group->vg_name); - - /* Read in the LV array from disk if necessary. */ - rc = read_lv(group); - if (rc) { - LOG_WARNING("Unable to read LV metadata for group %s\n", - group->vg_name); - LOG_WARNING("No regions can be discovered for group %s\n", - group->vg_name); - continue; - } - - /* Assemble each volume in the group. */ - discover_volumes_in_group(group); - - /* Build the LE map for each LV discovered in this group. This - * must be done after all LVS in the group are discovered. - */ - build_le_maps(group); - check_le_maps(group); - - /* Set up all of the initial snapshot maps. Only the kernel - * keeps track of the snapshot maps. - */ - build_snapshot_maps(group); - - /* Set up the pointers to link snapshot volumes - * with their originals. - */ - link_snapshot_volumes(group); - } - - return 0; -} - -/** - * export_volumes - * - * The last thing the plugin must do is take each newly constructed volume - * and place it on the evms logical node list. A zero return-code from - * this function means nothing new was added to the list, and a positive - * return code means that many new items were added to the list. - **/ -static int export_volumes(struct evms_logical_node ** evms_node_list, - int final_discover) -{ - struct lvm_volume_group * group; - struct evms_logical_node * new_node; - struct lvm_logical_volume * volume; - int i, count = 0; - - LOG_EXTRA("Exporting volumes\n"); - - /* For every valid, dirty volume group. */ - for ( group = lvm_group_list; group; group = group->next_group ) { - if ( ! (group->flags & EVMS_VG_DIRTY) ) { - continue; - } - - /* Export every valid volume in the group. For re-discovery, - * we re-export the same logical node. - */ - for ( i = 1; i <= MAX_LV; i++ ) { - volume = group->volume_list[i]; - if (!volume) { - continue; - } - - /* For new volumes, create a new EVMS node and - * initialize the appropriate fields. - */ - if ( volume->lv_access & EVMS_LV_NEW ) { - if ( evms_cs_allocate_logical_node(&new_node) ) { - continue; - } - MOD_INC_USE_COUNT; - - volume->volume_node = new_node; - volume->lv_access &= (~EVMS_LV_QUIESCED & - ~EVMS_LV_NEW); - new_node->hardsector_size = - group->hard_sect_size; - new_node->block_size = group->block_size; - new_node->plugin = &lvm_plugin_header; - new_node->private = volume; - memcpy(new_node->name, volume->name, NAME_LEN); - - /* Snapshot volumes should report the - * size of their original. - */ - new_node->total_vsectors = - (volume->lv_access & LV_SNAPSHOT) ? - volume->snapshot_org->lv_size : - volume->lv_size; - - /* Is the volume read-only? */ - if ( ! (volume->lv_access & LV_WRITE) ) { - new_node->flags |= - EVMS_VOLUME_READ_ONLY; - LOG_DEBUG("LVM volume %s is read-only\n", - volume->name); - } - - /* Is the volume incomplete? */ - if ( volume->lv_access & EVMS_LV_INCOMPLETE ) { - new_node->flags |= - (EVMS_VOLUME_READ_ONLY | - EVMS_VOLUME_PARTIAL); - LOG_DEBUG("LVM volume %s is incomplete\n", - volume->name); - } - - /* Does the volume group contain any partial or - * removable PVs? - */ - if ( group->flags & EVMS_VG_PARTIAL_PVS ) { - new_node->flags |= EVMS_VOLUME_PARTIAL; - } - if ( group->flags & EVMS_VG_REMOVABLE_PVS ) { - new_node->flags |= - EVMS_DEVICE_REMOVABLE; - } - } - - /* Export the node, only if it hasn't been exported - * during this full EVMS discover. - */ - if ( ! (volume->lv_access & EVMS_LV_EXPORTED) ) { - if ( ! evms_cs_add_logical_node_to_list(evms_node_list, - volume->volume_node) ) { - LOG_DETAILS("Exporting LVM volume %s\n", - volume->name); - volume->lv_access |= EVMS_LV_EXPORTED; - count++; - } - } - - if (final_discover) { - volume->lv_access &= ~EVMS_LV_EXPORTED; - } - } - - /* The group is clean now. */ - group->flags &= ~EVMS_VG_DIRTY; - } - - return count; -} - -/** - * lvm_cleanup - * - * This function runs through the entire lvm data structure, removing - * all items that are not needed at runtime. Currently, this is just the - * struct vg_disk structure and the struct pv_disk structure for each PV. - * Also, any groups that don't contain any volumes are deleted. All of the - * other volume_group, logical_volume and evms_logical_node structures will - * be kept around at run-time. - **/ -static int lvm_cleanup(void) -{ - struct lvm_volume_group * group, * next_group; - struct lvm_physical_volume * pv_entry; - - for ( group = lvm_group_list; group; group = next_group ) { - next_group = group->next_group; - - /* Delete groups with no volumes. */ - if (!group->volume_count) { - LOG_WARNING("Group %s contains no logical volumes. Deleting.\n", - group->vg_name); - remove_group_from_list(group); - deallocate_volume_group(group); - /* Need to go back to the start of the list, - * just to be safe. :) - */ - next_group = lvm_group_list; - continue; - } - - /* Delete data structures that aren't used at runtime. */ - if (group->vg) { - kfree(group->vg); - group->vg = NULL; - } - - for ( pv_entry = group->pv_list; - pv_entry; pv_entry = pv_entry->next) { - if (pv_entry->pv) { - kfree(pv_entry->pv); - pv_entry->pv = NULL; - } - if (pv_entry->pe_map) { - vfree(pv_entry->pe_map); - pv_entry->pe_map = NULL; - } - } - if (group->lv_array_disk) { - vfree(group->lv_array_disk); - group->lv_array_disk = group->lv_array = NULL; - } - if (group->uuid_list) { - vfree(group->uuid_list); - group->uuid_list = NULL; - } - } - return 0; -} - -/** - * lvm_get_bmap - * - * Support for the BMAP ioctl used by LILO to translate filesystem blocks - * to disk blocks to map kernel images for boot time. - **/ -static int lvm_get_bmap(struct evms_logical_node * node, - struct evms_get_bmap_pkt * bmap, - struct evms_logical_node ** pv_node) -{ - struct lvm_logical_volume * volume = node->private; - struct lvm_physical_volume * pv_entry; - u64 pe_start_sector, new_sector = 0, new_size = 0; - int rc = 0; - - /* No kernel images allowed on snapshot LVs. */ - if ( volume->lv_access & LV_SNAPSHOT ) { - return -EINVAL; - } - - /* Range check. */ - if ( bmap->rsector >= volume->lv_size ) { - return -EINVAL; - } - - rc = remap_sector(node, bmap->rsector, 1, &new_sector, - &new_size, &pe_start_sector, &pv_entry); - - if (rc || !pv_entry || !new_sector) { - return -EINVAL; - } - - bmap->rsector = new_sector; - *pv_node = pv_entry->logical_node; - - return 0; -} - -/** - * lvm_global_proc_read - * - * A callback function for the lvm-global proc-fs entry. This will print - * general info about all LVM VGs, PVs, and LVs. - **/ -static int lvm_global_proc_read(char * page, char ** start, off_t off, - int count, int * eof, void * data) -{ - struct lvm_volume_group * group; - struct lvm_physical_volume * pv_entry; - struct lvm_logical_volume * volume, * snap; - int vgs = 0, lvs = 0, pvs = 0; - int i, sz = 0; - - PROCPRINT("Enterprise Volume Management System: LVM Plugin\n"); - PROCPRINT("Plugin ID: %x.%x.%x\n", - GetPluginOEM(lvm_plugin_header.id), - GetPluginType(lvm_plugin_header.id), - GetPluginID(lvm_plugin_header.id)); - PROCPRINT("Plugin Version: %d.%d.%d\n", - lvm_plugin_header.version.major, - lvm_plugin_header.version.minor, - lvm_plugin_header.version.patchlevel); - PROCPRINT("Required EVMS Services Version: %d.%d.%d\n", - lvm_plugin_header.required_services_version.major, - lvm_plugin_header.required_services_version.minor, - lvm_plugin_header.required_services_version.patchlevel); - - /* Count all existing items. */ - for ( group = lvm_group_list; group; group = group->next_group ) { - lvs += group->volume_count; - pvs += group->pv_count; - vgs++; - } - - PROCPRINT("\n"); - PROCPRINT("Total: %d VGs %d PVs %d LVs\n", vgs, pvs, lvs); - - /* Print out specifics about each VG. */ - for ( group = lvm_group_list; group; group = group->next_group ) { - PROCPRINT("\n"); - PROCPRINT("VG: %s [%d PV, %d LV]\n", - group->vg_name, group->pv_count, group->volume_count); - PROCPRINT("PVs:\n"); - for ( pv_entry = group->pv_list; - pv_entry; pv_entry = pv_entry->next ) { - if (pv_entry->logical_node) { - PROCPRINT("\t%s\t%10Ld KB\n", - pv_entry->logical_node->name, - (long long)pv_entry->logical_node->total_vsectors / 2); - } - } - PROCPRINT("LVs:\n"); - for ( i = 1; i <= MAX_LV; i++ ) { - if (group->volume_list[i]) { - volume = group->volume_list[i]; - PROCPRINT("\t%s\t%10Ld KB / %5d LEs", - volume->name, - (long long)volume->lv_size / 2, - volume->num_le); - if ( volume->lv_access & LV_SNAPSHOT ) { - PROCPRINT("\tSnapshot of : "); - if (volume->snapshot_org) { - PROCPRINT("%s : ", - volume->snapshot_org->name); - } else { - PROCPRINT("(unknown) : "); - } - PROCPRINT("%ld%% full : ", - (long)(volume->next_free_chunk) * - 100 / (long)(volume->lv_size)); - if ( volume->lv_status & LV_ACTIVE ) { - PROCPRINT("active"); - } else { - PROCPRINT("disabled"); - } - } else if ( volume->lv_access & LV_SNAPSHOT_ORG ) { - PROCPRINT("\tSnapshotted by : "); - for ( snap = volume->snapshot_next; - snap; - snap = snap->snapshot_next ) { - PROCPRINT("%s ", snap->name); - } - } - PROCPRINT("\n"); - } - } - } - -out: - *start = page + off; - sz -= off; - if (sz < 0) - sz = 0; - return sz > count ? count : sz; -} - - -/********** Required EVMS Plugin Functions **********/ - - -/** - * lvm_discover - * - * This is the entry point into the LVM discovery process. It is a three - * phase process. First, the list of nodes are examined for PVs, and the - * appropriate volume groups are created. Then each volume group is - * examined to find all available logical volumes. Finally, each LVM - * logical volume has a new EVMS node created for it, and added to the - * list of nodes. - **/ -static int lvm_discover(struct evms_logical_node ** evms_node_list) -{ - int rc; - - MOD_INC_USE_COUNT; - LOG_EXTRA("Beginning discovery.\n"); - - discover_volume_groups(evms_node_list); - - check_volume_groups(); - - discover_logical_volumes(FALSE); - - check_logical_volumes(FALSE); - - rc = export_volumes(evms_node_list, FALSE); - - LOG_EXTRA("Discovery complete.\n"); - MOD_DEC_USE_COUNT; - return rc; -} - -/** - * lvm_discover_end - * - * The discovery process at the region-manager level is now iterative, - * much like the EVMS feature level. This allows the ability to stack - * LVM on top of MD, or vice-versa. To accomplish this correctly, and - * also to accomplish partial volume discovery, a second discover - * entry point is needed, so EVMS can tell the region managers that - * discovery is over, and to finish up any discovery that is not yet - * complete. When this function is called, it should be assumed that - * the node list has had nothing new added to it since the last call - * of the regular discover function. Therefore, when this function is - * called, we do not need to try to discovery any additional volume - * groups. We will, however, look for logical volumes once more. This - * gives us the ability to export (read-only) volumes that have - * partially corrupted LE maps due to missing PVs in their VG. - **/ -static int lvm_discover_end(struct evms_logical_node ** evms_node_list) -{ - int rc; - - MOD_INC_USE_COUNT; - LOG_EXTRA("Beginning final discovery\n"); - - discover_volume_groups(evms_node_list); - - check_volume_groups(); - - discover_logical_volumes(TRUE); - - check_logical_volumes(TRUE); - - rc = export_volumes(evms_node_list, TRUE); - - lvm_cleanup(); - - LOG_EXTRA("Final discovery complete.\n"); - MOD_DEC_USE_COUNT; - return rc; -} - -/** - * lvm_delete_node - * - * This function deletes the in-memory representation of an LVM logical volume. - **/ -static int lvm_delete_node(struct evms_logical_node * logical_node) -{ - struct lvm_logical_volume * volume = logical_node->private; - struct lvm_volume_group * group = volume->group; - - LOG_DEBUG("Deleting LVM node %s\n", logical_node->name); - - if ( deallocate_logical_volume(volume) ) { - return -EINVAL; - } - - /* If we just removed the last volume from this group, the entire group - * must also be deleted. - */ - if ( group && group->volume_count == 0 ) { - remove_group_from_list(group); - deallocate_volume_group(group); - } - - /* Free the logical node. */ - evms_cs_deallocate_logical_node(logical_node); - MOD_DEC_USE_COUNT; - return 0; -} - -/** - * lvm_read - **/ -static void lvm_read(struct evms_logical_node * node, - struct buffer_head * bh) -{ - struct lvm_logical_volume * volume = node->private; - struct lvm_physical_volume * pv_entry; - u64 size = bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - u64 new_sector, new_size, pe_start_sector; - - /* If this volume is a snapshot, lock the volume, and do - * the LE-PE translation on its original volume. - */ - if ( volume->lv_access & LV_SNAPSHOT ) { - down(&volume->snap_semaphore); - if (!volume->snapshot_org) { - goto out_error; - } - node = volume->snapshot_org->volume_node; - } - - /* Make sure the volume is active and readable. */ - if ( !(volume->lv_access & LV_READ && - volume->lv_status & LV_ACTIVE) ) { - goto out_error; - } - - /* Check if I/O goes past end of logical volume. Must use the - * node, not the volume, so snapshots will work correctly. - */ - if ( bh->b_rsector + size > node->total_vsectors ) { - goto out_error; - } - - /* Logical-to-Physical remapping. Check for incomplete volumes. - * Check intermediate boundary conditions as well. - */ - if ( remap_sector(node, bh->b_rsector, size, &new_sector, - &new_size, &pe_start_sector, &pv_entry) || - !pe_start_sector || !pv_entry || - size != new_size ) { - goto out_error; - } - - /* For snapshot volumes, check if this sector's chunk has been - * remapped. If it has, new_sector and pv_entry will be changed - * accordingly. If not, they remain the same. - */ - if ( volume->lv_access & LV_SNAPSHOT ) { - snapshot_remap_sector(volume, pe_start_sector, - &new_sector, &pv_entry); - } - - bh->b_rsector = new_sector; - R_IO(pv_entry->logical_node, bh); - -out: - /* Unlock the snapshot. */ - if ( volume->lv_access & LV_SNAPSHOT ) { - up(&volume->snap_semaphore); - } - return; - -out_error: - bh->b_end_io(bh, 0); - goto out; -} - -/** - * lvm_write - **/ -static void lvm_write(struct evms_logical_node * node, - struct buffer_head * bh) -{ - struct lvm_logical_volume * volume = node->private; - struct lvm_logical_volume * snap_volume; - struct lvm_physical_volume * pv_entry; - u64 size = bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - u64 new_sector, new_size, pe_start_sector; - - /* Make sure the volume is active and writable. */ - if ( !(volume->lv_access & LV_WRITE && - volume->lv_status & LV_ACTIVE) ) { - goto out_error; - } - - /* Check if I/O goes past end of logical volume. */ - if ( bh->b_rsector + size > node->total_vsectors ) { - goto out_error; - } - - /* Logical-to-Physical remapping. Check for incomplete volumes. - * Check intermediate boundary conditions as well. - */ - if ( remap_sector(node, bh->b_rsector, size, &new_sector, - &new_size, &pe_start_sector, &pv_entry) || - !pe_start_sector || !pv_entry || - size != new_size ) { - goto out_error; - } - - /* Copy-on-write for snapshotting. */ - if ( volume->lv_access & LV_SNAPSHOT_ORG ) { - /* Originals can be snapshotted multiple times. */ - for ( snap_volume = volume->snapshot_next; - snap_volume; snap_volume = snap_volume->snapshot_next ) { - if ( snapshot_copy_data(volume, snap_volume, - pe_start_sector, new_sector, - pv_entry) ) { - goto out_error; - } - } - } - - bh->b_rsector = new_sector; - W_IO(pv_entry->logical_node, bh); -out: - return; -out_error: - bh->b_end_io(bh, 0); - goto out; -} - -/** - * lvm_init_io - * - * Init_io on a snapshot volume treats it like a regular volume. - **/ -static int lvm_init_io(struct evms_logical_node * node, - int io_flag, - u64 sect_nr, - u64 num_sects, - void * buf_addr) -{ - struct lvm_logical_volume * volume = node->private; - struct lvm_physical_volume * pv_entry; - u64 pe_start_sector, new_sector, new_size; - int rc = 0; - - /* Only allow internal writes to snapshots (io_flag==4). Disallow - * writes to snapshot originals. - */ - if ( io_flag == WRITE && - volume->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG) ) { - return -EINVAL; - } - - /* The node for a snapshot reports the size of the original. If a - * request comes in in that range, just return. - */ - else if ( volume->lv_access & LV_SNAPSHOT && - sect_nr >= volume->lv_size && - sect_nr < node->total_vsectors ) { - if ( io_flag == READ ) { - memset(buf_addr, 0, - num_sects << EVMS_VSECTOR_SIZE_SHIFT); - } - return 0; - } - - /* Regular range check. */ - else if ( sect_nr + num_sects > volume->lv_size ) { - return -EINVAL; - } - - if ( io_flag == 4 ) { - io_flag = WRITE; - } - - /* Init IO needs to deal with the possibility of a request that spans - * PEs or stripes. This is possible because there is no limit on - * num_sects. To handle this, we loop through remap_sector and - * INIT_IO until num_sects reaches zero. - */ - while (num_sects) { - if ( remap_sector(node, sect_nr, num_sects, &new_sector, - &new_size, &pe_start_sector, &pv_entry) ) { - return -EIO; - } - - /* If the volume is incomplete, clear the buffer (on a read). */ - if (!pe_start_sector || !pv_entry) { - if ( io_flag == READ ) { - memset(buf_addr, 0, - new_size << EVMS_VSECTOR_SIZE_SHIFT); - } - } else { - rc = INIT_IO(pv_entry->logical_node, io_flag, - new_sector, new_size, buf_addr); - } - num_sects -= new_size; - sect_nr += new_size; - buf_addr = (void *)(((unsigned long) buf_addr) + - (unsigned long)(new_size << EVMS_VSECTOR_SIZE_SHIFT)); - } - - return rc; -} - -/** - * lvm_ioctl - **/ -static int lvm_ioctl(struct evms_logical_node * logical_node, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct lvm_logical_volume * volume = logical_node->private; - int rc = 0; - - LOG_ENTRY_EXIT("Ioctl %d\n", cmd); - - switch (cmd) { - - case HDIO_GETGEO: - { - /* Fixed geometry for all LVM volumes. */ - unsigned char heads = 64; - unsigned char sectors = 32; - short cylinders; - long start = 0; - struct hd_geometry * hd = (struct hd_geometry *)arg; - cylinders = logical_node->total_vsectors; - cylinders = (cylinders / heads) / sectors; - - if (!hd) { - return -EINVAL; - } - - if ( copy_to_user((char *)(&hd->heads), - &heads, sizeof(heads)) || - copy_to_user((char *)(&hd->sectors), - §ors, sizeof(sectors)) || - copy_to_user((short *)(&hd->cylinders), - &cylinders, sizeof(cylinders)) || - copy_to_user((long *)(&hd->start), - &start, sizeof(start)) ) { - return -EFAULT; - } - } - break; - - case EVMS_QUIESCE_VOLUME: - { - struct evms_quiesce_vol_pkt * tmp = - (struct evms_quiesce_vol_pkt *)arg; - if (tmp->command) { - volume->lv_access |= EVMS_LV_QUIESCED; - } else { - volume->lv_access &= ~EVMS_LV_QUIESCED; - } - } - break; - - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt * bmap = - (struct evms_get_bmap_pkt *)arg; - struct evms_logical_node * pv_node; - - rc = lvm_get_bmap(logical_node, bmap, &pv_node); - if (!rc) { - rc = IOCTL(pv_node, inode, file, cmd, - (unsigned long) bmap); - } - } - break; - - case EVMS_GET_DISK_LIST: - case EVMS_CHECK_MEDIA_CHANGE: - case EVMS_REVALIDATE_DISK: - case EVMS_OPEN_VOLUME: - case EVMS_CLOSE_VOLUME: - case EVMS_CHECK_DEVICE_STATUS: - { - /* These five ioctl all need to - * be broadcast to all PVs. - */ - struct lvm_volume_group * group = volume->group; - struct lvm_physical_volume * pv_entry; - for ( pv_entry = group->pv_list; - pv_entry; pv_entry = pv_entry->next ) { - rc |= IOCTL(pv_entry->logical_node, inode, - file, cmd, arg); - } - } - break; - - default: - /* Currently LVM does not send any ioctl's down to the - * PVs. Which PV would they go to? What would we do with - * the return codes? - */ - rc = -EINVAL; - } - - return rc; -} - -/** - * lvm_direct_ioctl - * - * This function provides a method for user-space to communicate directly - * with a plugin in the kernel. - **/ -static int lvm_direct_ioctl(struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long args) -{ - struct evms_plugin_ioctl_pkt pkt, * user_pkt; - struct lvm_pv_remove_ioctl pv_remove, * user_pv_remove; - struct lvm_snapshot_stat_ioctl snap_stats, * user_snap_stats; - int rc = 0; - - MOD_INC_USE_COUNT; - - user_pkt = (struct evms_plugin_ioctl_pkt *)args; - - /* Copy user's parameters to kernel space. */ - if ( copy_from_user(&pkt, user_pkt, sizeof(pkt)) ) { - MOD_DEC_USE_COUNT; - return -EFAULT; - } - - /* Make sure this is supposed to be our ioctl. */ - if ( pkt.feature_id != lvm_plugin_header.id ) { - MOD_DEC_USE_COUNT; - return -EINVAL; - } - - switch (pkt.feature_command) { - - case EVMS_LVM_PV_REMOVE_IOCTL: - user_pv_remove = - (struct lvm_pv_remove_ioctl *)pkt.feature_ioctl_data; - if ( copy_from_user(&pv_remove, user_pv_remove, - sizeof(pv_remove)) ) { - rc = -EINVAL; - break; - } - rc = remove_pv_from_group(pv_remove.pv_number, - pv_remove.vg_uuid); - break; - - case EVMS_LVM_SNAPSHOT_STAT_IOCTL: - user_snap_stats = - (struct lvm_snapshot_stat_ioctl *)pkt.feature_ioctl_data; - if ( copy_from_user(&snap_stats, user_snap_stats, - sizeof(snap_stats)) ) { - rc = -EINVAL; - break; - } - rc = get_snapshot_stats(&snap_stats); - if ( copy_to_user(user_snap_stats, &snap_stats, - sizeof(snap_stats)) ) { - rc = -EINVAL; - break; - } - break; - - default: - rc = -EINVAL; - break; - } - - pkt.status = rc; - copy_to_user(user_pkt, &pkt, sizeof(pkt)); - MOD_DEC_USE_COUNT; - return rc; -} - -/** - * lvm_vge_init - **/ -int __init lvm_vge_init(void) -{ - struct proc_dir_entry *pde; - - lvm_group_list = NULL; - lvm_proc = NULL; - - /* Register the global proc-fs entries. */ - pde = evms_cs_get_evms_proc_dir(); - if (pde) { - lvm_proc = create_proc_entry(LVM_PROC_NAME, S_IFDIR, pde); - if (lvm_proc) { - create_proc_read_entry(LVM_PROC_GLOBAL_NAME, S_IFREG, - lvm_proc, lvm_global_proc_read, - NULL); - } - } - - /* Register this plugin with EVMS. */ - return evms_cs_register_plugin(&lvm_plugin_header); -} - -/** - * lvm_vge_exit - **/ -void __exit lvm_vge_exit(void) -{ - struct lvm_volume_group * group, * next_group; - struct proc_dir_entry * pde; - int i; - - /* If LVM is called for module_exit, that means the reference - * count must be zero, which means there should be no volumes, - * and thus no volume groups. But, check anyway and delete - * any volumes and groups that are still hanging around. - */ - if (lvm_group_list) { - LOG_SERIOUS("Called for module_exit, but group list is not empty!\n"); - } - - for ( group = lvm_group_list; group; group = next_group ) { - next_group = group->next_group; - - LOG_SERIOUS("In module_exit: deleting all volumes from group %s.\n", - group->vg_name); - - for ( i = 1; i <= MAX_LV; i++ ) { - if (group->volume_list[i]) { - lvm_delete_node(group->volume_list[i]->volume_node); - } - } - } - - /* Unregister the proc-fs entries. */ - pde = evms_cs_get_evms_proc_dir(); - if (pde) { - remove_proc_entry(LVM_PROC_GLOBAL_NAME, lvm_proc); - remove_proc_entry(LVM_PROC_NAME, pde); - } - - /* Unregister this plugin from EVMS. */ - evms_cs_unregister_plugin(&lvm_plugin_header); -} - -module_init(lvm_vge_init); -module_exit(lvm_vge_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_core.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_core.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_core.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_core.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,3617 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - * linux/drivers/evms/md_core.c - * - * EVMS Linux MD Region Manager - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_PREFIX "md core: " - -/* - * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' - * is 100 KB/sec, so the extra system load does not show up that much. - * Increase it if you want to have more _guaranteed_ speed. Note that - * the RAID driver will use the maximum available bandwith if the IO - * subsystem is idle. There is also an 'absolute maximum' reconstruction - * speed limit - in case reconstruction slows down your system despite - * idle IO detection. - * - * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. - */ - -static MD_LIST_HEAD(all_raid_disks); -static MD_LIST_HEAD(pending_raid_disks); - -static int sysctl_speed_limit_min = 100; -static int sysctl_speed_limit_max = 100000; - - -static mdk_personality_t *pers[MAX_PERSONALITY]; - -static int md_blocksizes[MAX_MD_DEVS]; -static int md_hardsect_sizes[MAX_MD_DEVS]; -int evms_md_size[MAX_MD_DEVS]; -static struct evms_thread *evms_md_recovery_thread = NULL; - -/* - * Enables to iterate over all existing md arrays - */ -static LIST_HEAD(all_mddevs); -static LIST_HEAD(incomplete_mddevs); -static LIST_HEAD(running_mddevs); - -/* - * The mapping between kdev and mddev is not necessary a simple - * one! Eg. HSM uses several sub-devices to implement Logical - * Volumes. All these sub-devices map to the same mddev. - */ -struct dev_mapping evms_mddev_map[MAX_MD_DEVS]; - - -/* Support functions for discovery */ -static mdk_rdev_t * evms_md_find_rdev_all (struct evms_logical_node *node); -static mddev_t * evms_md_find_mddev_all (struct evms_logical_node *node); -static int evms_md_import_device (struct evms_logical_node **discover_list, - struct evms_logical_node *node); -static void evms_md_autostart_arrays(struct evms_logical_node **discover_list); -static void evms_md_run_devices (struct evms_logical_node **discover_list); -static int evms_md_run_array (struct evms_logical_node ** discover_list, - mddev_t *mddev); -static void evms_md_run_incomplete_array (struct evms_logical_node ** discover_list, - mddev_t *mddev); -static int evms_md_create_logical_node(struct evms_logical_node **discover_list, - mddev_t *mddev, uint flags); -static int evms_md_read_disk_sb (mdk_rdev_t * rdev); -static int evms_md_analyze_sbs (mddev_t * mddev); -static mddev_t * alloc_mddev (kdev_t dev); -static void free_mddev(mddev_t * mddev); -static void evms_md_create_recovery_thread(void); -static void evms_md_destroy_recovery_thread(void); -static int do_md_run (mddev_t * mddev); -static int do_md_stop (mddev_t * mddev, int ro); - -static void evms_md_export_rdev (mdk_rdev_t * rdev, int delete_node); -static void kick_rdev_from_array (mdk_rdev_t * rdev); -static mdp_disk_t *evms_md_find_disk(mddev_t *mddev, kdev_t dev); -static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb); - -/* Plugin API prototypes */ -static int md_discover( struct evms_logical_node ** discover_list ); -static int md_end_discover( struct evms_logical_node ** discover_list ); -static int md_delete( struct evms_logical_node * node); -static void md_read( struct evms_logical_node * node, - struct buffer_head * bh); -static void md_write( struct evms_logical_node * node, - struct buffer_head * bh); -static int md_sync_io( struct evms_logical_node *node, - int rw, - u64 sect_nr, - u64 num_sects, - void *data); -static int md_ioctl( struct evms_logical_node *node, - struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg); -static int md_ioctl_cmd_broadcast( - struct evms_logical_node *node, - struct inode *inode, - struct file *file, - unsigned long cmd, - unsigned long arg); - -static int md_direct_ioctl( - struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg); - -/* global MD data structures */ -static struct evms_plugin_fops md_fops = { - .discover = md_discover, - .end_discover = md_end_discover, - .delete = md_delete, - .read = md_read, - .write = md_write, - .init_io = md_sync_io, - .ioctl = md_ioctl, - .direct_ioctl = md_direct_ioctl -}; - -static struct evms_plugin_header md_plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_REGION_MANAGER, - EVMS_MD_ID), - .version = { - .major = EVMS_MD_MAJOR_VERSION, - .minor = EVMS_MD_MINOR_VERSION, - .patchlevel = EVMS_MD_PATCHLEVEL_VERSION - }, - .required_services_version = { - .major = EVMS_MD_COMMON_SERVICES_MAJOR, - .minor = EVMS_MD_COMMON_SERVICES_MINOR, - .patchlevel = EVMS_MD_COMMON_SERVICES_PATCHLEVEL - }, - .fops = &md_fops -}; - -/* global variables */ -static int exported_nodes; /* total # of exported devices - * produced during this discovery. - */ -static struct evms_logical_node **cur_discover_list = NULL; - -/**********************************************************/ -/* SYSCTL - EVMS/RAID folder */ -/**********************************************************/ - -#ifdef CONFIG_PROC_FS -static struct ctl_table_header *md_table_header; - -static ctl_table md_table[] = { - {DEV_EVMS_MD_SPEED_LIMIT_MIN, "speed_limit_min", - &sysctl_speed_limit_min, sizeof(int), 0644, NULL, &proc_dointvec}, - {DEV_EVMS_MD_SPEED_LIMIT_MAX, "speed_limit_max", - &sysctl_speed_limit_max, sizeof(int), 0644, NULL, &proc_dointvec}, - {0} -}; - -static ctl_table md_dir_table[] = { - {DEV_EVMS_MD, "md", NULL, 0, 0555, md_table}, - {0} -}; - -static ctl_table evms_dir_table[] = { - {DEV_EVMS, "evms", NULL, 0, 0555, md_dir_table}, - {0} -}; - -static ctl_table dev_dir_table[] = { - {CTL_DEV, "dev", NULL, 0, 0555, evms_dir_table}, - {0} -}; -#endif -/********** Required EVMS Plugin Functions **********/ - -/* - * Function: md_discover - * We should only export complete MD device nodes - */ -static int md_discover( struct evms_logical_node ** discover_list ) -{ - MOD_INC_USE_COUNT; - LOG_ENTRY_EXIT("%s: ENTRY\n", __FUNCTION__); - - /* initialize global variable */ - exported_nodes = 0; - cur_discover_list = discover_list; - evms_md_autostart_arrays(discover_list); - - LOG_ENTRY_EXIT("%s: EXIT (exported nodes: %d)\n", __FUNCTION__,exported_nodes); - cur_discover_list = NULL; - MOD_DEC_USE_COUNT; - return(exported_nodes); -} - -static mddev_t * evms_md_find_incomplete_array(int level) -{ - mddev_t *mddev; - struct list_head *tmp,*tmp2; - mdk_rdev_t *rdev; - - ITERATE_INCOMPLETE_MDDEV(mddev,tmp) { - ITERATE_RDEV(mddev, rdev, tmp2) { - if (rdev->sb && rdev->sb->level == level) - return mddev; - } - } - return NULL; -} - -/* - * Function: md_end_discover - */ -static int md_end_discover( struct evms_logical_node ** discover_list ) -{ - int rc = 0; - struct list_head *tmp; - mdk_rdev_t *rdev; - mddev_t *mddev; - struct evms_logical_node *node; - int done = FALSE; - - MOD_INC_USE_COUNT; - LOG_ENTRY_EXIT("%s: ENTRY\n", __FUNCTION__); - rc = md_discover(discover_list); - - do { - done = TRUE; - if ( (mddev = evms_md_find_incomplete_array(5)) != NULL) { - evms_md_run_incomplete_array(discover_list, mddev); - done = FALSE; - continue; - } - if ( (mddev = evms_md_find_incomplete_array(1)) != NULL) { - evms_md_run_incomplete_array(discover_list, mddev); - done = FALSE; - continue; - } - if ( (mddev = evms_md_find_incomplete_array(0)) != NULL) { - evms_md_run_incomplete_array(discover_list, mddev); - done = FALSE; - continue; - } - if ( (mddev = evms_md_find_incomplete_array(-1)) != NULL) { - evms_md_run_incomplete_array(discover_list, mddev); - done = FALSE; - continue; - } - - } while (!done); - - - /* - * At this point, delete all mddevs which did not start. - */ - ITERATE_MDDEV(mddev,tmp) { - if (mddev->pers == NULL) { - LOG_WARNING("%s: deleting md%d\n", __FUNCTION__, mdidx(mddev)); - free_mddev(mddev); - } - } - - - /* - * At this point, delete all rdevs which do not belong to any of discovered MD arrays. - */ - ITERATE_RDEV_ALL(rdev, tmp) { - if (!rdev->mddev) { - node = rdev->node; - if (node) { - if (node->plugin->id == md_plugin_header.id) - evms_md_export_rdev(rdev, FALSE); - else - evms_md_export_rdev(rdev, TRUE); - } - } - } - - LOG_ENTRY_EXIT("%s: EXIT\n", __FUNCTION__); - MOD_DEC_USE_COUNT; - return rc; -} - - -/* - * Function: md_delete_node - */ -static int md_delete( struct evms_logical_node * node) -{ - struct evms_md *evms_md; - mddev_t *mddev; - - evms_md = node->private; - mddev = evms_md->mddev; - LOG_DEFAULT("md_delete() [%s]\n", evms_md_partition_name(node)); - - if (mddev) - do_md_stop(mddev,0); - if (evms_md) { - if (evms_md->instance_plugin_hdr.fops) - kfree(evms_md->instance_plugin_hdr.fops); - kfree(evms_md); - } - - evms_cs_deallocate_logical_node(node); - return 0; -} - - -/* - * Function: md_read - */ -static void md_read( struct evms_logical_node * node, - struct buffer_head * bh) -{ - struct evms_md *evms_md; - mddev_t *mddev; - - evms_md = node->private; - mddev = evms_md->mddev; - if (evms_md_check_boundary(node, bh)) return; - if (mddev && mddev->pers) - mddev->pers->read(node, bh); -} - - -/* - * Function: md_write - */ -static void md_write( struct evms_logical_node * node, - struct buffer_head * bh) -{ - struct evms_md *evms_md; - mddev_t *mddev; - - evms_md = node->private; - mddev = evms_md->mddev; - if (evms_md_check_boundary(node, bh)) return; - if (mddev->ro) { - LOG_ERROR("%s: read-only is set for [%s]\n", __FUNCTION__, node->name); - bh->b_end_io(bh, 0); - return; - } - if (mddev && mddev->pers) - mddev->pers->write(node, bh); -} - -/* - * Function: md_sync_io - */ -static int md_sync_io( - struct evms_logical_node *node, - int rw, - u64 sect_nr, - u64 num_sects, - void *buf_addr) -{ - struct evms_md *evms_md; - mddev_t *mddev; - int rc = 0; - - evms_md = node->private; - mddev = evms_md->mddev; - - if (sect_nr + num_sects > node->total_vsectors) { - LOG_ERROR("%s: attempt to %s beyond MD device(%s) boundary("PFU64") with sect_nr("PFU64") and num_sects("PFU64")\n", - __FUNCTION__, - rw ? "WRITE" : "READ", - node->name, - node->total_vsectors, - sect_nr,num_sects); - rc = -EINVAL; - } - - if ((mddev->ro) && (rw != READ)) { - LOG_ERROR("%s: read-only is set for [%s]\n", __FUNCTION__, node->name); - return -EINVAL; - } - - if (!rc && mddev && mddev->pers) { - /* - * Check if the personality can handle synchronous I/O, - * otherwise use the generic function. - */ - if (mddev->pers->sync_io) - rc = mddev->pers->sync_io(mddev, rw, sect_nr, num_sects, buf_addr); - else - rc = evms_md_sync_io(node, rw, sect_nr, num_sects, buf_addr); - } else - rc = -EINVAL; - return rc; -} - -/** - * md_end_sync_request - End IO handler for synchronous I/O functions - **/ -static void md_end_sync_request(struct buffer_head *bh, int uptodate) -{ - struct evms_md_sync_cb * cb = (struct evms_md_sync_cb *) bh->b_private; - - if (!uptodate) - cb->rc |= -EIO; - /* we are done with the bh */ - evms_cs_deallocate_to_pool(evms_bh_pool, bh); - - if (atomic_dec_and_test(&cb->io_count)) { - if (waitqueue_active(&cb->wait)) - wake_up(&cb->wait); - } -} - -/** - * md_sync_request_submit_bh - submit a page-size bh - * @node - target MD node - * @bh - pointer to the buffer head - * @sector - the sector number - * @data - pointer to buffer - * @rw - READ/WRITE - * @cb - MD synchronous I/O control block - **/ -static inline void md_sync_request_submit_bh( - struct evms_logical_node *node, - struct buffer_head *bh, - unsigned long sector, - char *data, - int rw, - struct evms_md_sync_cb *cb) -{ - - bh->b_this_page = (struct buffer_head *)1; - bh->b_rsector = sector; - bh->b_size = PAGE_SIZE; - bh->b_state = 0; - set_bit(BH_Dirty, &bh->b_state); - set_bit(BH_Lock, &bh->b_state); - set_bit(BH_Req, &bh->b_state); - set_bit(BH_Mapped, &bh->b_state); - atomic_set(&bh->b_count, 1); - bh->b_data = data; - bh->b_page = virt_to_page(data); - bh->b_list = BUF_LOCKED; - bh->b_end_io = md_end_sync_request; - bh->b_private = cb; - atomic_inc(&cb->io_count); - if (rw == READ) - R_IO(node,bh); - else - W_IO(node,bh); -} - -/** - * evms_md_allocate_bh - * - * Note that this function will not return unless we got a free bh - **/ -static inline struct buffer_head *evms_md_allocate_bh(void) -{ - struct buffer_head *bh; - - while ((bh = evms_cs_allocate_from_pool(evms_bh_pool, FALSE)) == NULL) - schedule(); /* just yield for a someone to deallocate a bh */ - init_waitqueue_head(&bh->b_wait); - atomic_set(&bh->b_count, 0); - return(bh); -} - -/** - * md_partial_sync_io - - * This function handles synchronous I/O when sector is not page aligned - * @node - evms node for the MD array - * @rw - READ/WRITE - * @sector - the sector - * @nsects - on input, the total sectors for the request - * @nsects - on output, number of sectors completed - * @data - data buffer - **/ -int evms_md_partial_sync_io( - struct evms_logical_node *node, - int rw, - u64 sector, - u32 *nsects, - void *data) -{ - int rc; - u32 offset, size; - struct buffer_head *bh; - struct evms_md_sync_cb cb; - char *page; - - size = (u32)(*nsects << EVMS_VSECTOR_SIZE_SHIFT); - - /* calculate byte offset */ - offset = (u32)((sector & (EVMS_MD_SECTS_PER_PAGE-1)) << EVMS_VSECTOR_SIZE_SHIFT); - if (!offset && (*nsects >= EVMS_MD_SECTS_PER_PAGE)) { - *nsects = 0; - return 0; /* Nothing to do */ - } - - page = NULL; - rc = 0; - - page = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!page) { - LOG_ERROR("%s: no memory!\n", __FUNCTION__); - rc = -ENOMEM; - } - - bh = evms_md_allocate_bh(); - - if (!rc) { - memset(&cb, 0, sizeof(cb)); - init_waitqueue_head(&cb.wait); - atomic_set(&cb.io_count, 0); - md_sync_request_submit_bh( - node, bh, - (unsigned long)(sector & EVMS_MD_SECTS_PER_PAGE_MASK), - page, READ, &cb); - wait_disk_event(cb.wait, !atomic_read(&cb.io_count)); - rc |= cb.rc; - } - - if (!rc) { - size = (size <= (PAGE_SIZE - offset)) ? size : (PAGE_SIZE - offset); - - switch (rw) { - case READ: - /* copy data and return */ - memcpy(data, page+offset, size); - break; - case WRITE: - /* copy data and then write */ - memcpy(page+offset, data, size); - - bh = evms_md_allocate_bh(); - - md_sync_request_submit_bh( - node, bh, - (unsigned long)(sector & EVMS_MD_SECTS_PER_PAGE_MASK), - page, WRITE, &cb); - wait_disk_event(cb.wait, !atomic_read(&cb.io_count)); - rc |= cb.rc; - break; - default: - rc = -EINVAL; - } - } - - if (page) - kfree(page); - - if (!rc) - *nsects = (u64)(size >> EVMS_VSECTOR_SIZE_SHIFT); - else - *nsects = 0; - return rc; -} - -/** - * evms_md_sync_io - This function handles synchronous I/O - **/ -int evms_md_sync_io( - struct evms_logical_node *node, - int rw, - u64 sector, - u64 total_nr_sects, - void *data ) -{ - int rc = 0; - u64 total_nr_pages, size; - u32 nsects; - struct buffer_head *bh; - struct evms_md_sync_cb cb; - - if (sector % EVMS_MD_SECTS_PER_PAGE) { - nsects = total_nr_sects; - rc = evms_md_partial_sync_io(node, rw, sector, &nsects, data); - if (!rc) { - total_nr_sects -= nsects; - sector += nsects; - data += (nsects << EVMS_VSECTOR_SIZE_SHIFT); - if (total_nr_sects == 0) - return rc; - } else { - return rc; - } - } - - total_nr_pages = total_nr_sects / EVMS_MD_SECTS_PER_PAGE; - size = total_nr_sects << EVMS_VSECTOR_SIZE_SHIFT; - - memset(&cb, 0, sizeof(cb)); - init_waitqueue_head(&cb.wait); - atomic_set(&cb.io_count, 0); - - while (!rc && total_nr_pages) { - - bh = evms_md_allocate_bh(); - - md_sync_request_submit_bh(node, bh,(unsigned long)sector, data, rw, &cb); - - sector += EVMS_MD_SECTS_PER_PAGE; - size -= PAGE_SIZE; - total_nr_pages--; - data += PAGE_SIZE; - } - if (!rc) { - wait_disk_event(cb.wait, !atomic_read(&cb.io_count)); - rc |= cb.rc; - } - - if (!rc && size) { - nsects = size >> EVMS_VSECTOR_SIZE_SHIFT; - rc = evms_md_partial_sync_io(node, rw, sector, &nsects, data); - } - - return(rc); -} - -/* - * Function: md_ioctl - */ -static int md_ioctl( - struct evms_logical_node * node, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct evms_md * evms_md = node->private; - mddev_t *mddev; - int rc = 0; - - if ((!inode) || (!evms_md) ) - rc = -EINVAL; - - if (!rc) { - switch (cmd) { - /* - * We have a problem here : there is no easy way to give a CHS - * virtual geometry. We currently pretend that we have a 2 heads - * 4 sectors (with a BIG number of cylinders...). This drives - * dosfs just mad... ;-) - */ - - case HDIO_GETGEO: - { - struct hd_geometry hdgeo; - hdgeo.heads = 2; - hdgeo.sectors = 4; - hdgeo.cylinders = ((unsigned int)node->total_vsectors) / - hdgeo.heads / hdgeo.sectors; - hdgeo.start = 0; - if (copy_to_user((int *)arg, - &hdgeo, - sizeof(hdgeo))) - rc = -EFAULT; - } - break; - case EVMS_QUIESCE_VOLUME: - case EVMS_GET_DISK_LIST: - case EVMS_CHECK_MEDIA_CHANGE: - case EVMS_REVALIDATE_DISK: - case EVMS_OPEN_VOLUME: - case EVMS_CLOSE_VOLUME: - case EVMS_CHECK_DEVICE_STATUS: - rc = md_ioctl_cmd_broadcast( - node, inode, file, cmd, arg); - break; - case EVMS_PLUGIN_IOCTL: - rc = md_direct_ioctl( - inode, file, cmd, arg); - break; - default: - mddev = evms_md->mddev; - if (mddev == NULL) { - rc = -ENODEV; - } else if (mddev->pers->evms_ioctl == NULL) { - rc = -ENOSYS; - } else { - rc = mddev->pers->evms_ioctl(mddev, inode, file, cmd, arg); - } - } - } - return(rc); -} - -static int md_ioctl_cmd_broadcast( - struct evms_logical_node *node, - struct inode *inode, - struct file *file, - unsigned long cmd, - unsigned long arg) -{ - int rc = 0; - struct evms_md *evms_md; - mddev_t *mddev; - struct list_head *tmp; - mdk_rdev_t *rdev; - - evms_md = node->private; - mddev = evms_md->mddev; - - /* broadcast this cmd to all children */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (!rdev->mddev) { - MD_BUG(); - continue; - } - if (!rdev->virtual_spare) { - rc |= IOCTL(rdev->node, inode, file, cmd, arg); - } - } - return (rc); -} - - -static int evms_md_add_virtual_spare (mddev_t *mddev, kdev_t dev) -{ - mdk_rdev_t *rdev; - mdp_disk_t *disk = NULL; - int i; - - if (evms_md_find_rdev(mddev,dev)) - return -EEXIST; - - LOG_ENTRY_EXIT("%s ENTRY\n", __FUNCTION__); - if ((rdev = kmalloc(sizeof(*rdev),GFP_KERNEL)) == NULL) - return -ENOMEM; - - memset(rdev, 0, sizeof(*rdev)); - - for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { - disk = mddev->sb->disks + i; - if (!disk->major && !disk->minor) - break; - if (disk_removed(disk)) - break; - } - if (i == MD_SB_DISKS) { - LOG_WARNING("%s : [md%d]can not hot-add to full array!\n", __FUNCTION__, mdidx(mddev)); - kfree(rdev); - return -EBUSY; - } - - if (disk_removed(disk)) { - /* - * reuse slot - */ - if (disk->number != i) { - MD_BUG(); - kfree(rdev); - return -EINVAL; - } - } else { - disk->number = i; - } - - disk->raid_disk = disk->number; - disk->major = MAJOR(dev); - disk->minor = MINOR(dev); - - mark_disk_spare(disk); - - rdev->mddev = mddev; - rdev->dev = dev; - rdev->desc_nr = disk->number; - rdev->virtual_spare = 1; - - /* bind rdev to mddev array */ - list_add(&rdev->all, &all_raid_disks); - list_add(&rdev->same_set, &mddev->disks); - MD_INIT_LIST_HEAD(&rdev->pending); - - mddev->sb->nr_disks++; - mddev->sb->spare_disks++; - mddev->sb->working_disks++; - mddev->nb_dev++; - - mddev->sb_dirty = 1; - - evms_md_update_sb(mddev); - - return 0; -} - -static int evms_md_remove_disk(mddev_t *mddev, kdev_t dev) -{ - mdk_rdev_t *rdev = NULL; - mdp_disk_t *disk; - int rc = 0; - - disk = evms_md_find_disk(mddev,dev); - if (!disk) - return -ENODEV; - - rdev = evms_md_find_rdev(mddev,dev); - - if (rdev && !rdev->faulty) { - /* - * The disk is active in the array, - * must ask the personality to do it - */ - if (mddev->pers && mddev->pers->diskop) { - /* Assume spare, try to remove it first. */ - rc = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_SPARE); - if (rc) - rc = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); - } else - rc = -ENOSYS; - } - - if (!rc) { - remove_descriptor(disk,mddev->sb); - if (rdev) - kick_rdev_from_array(rdev); - mddev->sb_dirty = 1; - evms_md_update_sb(mddev); - - } - return rc; -} - - -/* - * Function: md_direct_ioctl - * - * This function provides a method for user-space to communicate directly - * with a plugin in the kernel. - */ -static int md_direct_ioctl( - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long args ) -{ - struct evms_plugin_ioctl_pkt argument; - kdev_t md_kdev; - mddev_t *mddev = NULL; - struct evms_md_ioctl ioctl_arg; - struct evms_md_kdev device; - struct evms_md_array_info array_info, *usr_array_info; - int rc = 0; - - MOD_INC_USE_COUNT; - - // Copy user's parameters to kernel space - if ( copy_from_user(&argument, (struct evms_plugin_ioctl_pkt*)args, sizeof(argument)) ) { - MOD_DEC_USE_COUNT; - return -EFAULT; - } - - // Make sure this is supposed to be our ioctl. - if ( argument.feature_id != md_plugin_header.id ) { - MOD_DEC_USE_COUNT; - return -EINVAL; - } - - // Copy user's md ioclt parmeters to kernel space - if ( copy_from_user(&ioctl_arg, - (struct evms_md_ioctl*)argument.feature_ioctl_data, - sizeof(ioctl_arg)) ) - rc = -EFAULT; - else { - if (ioctl_arg.mddev_idx < MAX_MD_DEVS) { - md_kdev = MKDEV(MD_MAJOR, ioctl_arg.mddev_idx); - mddev = kdev_to_mddev(md_kdev); - if (mddev == NULL) - rc = -ENODEV; - } else - rc = -ENODEV; - } - - if (!rc) { - switch(argument.feature_command) { - case EVMS_MD_PERS_IOCTL_CMD: - if (mddev->pers->md_pers_ioctl == NULL) { - MOD_DEC_USE_COUNT; - return -ENOSYS; - } - rc = mddev->pers->md_pers_ioctl(mddev, - ioctl_arg.cmd, - ioctl_arg.arg); - copy_to_user((struct evms_md_ioctl*)argument.feature_ioctl_data, - &ioctl_arg, - sizeof(ioctl_arg)); - break; - - case EVMS_MD_ADD: - if ( copy_from_user(&device, - (struct evms_md_kdev *)ioctl_arg.arg, - sizeof(device)) ) - rc = -EFAULT; - else - rc = evms_md_add_virtual_spare(mddev,MKDEV(device.major, device.minor)); - break; - - case EVMS_MD_REMOVE: - if ( copy_from_user(&device, - (struct evms_md_kdev *)ioctl_arg.arg, - sizeof(device)) ) - rc = -EFAULT; - else - rc = evms_md_remove_disk(mddev,MKDEV(device.major, device.minor)); - break; - - case EVMS_MD_ACTIVATE: - rc = -ENOSYS; - break; - - case EVMS_MD_DEACTIVATE: - rc = -ENOSYS; - break; - - case EVMS_MD_GET_ARRAY_INFO: - - usr_array_info = (struct evms_md_array_info *)ioctl_arg.arg; - if ( copy_from_user(&array_info, usr_array_info, - sizeof(array_info)) ) - rc = -EFAULT; - else { - array_info.state = 0; - if (mddev->curr_resync) - array_info.state |= EVMS_MD_ARRAY_SYNCING; - copy_to_user(&usr_array_info->state, &array_info.state, - sizeof(usr_array_info->state)); - if (copy_to_user(array_info.sb, mddev->sb, - sizeof(mdp_super_t))) - rc = -EFAULT; - } - break; - default: - rc = -ENOSYS; - break; - } - } - - argument.status = rc; - copy_to_user((struct evms_plugin_ioctl_pkt*)args, &argument, sizeof(argument)); - MOD_DEC_USE_COUNT; - return rc; -} - - - - -void evms_md_add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data) -{ - unsigned int minor = MINOR(dev); - - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return; - } - if (evms_mddev_map[minor].mddev != NULL) { - MD_BUG(); - return; - } - evms_mddev_map[minor].mddev = mddev; - evms_mddev_map[minor].data = data; -} - -void evms_md_del_mddev_mapping (mddev_t * mddev, kdev_t dev) -{ - unsigned int minor = MINOR(dev); - - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return; - } - if (evms_mddev_map[minor].mddev != mddev) { - MD_BUG(); - return; - } - evms_mddev_map[minor].mddev = NULL; - evms_mddev_map[minor].data = NULL; -} - -static mddev_t * alloc_mddev (kdev_t dev) -{ - mddev_t *mddev; - - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return 0; - } - mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); - if (!mddev) - return NULL; - - memset(mddev, 0, sizeof(*mddev)); - - mddev->__minor = MINOR(dev); - init_MUTEX(&mddev->reconfig_sem); - init_MUTEX(&mddev->recovery_sem); - init_MUTEX(&mddev->resync_sem); - INIT_LIST_HEAD(&mddev->disks); - INIT_LIST_HEAD(&mddev->all_mddevs); - INIT_LIST_HEAD(&mddev->incomplete_mddevs); - INIT_LIST_HEAD(&mddev->running_mddevs); - atomic_set(&mddev->active, 0); - atomic_set(&mddev->recovery_active, 0); - - /* - * The 'base' mddev is the one with data NULL. - * personalities can create additional mddevs - * if necessary. - */ - evms_md_add_mddev_mapping(mddev, dev, 0); - list_add(&mddev->all_mddevs, &all_mddevs); - - MOD_INC_USE_COUNT; - evms_md_create_recovery_thread(); - - return mddev; -} - -mdk_rdev_t * evms_md_find_rdev_nr(mddev_t *mddev, int nr) -{ - mdk_rdev_t * rdev; - struct list_head *tmp; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == nr) - return rdev; - } - return NULL; -} - - -mdk_rdev_t * evms_md_find_rdev(mddev_t * mddev, kdev_t dev) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->dev == dev) - return rdev; - } - return NULL; -} - -mdk_rdev_t * evms_md_find_rdev_from_node(mddev_t * mddev, struct evms_logical_node * node) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->node == node) - return rdev; - } - return NULL; -} - -static MD_LIST_HEAD(device_names); - -static char * org_partition_name (kdev_t dev) -{ - struct gendisk *hd; - static char nomem [] = ""; - dev_name_t *dname; - struct list_head *tmp = device_names.next; - - while (tmp != &device_names) { - dname = list_entry(tmp, dev_name_t, list); - if (dname->dev == dev) - return dname->name; - tmp = tmp->next; - } - - dname = (dev_name_t *) kmalloc(sizeof(*dname), GFP_KERNEL); - - if (!dname) - return nomem; - /* - * ok, add this new device name to the list - */ - hd = get_gendisk (dev); - dname->name = NULL; - if (hd) - dname->name = disk_name (hd, MINOR(dev), dname->namebuf); - if (!dname->name) { - sprintf (dname->namebuf, "[dev %s]", kdevname(dev)); - dname->name = dname->namebuf; - } - - dname->dev = dev; - MD_INIT_LIST_HEAD(&dname->list); - list_add(&dname->list, &device_names); - - return dname->name; -} - - -#define EVMS_MD_NULL_PARTITION_NAME "" -char * evms_md_partition_name (struct evms_logical_node *node) -{ - if (node && node->name) - return node->name; - else - return EVMS_MD_NULL_PARTITION_NAME; -} - -static char * get_partition_name (mdk_rdev_t *rdev) -{ - if (rdev->node) - return evms_md_partition_name(rdev->node); - else - return org_partition_name(rdev->dev); -} - -/* - * Function: evms_md_calc_dev_sboffset - * return the LSN for md super block. - */ -static u64 evms_md_calc_dev_sboffset (struct evms_logical_node *node,mddev_t *mddev, int persistent) -{ - u64 size = 0; - - size = node->total_vsectors; - if (persistent) { - size = MD_NEW_SIZE_SECTORS(size); - } - return size; /* size in sectors */ -} - -/* - * Function: evms_md_calc_dev_size - * return data size (in blocks) for an "extended" device. - */ -static unsigned long evms_md_calc_dev_size (struct evms_logical_node *node, - mddev_t *mddev, - int persistent) -{ - unsigned long size; - u64 size_in_sectors; - - size_in_sectors = evms_md_calc_dev_sboffset(node, mddev, persistent); - size = size_in_sectors >> 1; - if (!mddev->sb) { - MD_BUG(); - return size; - } - if (mddev->sb->chunk_size) - size &= ~(mddev->sb->chunk_size/1024 - 1); - return size; -} - -static unsigned int zoned_raid_size (mddev_t *mddev) -{ - unsigned int mask; - mdk_rdev_t * rdev; - struct list_head *tmp; - - if (!mddev->sb) { - MD_BUG(); - return -EINVAL; - } - /* - * do size and offset calculations. - */ - mask = ~(mddev->sb->chunk_size/1024 - 1); - - ITERATE_RDEV(mddev,rdev,tmp) { - rdev->size &= mask; - evms_md_size[mdidx(mddev)] += rdev->size; - } - return 0; -} - -/* - * We check wether all devices are numbered from 0 to nb_dev-1. The - * order is guaranteed even after device name changes. - * - * Some personalities (raid0, linear) use this. Personalities that - * provide data have to be able to deal with loss of individual - * disks, so they do their checking themselves. - */ -int evms_md_check_ordering (mddev_t *mddev) -{ - int i, c; - mdk_rdev_t *rdev; - struct list_head *tmp; - - /* - * First, all devices must be fully functional - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) { - LOG_ERROR("evms_md_check_ordering() md%d's device %s faulty, aborting.\n", - mdidx(mddev), get_partition_name(rdev)); - goto abort; - } - } - - c = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - c++; - } - if (c != mddev->nb_dev) { - MD_BUG(); - goto abort; - } - if (mddev->nb_dev != mddev->sb->raid_disks) { - LOG_ERROR("%s: [md%d] array needs %d disks, has %d, aborting.\n", - __FUNCTION__, mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev); - goto abort; - } - /* - * Now the numbering check - */ - for (i = 0; i < mddev->nb_dev; i++) { - c = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == i) - c++; - } - if (!c) { - LOG_ERROR("md%d, missing disk #%d, aborting.\n",mdidx(mddev), i); - goto abort; - } - if (c > 1) { - LOG_ERROR("md%d, too many disks #%d, aborting.\n",mdidx(mddev), i); - goto abort; - } - } - return 0; -abort: - return 1; -} - -static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) -{ - if (disk_active(disk)) { - sb->working_disks--; - } else { - if (disk_spare(disk)) { - sb->spare_disks--; - sb->working_disks--; - } else { - sb->failed_disks--; - } - } - sb->nr_disks--; - disk->major = disk->minor = 0; - mark_disk_removed(disk); -} - -#define BAD_MINOR \ -"%s: invalid raid minor (%x)\n" - -#define NO_SB \ -"disabled device %s, could not read superblock.\n" - -#define BAD_CSUM \ -"invalid superblock checksum on %s\n" - - -static int alloc_array_sb (mddev_t * mddev) -{ - if (mddev->sb) { - MD_BUG(); - return 0; - } - - mddev->sb = (mdp_super_t *) __get_free_page (GFP_KERNEL); - if (!mddev->sb) { - LOG_ERROR("%s: Out of memory!\n", __FUNCTION__); - return -ENOMEM; - } - md_clear_page(mddev->sb); - return 0; -} - -static int alloc_disk_sb (mdk_rdev_t * rdev) -{ - if (rdev->sb) - MD_BUG(); - - rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL); - if (!rdev->sb) { - LOG_ERROR("%s: Out of memory!\n", __FUNCTION__); - return -EINVAL; - } - md_clear_page(rdev->sb); - - return 0; -} - -/* - * Function: free_disk_sb - * - */ -static void free_disk_sb (mdk_rdev_t * rdev) -{ - if (rdev->sb) { - free_page((unsigned long) rdev->sb); - rdev->sb = NULL; - rdev->sb_offset = 0; - rdev->size = 0; - } else { - if (!rdev->virtual_spare && !rdev->faulty) - MD_BUG(); - } -} - -/* - * Function: evms_md_read_disk_sb - * Read the MD superblock. - */ -static int evms_md_read_disk_sb (mdk_rdev_t * rdev) -{ - int rc = 0; - struct evms_logical_node *node = rdev->node; - u64 sb_offset_in_sectors; - - if (!rdev->sb) { - MD_BUG(); - return -EINVAL; - } - if (node->total_vsectors <= MD_RESERVED_SECTORS) { - LOG_DETAILS("%s is too small, total_vsectors("PFU64")\n", - evms_md_partition_name(node), node->total_vsectors); - return -EINVAL; - } - - /* - * Calculate the position of the superblock, - * it's at the end of the disk - */ - sb_offset_in_sectors = evms_md_calc_dev_sboffset(node, rdev->mddev, 1); - rdev->sb_offset = (unsigned long)(sb_offset_in_sectors >> 1); - LOG_DEBUG("(read) %s's sb offset("PFU64") total_vsectors("PFU64")\n", - evms_md_partition_name(node), sb_offset_in_sectors, node->total_vsectors); - - /* - * Read superblock - */ - rc = INIT_IO(node, 0, sb_offset_in_sectors, MD_SB_SECTORS, rdev->sb); - - return rc; -} - -static unsigned int calc_sb_csum (mdp_super_t * sb) -{ - unsigned int disk_csum, csum; - - disk_csum = sb->sb_csum; - sb->sb_csum = 0; - csum = csum_partial((void *)sb, MD_SB_BYTES, 0); - sb->sb_csum = disk_csum; - return csum; -} - - - -/* - * Check one RAID superblock for generic plausibility - */ - -static int check_disk_sb (mdk_rdev_t * rdev) -{ - mdp_super_t *sb; - int ret = -EINVAL; - - sb = rdev->sb; - if (!sb) { - MD_BUG(); - goto abort; - } - - if (sb->md_magic != MD_SB_MAGIC) { - goto abort; - } - - if (sb->md_minor >= MAX_MD_DEVS) { - LOG_ERROR(BAD_MINOR, get_partition_name(rdev), sb->md_minor); - goto abort; - } - if (calc_sb_csum(sb) != sb->sb_csum) { - LOG_ERROR(BAD_CSUM, get_partition_name(rdev)); - goto abort; - } - - switch (sb->level) { - case -1: - case 0: - case 1: - case 5: - break; - default: - LOG_ERROR("%s: EVMS MD does not support MD level %d\n", __FUNCTION__, sb->level); - goto abort; - } - ret = 0; -abort: - return ret; -} - -static kdev_t dev_unit(kdev_t dev) -{ - unsigned int mask; - struct gendisk *hd = get_gendisk(dev); - - if (!hd) - return 0; - mask = ~((1 << hd->minor_shift) - 1); - - return MKDEV(MAJOR(dev), MINOR(dev) & mask); -} - -static mdk_rdev_t * match_dev_unit(mddev_t *mddev, kdev_t dev) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev,rdev,tmp) - if (dev_unit(rdev->dev) == dev_unit(dev)) - return rdev; - - return NULL; -} - -static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev1,rdev,tmp) - if (match_dev_unit(mddev2, rdev->dev)) - return 1; - - return 0; -} - - -static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) -{ - mdk_rdev_t *same_pdev; - - if (rdev->mddev) { - MD_BUG(); - return; - } - - same_pdev = match_dev_unit(mddev, rdev->dev); - if (same_pdev) - LOG_WARNING("[md%d] WARNING: %s appears to be on the same physical disk as %s. True\n" - " protection against single-disk failure might be compromised.\n", - mdidx(mddev), get_partition_name(rdev),get_partition_name(same_pdev)); - - list_add(&rdev->same_set, &mddev->disks); - rdev->mddev = mddev; - mddev->nb_dev++; - if (rdev->sb && disk_active(&rdev->sb->this_disk)) - mddev->nr_raid_disks++; - LOG_DETAILS("bind<%s,%d>\n", get_partition_name(rdev), rdev->mddev->nb_dev); -} - -static void unbind_rdev_from_array (mdk_rdev_t * rdev) -{ - if (!rdev->mddev) { - MD_BUG(); - return; - } - list_del(&rdev->same_set); - MD_INIT_LIST_HEAD(&rdev->same_set); - rdev->mddev->nb_dev--; - if (rdev->sb && disk_active(&rdev->sb->this_disk)) - rdev->mddev->nr_raid_disks--; - LOG_DETAILS("unbind<%s,%d>\n", get_partition_name(rdev), rdev->mddev->nb_dev); - rdev->mddev = NULL; -} - - -/* - * Function: evms_md_export_rdev - * EVMS MD version of export_rdev() - * Discard this MD "extended" device - */ -static void evms_md_export_rdev (mdk_rdev_t * rdev, int delete_node) -{ - LOG_DETAILS("%s: (%s)\n", __FUNCTION__ , get_partition_name(rdev)); - if (rdev->mddev) - MD_BUG(); - free_disk_sb(rdev); - list_del(&rdev->all); - MD_INIT_LIST_HEAD(&rdev->all); - if (rdev->pending.next != &rdev->pending) { - LOG_WARNING("%s: (%s was pending)\n",__FUNCTION__ ,get_partition_name(rdev)); - list_del(&rdev->pending); - MD_INIT_LIST_HEAD(&rdev->pending); - } - if (rdev->node && delete_node) { - if (cur_discover_list) { - LOG_DETAILS("%s: remove (%s) from discover list.\n", __FUNCTION__, - get_partition_name(rdev)); - evms_cs_remove_logical_node_from_list(cur_discover_list, rdev->node); - } - LOG_DETAILS("%s: deleting node %s\n", __FUNCTION__, get_partition_name(rdev)); - DELETE(rdev->node); - rdev->node = NULL; - } - rdev->dev = 0; - rdev->faulty = 0; - kfree(rdev); -} - - -static void kick_rdev_from_array (mdk_rdev_t * rdev) -{ - LOG_DEFAULT("%s: (%s)\n", __FUNCTION__,get_partition_name(rdev)); - unbind_rdev_from_array(rdev); - evms_md_export_rdev(rdev, TRUE); -} - -static void export_array (mddev_t *mddev) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - mdp_super_t *sb = mddev->sb; - - LOG_DEFAULT("%s: [md%d]\n",__FUNCTION__ ,mdidx(mddev)); - if (mddev->sb) { - mddev->sb = NULL; - free_page((unsigned long) sb); - } - - LOG_DEBUG("%s: removing all extended devices belong to md%d\n",__FUNCTION__,mdidx(mddev)); - ITERATE_RDEV(mddev,rdev,tmp) { - if (!rdev->mddev) { - MD_BUG(); - continue; - } - kick_rdev_from_array(rdev); - } - if (mddev->nb_dev) - MD_BUG(); -} - -static void free_mddev (mddev_t *mddev) -{ - struct evms_logical_node *node; - struct evms_md *evms_md; - - if (!mddev) { - MD_BUG(); - return; - } - - node = mddev->node; - - export_array(mddev); - evms_md_size[mdidx(mddev)] = 0; - - - /* - * Make sure nobody else is using this mddev - * (careful, we rely on the global kernel lock here) - */ - while (atomic_read(&mddev->resync_sem.count) != 1) - schedule(); - while (atomic_read(&mddev->recovery_sem.count) != 1) - schedule(); - - evms_md_del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); - list_del(&mddev->all_mddevs); - INIT_LIST_HEAD(&mddev->all_mddevs); - if (!list_empty(&mddev->running_mddevs)) { - list_del(&mddev->running_mddevs); - INIT_LIST_HEAD(&mddev->running_mddevs); - } - if (!list_empty(&mddev->incomplete_mddevs)) { - list_del(&mddev->incomplete_mddevs); - INIT_LIST_HEAD(&mddev->incomplete_mddevs); - } - - kfree(mddev); - if (node) { - evms_md = node->private; - evms_md->mddev = NULL; - } - MOD_DEC_USE_COUNT; - evms_md_destroy_recovery_thread(); -} - - -static void print_desc(mdp_disk_t *desc) -{ - printk(" DISK\n", desc->number, - desc->raid_disk,desc->state); -} - -static void print_sb(mdp_super_t *sb) -{ - int i; - - printk(" SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", - sb->major_version, sb->minor_version, sb->patch_version, - sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, - sb->ctime); - printk(" L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, - sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, - sb->layout, sb->chunk_size); - printk(" UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%x\n", - sb->utime, sb->state, sb->active_disks, sb->working_disks, - sb->failed_disks, sb->spare_disks, - sb->sb_csum, sb->events_lo); - - for (i = 0; i < MD_SB_DISKS; i++) { - mdp_disk_t *desc; - - desc = sb->disks + i; - if (desc->number || desc->major || desc->minor || desc->raid_disk || (desc->state && (desc->state != 4))) { - printk(" D %2d: ", i); - print_desc(desc); - } - } - printk(" THIS: "); - print_desc(&sb->this_disk); - -} - -static void print_rdev(mdk_rdev_t *rdev) -{ - printk("rdev %s: SZ:%08ld F:%d DN:%d ", - get_partition_name(rdev), - rdev->size, rdev->faulty, rdev->desc_nr); - if (rdev->sb) { - printk("rdev superblock:\n"); - print_sb(rdev->sb); - } else - printk("no rdev superblock!\n"); -} - -void evms_md_print_devices (void) -{ - struct list_head *tmp, *tmp2; - mdk_rdev_t *rdev; - mddev_t *mddev; - - printk("\n"); - printk(": **********************************\n"); - printk(": * *\n"); - printk(": **********************************\n"); - ITERATE_MDDEV(mddev,tmp) { - printk("md%d: ", mdidx(mddev)); - - ITERATE_RDEV(mddev,rdev,tmp2) - printk("<%s>", get_partition_name(rdev)); - - if (mddev->sb) { - printk(" array superblock:\n"); - print_sb(mddev->sb); - } else - printk(" no array superblock.\n"); - - ITERATE_RDEV(mddev,rdev,tmp2) - print_rdev(rdev); - } - printk(": **********************************\n"); - printk("\n"); -} - -static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2) -{ - int ret; - mdp_super_t *tmp1, *tmp2; - - tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL); - tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL); - - if (!tmp1 || !tmp2) { - ret = 0; - printk(KERN_INFO "md.c: sb1 is not equal to sb2!\n"); - goto abort; - } - - *tmp1 = *sb1; - *tmp2 = *sb2; - - /* - * nr_disks is not constant - */ - tmp1->nr_disks = 0; - tmp2->nr_disks = 0; - - if (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4)) - ret = 0; - else - ret = 1; - -abort: - if (tmp1) - kfree(tmp1); - if (tmp2) - kfree(tmp2); - - return ret; -} - -static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) -{ - if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && - (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && - (rdev1->sb->set_uuid2 == rdev2->sb->set_uuid2) && - (rdev1->sb->set_uuid3 == rdev2->sb->set_uuid3)) - - return 1; - - return 0; -} - -/* - * Function: evms_md_find_rdev_all - * EVMS MD version of find_rdev_all() - * Search entire all_raid_disks for "node" - * Return the MD "extended" device if found. - */ -static mdk_rdev_t * evms_md_find_rdev_all (struct evms_logical_node *node) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - - tmp = all_raid_disks.next; - while (tmp != &all_raid_disks) { - rdev = list_entry(tmp, mdk_rdev_t, all); - if (rdev->node == node) - return rdev; - tmp = tmp->next; - } - return NULL; -} - -/* - * Function: evms_md_find_mddev_all - */ -static mddev_t * evms_md_find_mddev_all (struct evms_logical_node *node) -{ - struct list_head *tmp; - mddev_t *mddev; - - ITERATE_MDDEV(mddev,tmp) { - if (mddev->node == node) - return mddev; - } - return NULL; -} - - -/* - * Function: evms_md_write_disk_sb - * EVMS MD version of write_disk_sb - */ -static int evms_md_write_disk_sb(mdk_rdev_t * rdev) -{ - unsigned long size; - u64 sb_offset_in_sectors; - - if (!rdev->sb) { - MD_BUG(); - return 1; - } - if (rdev->faulty) { - MD_BUG(); - return 1; - } - if (rdev->sb->md_magic != MD_SB_MAGIC) { - MD_BUG(); - return 1; - } - - sb_offset_in_sectors = evms_md_calc_dev_sboffset(rdev->node, rdev->mddev, 1); - if (rdev->sb_offset != (sb_offset_in_sectors >> 1)) { - LOG_WARNING("%s's sb offset has changed from blocks(%ld) to blocks(%ld), skipping\n", - get_partition_name(rdev), - rdev->sb_offset, - (unsigned long)(sb_offset_in_sectors >> 1)); - goto skip; - } - /* - * If the disk went offline meanwhile and it's just a spare, then - * its size has changed to zero silently, and the MD code does - * not yet know that it's faulty. - */ - size = evms_md_calc_dev_size(rdev->node, rdev->mddev, 1); - if (size != rdev->size) { - LOG_WARNING("%s's size has changed from %ld to %ld since import, skipping\n", - get_partition_name(rdev), rdev->size, size); - goto skip; - } - - LOG_DETAILS("(write) %s's sb offset: "PFU64"\n",get_partition_name(rdev), sb_offset_in_sectors); - - INIT_IO(rdev->node,WRITE,sb_offset_in_sectors,MD_SB_SECTORS,rdev->sb); - -skip: - return 0; -} - -static int evms_md_sync_sbs(mddev_t * mddev) -{ - mdk_rdev_t *rdev; - struct list_head *tmp; - mdp_disk_t * disk; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->virtual_spare || rdev->faulty) - continue; - - /* copy everything from the master */ - memcpy(rdev->sb, mddev->sb, sizeof(mdp_super_t)); - - /* this_disk is unique, copy it from the master */ -// rdev->sb->this_disk = mddev->sb->disks[rdev->desc_nr]; - // use the SB disk array since if update occurred on normal shutdown - // the rdevs may be out of date. - disk = evms_md_find_disk(mddev, rdev->dev); - if (disk) { - rdev->sb->this_disk = *disk; - } - - rdev->sb->sb_csum = calc_sb_csum(rdev->sb); - } - return 0; -} - -static int evms_md_update_sb_sync(mddev_t * mddev, int clean) -{ - mdk_rdev_t *rdev; - struct list_head *tmp; - int rc = 0; - int found = FALSE; - - ITERATE_RDEV(mddev,rdev,tmp) { - - if (rdev->virtual_spare || rdev->faulty) - continue; - - if ((rc = evms_md_read_disk_sb(rdev))) { - LOG_ERROR("%s: error reading superblock on %s!\n", - __FUNCTION__, evms_md_partition_name(rdev->node)); - break; - } - - if ((rc = check_disk_sb(rdev))) { - LOG_ERROR("%s: %s has invalid sb!\n", - __FUNCTION__, evms_md_partition_name(rdev->node)); - break; - } - - rdev->desc_nr = rdev->sb->this_disk.number; - rdev->dev = MKDEV(rdev->sb->this_disk.major, rdev->sb->this_disk.minor); - - /* copy master superlbock from the first good rdev */ - if (!found) { - found = TRUE; - memcpy(mddev->sb, rdev->sb, sizeof(mdp_super_t)); - if (clean) - mddev->sb->state |= 1 << MD_SB_CLEAN; - else - mddev->sb->state &= ~(1 << MD_SB_CLEAN); - } - } - if (!rc && found) { - evms_md_update_sb(mddev); - } else { - LOG_SERIOUS("%s: BUG! BUG! superblocks will not be updated!\n", __FUNCTION__); - } - return rc; - -} - -int evms_md_update_sb(mddev_t * mddev) -{ - int err, count = 100; - struct list_head *tmp; - mdk_rdev_t *rdev; - - -repeat: - mddev->sb->utime = CURRENT_TIME; - if ((++mddev->sb->events_lo)==0) - ++mddev->sb->events_hi; - - if ((mddev->sb->events_lo|mddev->sb->events_hi)==0) { - /* - * oops, this 64-bit counter should never wrap. - * Either we are in around ~1 trillion A.C., assuming - * 1 reboot per second, or we have a bug: - */ - MD_BUG(); - mddev->sb->events_lo = mddev->sb->events_hi = 0xffffffff; - } - evms_md_sync_sbs(mddev); - - /* - * do not write anything to disk if using - * nonpersistent superblocks - */ - if (mddev->sb->not_persistent) - return 0; - - LOG_DETAILS("%s: updating [md%d] superblock\n",__FUNCTION__ ,mdidx(mddev)); - - err = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (!rdev->virtual_spare && !rdev->faulty) { - LOG_DETAILS(" %s [events: %x]", - get_partition_name(rdev), - rdev->sb->events_lo); - err += evms_md_write_disk_sb(rdev); - } else { - if (rdev->faulty) - LOG_DETAILS(" skipping faulty %s\n", get_partition_name(rdev)); - if (rdev->virtual_spare) - LOG_DETAILS(" skipping virtual spare.\n"); - } - } - if (err) { - if (--count) { - LOG_WARNING("errors occurred during superblock update, repeating\n"); - goto repeat; - } - LOG_ERROR("excessive errors occurred during superblock update, exiting\n"); - } - return 0; -} - -/* - * Function: evms_md_import_device - * Insure that node is not yet imported. - * Read and validate the MD super block on this device - * Add to the global MD "extended" devices list (all_raid_disks) - * - */ -static int evms_md_import_device (struct evms_logical_node **discover_list, - struct evms_logical_node *node) -{ - int err; - mdk_rdev_t *rdev; - - LOG_ENTRY_EXIT("%s: discovering %s\n",__FUNCTION__,evms_md_partition_name(node)); - - if (evms_md_find_rdev_all(node)) { - LOG_DEBUG("%s exists\n", evms_md_partition_name(node)); - return -EEXIST; - } - - rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); - if (!rdev) { - LOG_ERROR("could not alloc mem for %s!\n", evms_md_partition_name(node)); - return -ENOMEM; - } - memset(rdev, 0, sizeof(*rdev)); - - if ((err = alloc_disk_sb(rdev))) - goto abort_free; - - rdev->node = node; /* set this for evms_md_read_disk_sb() */ - - rdev->desc_nr = -1; - rdev->faulty = 0; - - if (!node->total_vsectors) { - LOG_ERROR("%s has zero size!\n", evms_md_partition_name(node)); - err = -EINVAL; - goto abort_free; - } - - if ((err = evms_md_read_disk_sb(rdev))) { - LOG_EXTRA("could not read %s's sb, not importing!\n",evms_md_partition_name(node)); - goto abort_free; - } - if ((err = check_disk_sb(rdev))) { - LOG_EXTRA("%s has invalid sb, not importing!\n",evms_md_partition_name(node)); - goto abort_free; - } - rdev->desc_nr = rdev->sb->this_disk.number; - rdev->dev = MKDEV(rdev->sb->this_disk.major, rdev->sb->this_disk.minor); - LOG_DETAILS("FOUND %s desc_nr(%d)\n", get_partition_name(rdev), rdev->desc_nr); - list_add(&rdev->all, &all_raid_disks); - MD_INIT_LIST_HEAD(&rdev->pending); - - if (rdev->faulty && rdev->sb) - free_disk_sb(rdev); - - return 0; - -abort_free: - if (rdev->sb) { - free_disk_sb(rdev); - } - kfree(rdev); - return err; -} - - - -/* - * Function: evms_md_analyze_sbs - * EVMS MD version of analyze_sbs() - */ -static int evms_md_analyze_sbs (mddev_t * mddev) -{ - int out_of_date = 0, i; - struct list_head *tmp, *tmp2; - mdk_rdev_t *rdev, *rdev2, *freshest; - mdp_super_t *sb; - - LOG_ENTRY_EXIT("Analyzing all superblocks...\n"); - /* - * Verify the RAID superblock on each real device - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) { - MD_BUG(); - goto abort; - } - if (!rdev->sb) { - MD_BUG(); - goto abort; - } - if (check_disk_sb(rdev)) - goto abort; - } - - /* - * The superblock constant part has to be the same - * for all disks in the array. - */ - sb = NULL; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (!sb) { - sb = rdev->sb; - continue; - } - if (!sb_equal(sb, rdev->sb)) { - LOG_WARNING("kick out %s\n",get_partition_name(rdev)); - kick_rdev_from_array(rdev); - continue; - } - } - - /* - * OK, we have all disks and the array is ready to run. Let's - * find the freshest superblock, that one will be the superblock - * that represents the whole array. - */ - if (!mddev->sb) - if (alloc_array_sb(mddev)) - goto abort; - sb = mddev->sb; - freshest = NULL; - - ITERATE_RDEV(mddev,rdev,tmp) { - __u64 ev1, ev2; - /* - * if the checksum is invalid, use the superblock - * only as a last resort. (decrease it's age by - * one event) - */ - if (calc_sb_csum(rdev->sb) != rdev->sb->sb_csum) { - if (rdev->sb->events_lo || rdev->sb->events_hi) - if ((rdev->sb->events_lo--)==0) - rdev->sb->events_hi--; - } - LOG_DETAILS("%s's event counter: %x\n",get_partition_name(rdev), rdev->sb->events_lo); - - if (!freshest) { - freshest = rdev; - continue; - } - /* - * Find the newest superblock version - */ - ev1 = md_event(rdev->sb); - ev2 = md_event(freshest->sb); - if (ev1 != ev2) { - out_of_date = 1; - if (ev1 > ev2) - freshest = rdev; - } - } - if (out_of_date) { - LOG_WARNING("OUT OF DATE, freshest: %s\n",get_partition_name(freshest)); - } - memcpy (sb, freshest->sb, sizeof(*sb)); - - /* - * at this point we have picked the 'best' superblock - * from all available superblocks. - * now we validate this superblock and kick out possibly - * failed disks. - */ - ITERATE_RDEV(mddev,rdev,tmp) { - /* - * Kick all non-fresh devices - */ - __u64 ev1, ev2; - ev1 = md_event(rdev->sb); - ev2 = md_event(sb); - if (ev1 < ev2) { - if (ev1) { - LOG_WARNING("kicking non-fresh %s from array!\n",get_partition_name(rdev)); - kick_rdev_from_array(rdev); - continue; - } else { - LOG_DETAILS("%s is a new spare.\n",get_partition_name(rdev)); - } - } - } - - /* - * Remove unavailable and faulty devices ... - * - * note that if an array becomes completely unrunnable due to - * missing devices, we do not write the superblock back, so the - * administrator has a chance to fix things up. The removal thus - * only happens if it's nonfatal to the contents of the array. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - int found; - mdp_disk_t *desc; - - desc = sb->disks + i; - - /* - * We kick faulty devices/descriptors immediately. - * - * Note: multipath devices are a special case. Since we - * were able to read the superblock on the path, we don't - * care if it was previously marked as faulty, it's up now - * so enable it. - */ - if (disk_faulty(desc) && mddev->sb->level != -4) { - found = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr != desc->number) - continue; - LOG_WARNING("[md%d] kicking faulty %s!\n",mdidx(mddev),get_partition_name(rdev)); - kick_rdev_from_array(rdev); - found = 1; - break; - } - if (!found) { - LOG_WARNING("%s: [md%d] found former faulty device [number=%d]\n", - __FUNCTION__ ,mdidx(mddev), desc->number); - } - /* - * Don't call remove_descriptor(), - * let the administrator remove it from the user-land */ - /* remove_descriptor(desc, sb); */ - continue; - } else if (disk_faulty(desc)) { - /* - * multipath entry marked as faulty, unfaulty it - */ - kdev_t dev; - - dev = MKDEV(desc->major, desc->minor); - - rdev = evms_md_find_rdev(mddev, dev); - if (rdev) - mark_disk_spare(desc); - else { - LOG_WARNING("%s: [md%d] (MULTIPATH) found former faulty device [number=%d]\n", - __FUNCTION__ ,mdidx(mddev), desc->number); - /* - * Don't call remove_descriptor(), - * let the administrator remove it from the user-land */ - /* remove_descriptor(desc, sb); */ - } - } - - /* - * Is this device present in the rdev ring? - */ - found = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - /* - * Multi-path IO special-case: since we have no - * this_disk descriptor at auto-detect time, - * we cannot check rdev->number. - * We can check the device though. - */ - if ((sb->level == -4) && (rdev->dev == - MKDEV(desc->major,desc->minor))) { - found = 1; - break; - } - if (rdev->desc_nr == desc->number) { - found = 1; - break; - } - } - if (found) - continue; - - LOG_WARNING(" [md%d]: former device [number=%d] is unavailable!\n", - mdidx(mddev), desc->number); - remove_descriptor(desc, sb); - } - - /* - * Kick all rdevs that are not in the - * descriptor array: - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == -1) - kick_rdev_from_array(rdev); - } - - /* - * Do a final reality check. - */ - if (mddev->sb->level != -4) { - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == -1) { - MD_BUG(); - goto abort; - } - /* - * is the desc_nr unique? - */ - ITERATE_RDEV(mddev,rdev2,tmp2) { - if ((rdev2 != rdev) && - (rdev2->desc_nr == rdev->desc_nr)) { - MD_BUG(); - goto abort; - } - } - } - } - -#define OLD_VERSION KERN_ALERT \ -"md%d: unsupported raid array version %d.%d.%d\n" - -#define NOT_CLEAN_IGNORE KERN_ERR \ -"md%d: raid array is not clean -- starting background reconstruction\n" - - /* - * Check if we can support this RAID array - */ - if (sb->major_version != MD_MAJOR_VERSION || - sb->minor_version > MD_MINOR_VERSION) { - - LOG_ERROR("[md%d] unsupported raid array version %d.%d.%d\n", - mdidx(mddev), - sb->major_version, - sb->minor_version, - sb->patch_version); - goto abort; - } - - if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || - (sb->level == 4) || (sb->level == 5))) - LOG_WARNING("[md%d, level=%d] raid array is not clean -- starting background reconstruction\n", - mdidx(mddev), sb->level); - - LOG_ENTRY_EXIT("analysis of all superblocks is OK!\n"); - return 0; -abort: - LOG_WARNING("ABORT analyze_sbs()!!!\n"); - return 1; -} - - -static int device_size_calculation (mddev_t * mddev) -{ - int data_disks = 0, persistent; - //unsigned int readahead; - mdp_super_t *sb = mddev->sb; - struct list_head *tmp; - mdk_rdev_t *rdev; - - /* - * Do device size calculation. Bail out if too small. - * (we have to do this after having validated chunk_size, - * because device size has to be modulo chunk_size) - */ - persistent = !mddev->sb->not_persistent; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) - continue; - if (rdev->size) { - LOG_DEFAULT("%s: already calculated %s\n", __FUNCTION__, get_partition_name(rdev)); - continue; - } - rdev->size = evms_md_calc_dev_size(rdev->node, mddev, persistent); - if (rdev->size < sb->chunk_size / 1024) { - LOG_WARNING("Dev %s smaller than chunk_size: %ldk < %dk\n", - get_partition_name(rdev), rdev->size, sb->chunk_size / 1024); - return -EINVAL; - } - } - - switch (sb->level) { - case -4: - data_disks = 1; - break; - case -3: - data_disks = 1; - break; - case -2: - data_disks = 1; - break; - case -1: - zoned_raid_size(mddev); - data_disks = 1; - break; - case 0: - zoned_raid_size(mddev); - data_disks = sb->raid_disks; - break; - case 1: - data_disks = 1; - break; - case 4: - case 5: - data_disks = sb->raid_disks-1; - break; - default: - LOG_ERROR("[md%d] unkown level %d\n", mdidx(mddev), sb->level); - goto abort; - } - if (!evms_md_size[mdidx(mddev)]) - evms_md_size[mdidx(mddev)] = sb->size * data_disks; - - return 0; -abort: - return 1; -} - - -#define TOO_BIG_CHUNKSIZE KERN_ERR \ -"too big chunk_size: %d > %d\n" - -#define TOO_SMALL_CHUNKSIZE KERN_ERR \ -"too small chunk_size: %d < %ld\n" - -#define BAD_CHUNKSIZE KERN_ERR \ -"no chunksize specified, see 'man raidtab'\n" - -static int do_md_run (mddev_t * mddev) -{ - int pnum, err; - int chunk_size; - struct list_head *tmp; - mdk_rdev_t *rdev; - - - if (!mddev->nb_dev) { - MD_BUG(); - return -EINVAL; - } - - if (mddev->pers) - return -EBUSY; - - /* - * Resize disks to align partitions size on a given - * chunk size. - */ - evms_md_size[mdidx(mddev)] = 0; - - /* - * Analyze all RAID superblock(s) - */ - if (evms_md_analyze_sbs(mddev)) { - MD_BUG(); - return -EINVAL; - } - - mddev->chunk_size = chunk_size = mddev->sb->chunk_size; - pnum = level_to_pers(mddev->sb->level); - - if ((pnum != MULTIPATH) && (pnum != RAID1)) { - if (!chunk_size) { - /* - * 'default chunksize' in the old md code used to - * be PAGE_SIZE, baaad. - * we abort here to be on the safe side. We dont - * want to continue the bad practice. - */ - printk(BAD_CHUNKSIZE); - return -EINVAL; - } - if (chunk_size > MAX_CHUNK_SIZE) { - printk(TOO_BIG_CHUNKSIZE, chunk_size, MAX_CHUNK_SIZE); - return -EINVAL; - } - /* - * chunk-size has to be a power of 2 and multiples of PAGE_SIZE - */ - if ( (1 << ffz(~chunk_size)) != chunk_size) { - MD_BUG(); - return -EINVAL; - } - if (chunk_size < PAGE_SIZE) { - printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE); - return -EINVAL; - } - } else - if (chunk_size) - printk(KERN_INFO "RAID level %d does not need chunksize! Continuing anyway.\n", mddev->sb->level); - - if (pnum >= MAX_PERSONALITY) { - MD_BUG(); - return -EINVAL; - } - if (!pers[pnum]) - { -#ifdef CONFIG_KMOD - char module_name[80]; - sprintf (module_name, "md-personality-%d", pnum); - request_module (module_name); - if (!pers[pnum]) -#endif - { - printk(KERN_ERR "personality %d is not loaded!\n", - pnum); - return -EINVAL; - } - } - if (device_size_calculation(mddev)) - return -EINVAL; - - /* - * Drop all container device buffers, from now on - * the only valid external interface is through the md - * device. - * Also find largest hardsector size - */ - md_hardsect_sizes[mdidx(mddev)] = 512; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) - continue; - invalidate_device(rdev->dev, 1); -/* if (get_hardsect_size(rdev->dev) - > md_hardsect_sizes[mdidx(mddev)]) - md_hardsect_sizes[mdidx(mddev)] = - get_hardsect_size(rdev->dev); */ - if (rdev->node->hardsector_size > md_hardsect_sizes[mdidx(mddev)]) { - md_hardsect_sizes[mdidx(mddev)] = rdev->node->hardsector_size; - } - - } - md_blocksizes[mdidx(mddev)] = 1024; - if (md_blocksizes[mdidx(mddev)] < md_hardsect_sizes[mdidx(mddev)]) - md_blocksizes[mdidx(mddev)] = md_hardsect_sizes[mdidx(mddev)]; - - mddev->pers = pers[pnum]; - - err = mddev->pers->run(mddev); - if (err) { - LOG_WARNING("%s: pers->run() failed.\n", __FUNCTION__); - mddev->pers = NULL; - return -EINVAL; - } - mddev->sb->state &= ~(1 << MD_SB_CLEAN); - - evms_md_update_sb(mddev); - - if (incomplete_mddev(mddev)) { - LOG_DEFAULT("%s: [md%d] was incomplete!\n", __FUNCTION__, mdidx(mddev)); - list_del(&mddev->incomplete_mddevs); - INIT_LIST_HEAD(&mddev->incomplete_mddevs); - } - - list_add(&mddev->running_mddevs, &running_mddevs); - - return (0); -} - -#undef TOO_BIG_CHUNKSIZE -#undef BAD_CHUNKSIZE - - -#define OUT(x) do { err = (x); goto out; } while (0) - - -#define STILL_MOUNTED KERN_WARNING \ -"md%d still mounted.\n" -#define STILL_IN_USE \ -"md%d still in use.\n" - -static int do_md_stop (mddev_t * mddev, int ro) -{ - int err = 0, resync_interrupted = 0, clean = 0; - kdev_t dev = mddev_to_kdev(mddev); - - if (atomic_read(&mddev->active)>1) { - printk(STILL_IN_USE, mdidx(mddev)); - OUT(-EBUSY); - } - - if (mddev->pers) { - /* - * It is safe to call stop here, it only frees private - * data. Also, it tells us if a device is unstoppable - * (eg. resyncing is in progress) - */ - if (mddev->pers->stop_resync) - if (mddev->pers->stop_resync(mddev)) - resync_interrupted = 1; - - if (mddev->recovery_running) - evms_cs_interrupt_thread(evms_md_recovery_thread); - - /* - * This synchronizes with signal delivery to the - * resync or reconstruction thread. It also nicely - * hangs the process if some reconstruction has not - * finished. - */ - down(&mddev->recovery_sem); - up(&mddev->recovery_sem); - - invalidate_device(dev, 1); - - if (ro) { - if (mddev->ro) - OUT(-ENXIO); - mddev->ro = 1; - mddev->node->plugin = &md_plugin_header; - } else { - if (mddev->ro) - set_device_ro(dev, 0); - if (mddev->pers->stop(mddev)) { - if (mddev->ro) - set_device_ro(dev, 1); - OUT(-EBUSY); - } - if (mddev->ro) - mddev->ro = 0; - } - if (mddev->sb) { - /* - * mark it clean only if there was no resync - * interrupted. - */ - if (!mddev->recovery_running && !resync_interrupted) { - LOG_DEBUG("%s: marking sb clean...\n", __FUNCTION__); - clean = 1; - } - evms_md_update_sb_sync(mddev, clean); - } - if (ro) - set_device_ro(dev, 1); - } - - /* - * Free resources if final stop - */ - if (!ro) { - printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); - free_mddev(mddev); - - } else - printk (KERN_INFO - "md%d switched to read-only mode.\n", mdidx(mddev)); -out: - return err; -} - - -static int evms_md_run_array (struct evms_logical_node ** discover_list, mddev_t *mddev) -{ - mdk_rdev_t *rdev; - struct list_head *tmp; - int err = 0; - uint flags = 0; - - if (mddev->disks.prev == &mddev->disks) { - MD_BUG(); - return -EINVAL; - } - - LOG_DETAILS("%s: trying to run array md%d\n", __FUNCTION__,mdidx(mddev) ); - - ITERATE_RDEV(mddev,rdev,tmp) { - LOG_DETAILS(" <%s>\n", get_partition_name(rdev)); - } - - err = do_md_run (mddev); - if (!err) { - /* - * remove all nodes consumed by this md device from the discover list - */ - ITERATE_RDEV(mddev,rdev,tmp) { - LOG_DETAILS(" removing %s from discover list.\n", get_partition_name(rdev)); - evms_cs_remove_logical_node_from_list(discover_list,rdev->node); - flags |= rdev->node->flags; - } - err = evms_md_create_logical_node(discover_list,mddev,flags); - if (!err) { - exported_nodes++; - } - } else { - LOG_WARNING("%s: could not start [md%d] containing: \n",__FUNCTION__,mdidx(mddev)); - ITERATE_RDEV(mddev,rdev,tmp) { - LOG_WARNING(" (%s, desc_nr=%d)\n", get_partition_name(rdev), rdev->desc_nr); - } - LOG_WARNING("%s: will try restart [md%d] again later.\n",__FUNCTION__,mdidx(mddev)); - - mddev->sb_dirty = 0; - } - return err; -} - -static void evms_md_run_incomplete_array (struct evms_logical_node ** discover_list, mddev_t *mddev) -{ - mdk_rdev_t *rdev; - - LOG_DEFAULT("%s [md%d]\n", - __FUNCTION__, mdidx(mddev)); - if (evms_md_run_array(discover_list,mddev) == 0) { - /* - * We succeeded running this MD device. - * Now read MD superblock on this newly created MD node. - */ - if (mddev->node && - (evms_md_import_device(discover_list,mddev->node) == 0)) { - /* - * Yes, there is a superblock on this MD node. - * We probably have a MD stacking case here. - */ - rdev = evms_md_find_rdev_all(mddev->node); - if (rdev) { - list_add(&rdev->pending, &pending_raid_disks); - evms_md_run_devices(discover_list); - } else { - LOG_WARNING("%s: imported %s but no rdev was found!\n", - __FUNCTION__, - evms_md_partition_name(mddev->node)); - } - } - } - if (incomplete_mddev(mddev)) { - list_del(&mddev->incomplete_mddevs); - INIT_LIST_HEAD(&mddev->incomplete_mddevs); - } -} - -/* - * lets try to run arrays based on all disks that have arrived - * until now. (those are in the ->pending list) - * - * the method: pick the first pending disk, collect all disks with - * the same UUID, remove all from the pending list and put them into - * the 'same_array' list. Then order this list based on superblock - * update time (freshest comes first), kick out 'old' disks and - * compare superblocks. If everything's fine then run it. - * - * If "unit" is allocated, then bump its reference count - */ -static void evms_md_run_devices (struct evms_logical_node **discover_list) -{ - struct list_head candidates; - struct list_head *tmp; - mdk_rdev_t *rdev0, *rdev; - mddev_t *mddev; - kdev_t md_kdev; - - - LOG_ENTRY_EXIT("%s: ENTRY\n", __FUNCTION__); - while (pending_raid_disks.next != &pending_raid_disks) { - rdev0 = list_entry(pending_raid_disks.next, - mdk_rdev_t, pending); - MD_INIT_LIST_HEAD(&candidates); - ITERATE_RDEV_PENDING(rdev,tmp) { - if (uuid_equal(rdev0, rdev)) { - if (!sb_equal(rdev0->sb, rdev->sb)) { - LOG_DETAILS("%s has same UUID as %s, but superblocks differ ...\n",\ - get_partition_name(rdev),get_partition_name(rdev0)); - continue; - } - list_del(&rdev->pending); - list_add(&rdev->pending, &candidates); - } - } - - /* - * now we have a set of devices, with all of them having - * mostly sane superblocks. It's time to allocate the - * mddev. - */ - md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); - mddev = kdev_to_mddev(md_kdev); - if (mddev && (!incomplete_mddev(mddev))) { - LOG_DETAILS("md%d already running, cannot run %s\n", - mdidx(mddev), get_partition_name(rdev0)); - - ITERATE_RDEV(mddev,rdev,tmp) { - /* - * This is EVMS re-discovery! - * Remove all nodes consumed by this md device from the discover list - */ - evms_cs_remove_logical_node_from_list(discover_list,rdev->node); - } - - ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { - if (evms_md_find_mddev_all(rdev->node)) - /* - * We have found an MD superblock on top of a running MD array. - * Delete rdev but keep the MD array. - */ - evms_md_export_rdev(rdev, FALSE); - else - evms_md_export_rdev(rdev, TRUE); - } - continue; - } - - if (!mddev) { - mddev = alloc_mddev(md_kdev); - if (mddev == NULL) { - LOG_ERROR("cannot allocate memory for md drive.\n"); - break; - } - LOG_DETAILS("created md%d\n", mdidx(mddev)); - } else { - LOG_DETAILS("%s: found INCOMPLETE md%d\n", __FUNCTION__, mdidx(mddev)); - } - - ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { - bind_rdev_to_array(rdev, mddev); - list_del(&rdev->pending); - MD_INIT_LIST_HEAD(&rdev->pending); - } - - if ((mddev->nr_raid_disks >= rdev0->sb->raid_disks) || - (mddev->nb_dev == rdev0->sb->nr_disks)) { - evms_md_run_array(discover_list,mddev); - } else { - LOG_DETAILS("THIS md%d IS INCOMPLETE, found %d devices, need %d\n", - mdidx(mddev), mddev->nr_raid_disks, rdev0->sb->raid_disks); - list_add(&mddev->incomplete_mddevs, &incomplete_mddevs); - ITERATE_RDEV(mddev,rdev,tmp) { - evms_cs_remove_logical_node_from_list(discover_list,rdev->node); - } - } - } - LOG_ENTRY_EXIT("%s: EXIT\n", __FUNCTION__); -} - -void evms_md_recover_arrays(void) -{ - if (!evms_md_recovery_thread) { - MD_BUG(); - return; - } - evms_cs_wakeup_thread(evms_md_recovery_thread); -} - -int evms_md_error_dev( - mddev_t *mddev, - kdev_t dev) -{ - mdk_rdev_t * rdev; - - rdev = evms_md_find_rdev(mddev, dev); - if (rdev) { - return evms_md_error(mddev,rdev->node); - } else { - LOG_ERROR("%s: could not find %s in md%d\n", - __FUNCTION__, org_partition_name(dev), mdidx(mddev)); - return 0; - } -} - -int evms_md_error( - mddev_t *mddev, - struct evms_logical_node *node) -{ - mdk_rdev_t * rrdev; - - /* check for NULL first */ - if (!mddev) { - MD_BUG(); - return 0; - } - LOG_ERROR("evms_md_error dev:(md%d), node:(%s), (caller: %p,%p,%p,%p).\n", - mdidx(mddev), node->name, - __builtin_return_address(0),__builtin_return_address(1), - __builtin_return_address(2),__builtin_return_address(3)); - - rrdev = evms_md_find_rdev_from_node(mddev, node); - if (!rrdev || rrdev->faulty) - return 0; - if (!mddev->pers->error_handler - || mddev->pers->error_handler(mddev,node) <= 0) { - free_disk_sb(rrdev); - rrdev->faulty = 1; - } else - return 1; - /* - * if recovery was running, stop it now. - */ - if (mddev->pers->stop_resync) - mddev->pers->stop_resync(mddev); - if (mddev->recovery_running) - evms_cs_interrupt_thread(evms_md_recovery_thread); - evms_md_recover_arrays(); - - return 0; -} - -int evms_register_md_personality (int pnum, mdk_personality_t *p) -{ - if (pnum >= MAX_PERSONALITY) { - MD_BUG(); - return -EINVAL; - } - - if (pers[pnum]) { - MD_BUG(); - return -EBUSY; - } - - pers[pnum] = p; - LOG_DETAILS("%s personality registered as nr %d\n",p->name, pnum); - return 0; -} - -int evms_unregister_md_personality (int pnum) -{ - if (pnum >= MAX_PERSONALITY) { - MD_BUG(); - return -EINVAL; - } - - printk(KERN_INFO "%s personality unregistered\n", pers[pnum]->name); - pers[pnum] = NULL; - return 0; -} - -mdp_disk_t *evms_md_get_spare(mddev_t *mddev) -{ - mdp_super_t *sb = mddev->sb; - mdp_disk_t *disk; - mdk_rdev_t *rdev; - int i, j; - - for (i = 0, j = 0; j < mddev->nb_dev; i++) { - rdev = evms_md_find_rdev_nr(mddev, i); - if (rdev == NULL) - continue; - j++; - if (rdev->faulty) - continue; - if (!rdev->sb) { - if (!rdev->virtual_spare) - MD_BUG(); - continue; - } - disk = &sb->disks[rdev->desc_nr]; - if (disk_faulty(disk)) { - MD_BUG(); - continue; - } - if (disk_active(disk)) - continue; - return disk; - } - return NULL; -} - -static mdp_disk_t *evms_md_find_disk(mddev_t *mddev, kdev_t dev) -{ - mdp_super_t *sb = mddev->sb; - mdp_disk_t *disk; - int i; - - for (i=0; i < MD_SB_DISKS; i++) { - disk = &sb->disks[i]; - if ((disk->major == MAJOR(dev)) && (disk->minor == MINOR(dev))) - return disk; - } - return NULL; -} - -static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK]; -void evms_md_sync_acct( - kdev_t dev, - unsigned long nr_sectors) -{ - unsigned int major = MAJOR(dev); - unsigned int index; - - index = disk_index(dev); - if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - return; - - sync_io[major][index] += nr_sectors; -} - -static int is_mddev_idle(mddev_t *mddev) -{ - mdk_rdev_t * rdev; - struct list_head *tmp; - int idle; - unsigned long curr_events; - - idle = 1; - ITERATE_RDEV(mddev,rdev,tmp) { - int major = MAJOR(rdev->dev); - int idx = disk_index(rdev->dev); - - if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - continue; - - curr_events = kstat.dk_drive_rblk[major][idx] + - kstat.dk_drive_wblk[major][idx] ; - curr_events -= sync_io[major][idx]; - if ((curr_events - rdev->last_events) > 32) { - rdev->last_events = curr_events; - idle = 0; - } - } - return idle; -} - -MD_DECLARE_WAIT_QUEUE_HEAD(evms_resync_wait); - -void evms_md_done_sync(mddev_t *mddev, int blocks, int ok) -{ - /* another "blocks" (512byte) blocks have been synced */ - atomic_sub(blocks, &mddev->recovery_active); - wake_up(&mddev->recovery_wait); - if (!ok) { - // stop recovery, signal do_sync .... - } -} - -#define SYNC_MARKS 10 -#define SYNC_MARK_STEP (3*HZ) -int evms_md_do_sync(mddev_t *mddev, mdp_disk_t *spare) -{ - mddev_t *mddev2; - unsigned int max_sectors, currspeed, - j, window, err, serialize; - unsigned long mark[SYNC_MARKS]; - unsigned long mark_cnt[SYNC_MARKS]; - int last_mark,m; - struct list_head *tmp; - unsigned long last_check; - - - err = down_interruptible(&mddev->resync_sem); - if (err) - goto out_nolock; - -recheck: - serialize = 0; - ITERATE_MDDEV(mddev2,tmp) { - if (mddev2 == mddev) - continue; - if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) { - LOG_DEFAULT("delaying resync of md%d until md%d " - "has finished resync (they share one or more physical units)\n", - mdidx(mddev), mdidx(mddev2)); - serialize = 1; - break; - } - } - if (serialize) { - interruptible_sleep_on(&evms_resync_wait); - if (md_signal_pending(current)) { - md_flush_signals(); - err = -EINTR; - goto out; - } - goto recheck; - } - - mddev->curr_resync = 1; - - max_sectors = mddev->sb->size<<1; - - LOG_DEFAULT("syncing RAID array md%d\n", mdidx(mddev)); - LOG_DEFAULT("minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", - sysctl_speed_limit_min); - LOG_DEFAULT("using maximum available idle IO bandwith " - "(but not more than %d KB/sec) for reconstruction.\n", - sysctl_speed_limit_max); - - /* - * Resync has low priority. - */ - set_user_nice(current,19); - - is_mddev_idle(mddev); /* this also initializes IO event counters */ - for (m = 0; m < SYNC_MARKS; m++) { - mark[m] = jiffies; - mark_cnt[m] = 0; - } - last_mark = 0; - mddev->resync_mark = mark[last_mark]; - mddev->resync_mark_cnt = mark_cnt[last_mark]; - - /* - * Tune reconstruction: - */ - window = MD_READAHEAD*(PAGE_SIZE/512); - LOG_DEFAULT("using %dk window, over a total of %d blocks.\n", - window/2,max_sectors/2); - - atomic_set(&mddev->recovery_active, 0); - init_waitqueue_head(&mddev->recovery_wait); - last_check = 0; - for (j = 0; j < max_sectors;) { - int sectors; - - sectors = mddev->pers->sync_request(mddev, j); - - if (sectors < 0) { - err = sectors; - goto out; - } - atomic_add(sectors, &mddev->recovery_active); - j += sectors; - mddev->curr_resync = j; - - if (last_check + window > j) - continue; - - last_check = j; - - run_task_queue(&tq_disk); - - repeat: - if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) { - /* step marks */ - int next = (last_mark+1) % SYNC_MARKS; - - mddev->resync_mark = mark[next]; - mddev->resync_mark_cnt = mark_cnt[next]; - mark[next] = jiffies; - mark_cnt[next] = j - atomic_read(&mddev->recovery_active); - last_mark = next; - } - - - if (md_signal_pending(current)) { - /* - * got a signal, exit. - */ - mddev->curr_resync = 0; - LOG_DEFAULT("evms_md_do_sync() got signal ... exiting\n"); - md_flush_signals(); - err = -EINTR; - goto out; - } - - /* - * this loop exits only if either when we are slower than - * the 'hard' speed limit, or the system was IO-idle for - * a jiffy. - * the system might be non-idle CPU-wise, but we only care - * about not overloading the IO subsystem. (things like an - * e2fsck being done on the RAID array should execute fast) - */ - if (md_need_resched(current)) - schedule(); - - currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; - - if (currspeed > sysctl_speed_limit_min) { - set_user_nice(current,19); - - if ((currspeed > sysctl_speed_limit_max) || - !is_mddev_idle(mddev)) { - set_current_state(TASK_INTERRUPTIBLE); - md_schedule_timeout(HZ/4); - goto repeat; - } - } else - set_user_nice(current,-20); - } - LOG_DEFAULT("md%d: sync done.\n",mdidx(mddev)); - err = 0; - /* - * this also signals 'finished resyncing' to md_stop - */ -out: - wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active)==0); - up(&mddev->resync_sem); -out_nolock: - mddev->curr_resync = 0; - wake_up(&evms_resync_wait); - return err; -} - - - -/* - * This is a kernel thread which syncs a spare disk with the active array - * - * the amount of foolproofing might seem to be a tad excessive, but an - * early (not so error-safe) version of raid1syncd synced the first 0.5 gigs - * of my root partition with the first 0.5 gigs of my /home partition ... so - * i'm a bit nervous ;) - */ -void evms_md_do_recovery(void *data) -{ - int err; - mddev_t *mddev; - mdp_super_t *sb; - mdp_disk_t *spare; - struct list_head *tmp; - - LOG_DEFAULT("recovery thread got woken up ...\n"); -restart: - ITERATE_MDDEV(mddev,tmp) { - - sb = mddev->sb; - if (!sb) - continue; - if (mddev->recovery_running) - continue; - if (sb->active_disks == sb->raid_disks) - continue; - if (!sb->spare_disks) { - LOG_ERROR(" [md%d] no spare disk to reconstruct array! " - "-- continuing in degraded mode\n", mdidx(mddev)); - continue; - } - - spare = NULL; - - if (!spare) { - /* - * now here we get the spare and resync it. - */ - spare = evms_md_get_spare(mddev); - } - if (!spare) - continue; - - LOG_DEFAULT(" [md%d] resyncing spare disk %s to replace failed disk\n", - mdidx(mddev), org_partition_name(MKDEV(spare->major,spare->minor))); - if (!mddev->pers->diskop) - continue; - - if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE)) - continue; - - down(&mddev->recovery_sem); - mddev->recovery_running = 1; - err = evms_md_do_sync(mddev, spare); - if (err == -EIO) { - LOG_DEFAULT("[md%d] spare disk %s failed, skipping to next spare.\n", - mdidx(mddev), org_partition_name(MKDEV(spare->major,spare->minor))); - if (!disk_faulty(spare)) { - mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE); - mark_disk_faulty(spare); - mark_disk_nonsync(spare); - mark_disk_inactive(spare); - sb->spare_disks--; - sb->working_disks--; - sb->failed_disks++; - } - } else - if (disk_faulty(spare)) - mddev->pers->diskop(mddev, &spare, - DISKOP_SPARE_INACTIVE); - if (err == -EINTR || err == -ENOMEM) { - /* - * Recovery got interrupted, or ran out of mem ... - * signal back that we have finished using the array. - */ - mddev->pers->diskop(mddev, &spare, - DISKOP_SPARE_INACTIVE); - up(&mddev->recovery_sem); - mddev->recovery_running = 0; - continue; - } else { - mddev->recovery_running = 0; - up(&mddev->recovery_sem); - } - if (!disk_faulty(spare)) { - /* - * the SPARE_ACTIVE diskop possibly changes the - * pointer too - */ - mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_ACTIVE); - mark_disk_sync(spare); - mark_disk_active(spare); - sb->active_disks++; - sb->spare_disks--; - } - mddev->sb_dirty = 1; - evms_md_update_sb(mddev); - goto restart; - } - LOG_DEFAULT("recovery thread finished ...\n"); - -} - -static void evms_md_create_recovery_thread(void) -{ - static char * name = "evms_mdrecoveryd"; - - if (!evms_md_recovery_thread) { - /* Create MD recovery thread */ - evms_md_recovery_thread = evms_cs_register_thread(evms_md_do_recovery, NULL, name); - if (!evms_md_recovery_thread) - LOG_SERIOUS("%s: evms_cs_recovery_thread failed\n", __FUNCTION__); - } -} - -static void evms_md_destroy_recovery_thread(void) -{ - if (evms_md_recovery_thread && !MOD_IN_USE) { - /* Destroy MD recovery thread */ - evms_cs_unregister_thread(evms_md_recovery_thread); - evms_md_recovery_thread = NULL; - } -} - -/** - * evms_md_create_logical_node - **/ -static int evms_md_create_logical_node( - struct evms_logical_node **discover_list, - mddev_t *mddev, - uint flags) -{ - int rc; - struct evms_md *evms_md = NULL; - struct evms_logical_node *newnode = NULL; - struct evms_plugin_header *hdr = NULL; - struct evms_plugin_fops *fops = NULL; - - rc = evms_cs_allocate_logical_node(&newnode); - if (!rc) { - evms_md = kmalloc(sizeof(*evms_md), GFP_KERNEL); - if (!evms_md) { - rc = -ENOMEM; - } else { - - memset(evms_md,0,sizeof(*evms_md)); - evms_md->mddev = mddev; - - fops = kmalloc(sizeof(*fops), GFP_KERNEL); - if (fops) { - /* copy MD plugin header - * copy function table - * replace read and write function pointers. - */ - evms_md->instance_plugin_hdr = md_plugin_header; - memcpy(fops, &md_fops, sizeof(*fops)); - fops->read = mddev->pers->read; - fops->write = mddev->pers->write; - evms_md->instance_plugin_hdr.fops = fops; - hdr = &evms_md->instance_plugin_hdr; - } else { - LOG_WARNING("%s: No memory to copy function table\n",__FUNCTION__); - rc = 0; /* clear rc and continue */ - hdr = &md_plugin_header; - } - } - } - - if (!rc && hdr) { - memset(newnode,0,sizeof(*newnode)); - newnode->plugin = hdr; - newnode->total_vsectors = (u64)evms_md_size[mdidx(mddev)] * 2; - newnode->block_size = md_blocksizes[mdidx(mddev)]; - newnode->hardsector_size = md_hardsect_sizes[mdidx(mddev)]; - sprintf(newnode->name,"md/md%d",mdidx(mddev)); - newnode->private = evms_md; - newnode->flags = flags; - - rc = evms_cs_add_logical_node_to_list(discover_list, newnode); - if (rc) { - LOG_ERROR("%s: could not add md node %s\n", __FUNCTION__, newnode->name); - } else { - LOG_DEBUG("%s: added [%s] to discover list (total_vsectors="PFU64")\n", - __FUNCTION__, newnode->name, newnode->total_vsectors); - } - } - - if (!rc) { - mddev->node = newnode; - } else { - if (evms_md) { - if (fops) - kfree(fops); - kfree(evms_md); - } - if (newnode) - evms_cs_deallocate_logical_node(newnode); - } - return rc; -} - - -/* - * Function: evms_md_autostart_arrays - * Discover MD "extended" devices - * Add MD "extended" devices to pending list for further processing - */ -static void evms_md_autostart_arrays (struct evms_logical_node **discover_list) -{ - struct evms_logical_node *node, *next_node; - mdk_rdev_t *rdev; - int rc=0; - - LOG_ENTRY_EXIT(":autostart_arrays() ENTRY\n"); - - /* examine each node on the discover list */ - next_node = *discover_list; - while(next_node) { - node = next_node; - next_node = node->next; - - rc = evms_md_import_device(discover_list, node); - if (rc && (rc != -EEXIST)) { - LOG_EXTRA("autostart_arrrays() Not %s!\n",evms_md_partition_name(node)); - continue; - } - - /* - * Sanity checks: - */ - rdev = evms_md_find_rdev_all(node); - if (!rdev) { - LOG_ERROR("find_rdev_all() failed\n"); - continue; - } - if (rdev->faulty) { - MD_BUG(); - continue; - } - - if (!rc) { - list_add(&rdev->pending, &pending_raid_disks); - } else if (rc == -EEXIST) { - struct evms_logical_node *md_node; - /* - * Must be in a re-discovery process here. - * Find the EVMS MD node that this rdev is a member of - */ - if (rdev->mddev) { - md_node = rdev->mddev->node; - if (md_node) { - rc = evms_cs_add_logical_node_to_list(discover_list,md_node); - switch (rc) { - case 0: - exported_nodes++; - LOG_DETAILS("Added MD node (%s) to discover list\n", - md_node->name); - break; - case 1: /* already on the list */ - case 2: /* already on the list */ - break; - default: - LOG_WARNING("could not add md node (%s), rc=%d\n", - md_node->name, rc); - } - } else { - LOG_ERROR("This MD device [md%d] does not have an EVMS logical node.\n", - rdev->mddev->__minor); - } - } else { - LOG_ERROR("This device [%s] does not belong to any array!\n", - get_partition_name(rdev)); - evms_md_export_rdev(rdev, TRUE); - } - evms_cs_remove_logical_node_from_list(discover_list,node); - } - } - - evms_md_run_devices(discover_list); - LOG_DETAILS("EVMD MD:autostart_arrays() EXIT (exported_nodes=%d)\n",exported_nodes); -} - -#ifdef CONFIG_PROC_FS -static int status_resync(char * page, off_t * offset, int count, mddev_t * mddev) -{ - int sz = 0; - off_t off = *offset; - unsigned long max_blocks, resync, res, dt, db, rt; - - resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; - max_blocks = mddev->sb->size; - - /* - * Should not happen. - */ - if (!max_blocks) { - MD_BUG(); - return 0; - } - res = (resync/1024)*1000/(max_blocks/1024 + 1); - { - int i, x = res/50, y = 20-x; - PROCPRINT("["); - for (i = 0; i < x; i++) - PROCPRINT("="); - sz += sprintf(page + sz, ">"); - for (i = 0; i < y; i++) - PROCPRINT("."); - PROCPRINT("] "); - } - if (!mddev->recovery_running) - /* - * true resync - */ - PROCPRINT(" resync =%3lu.%lu%% (%lu/%lu)", - res/10, res % 10, resync, max_blocks); - else - /* - * recovery ... - */ - PROCPRINT(" recovery =%3lu.%lu%% (%lu/%lu)", - res/10, res % 10, resync, max_blocks); - - /* - * We do not want to overflow, so the order of operands and - * the * 100 / 100 trick are important. We do a +1 to be - * safe against division by zero. We only estimate anyway. - * - * dt: time from mark until now - * db: blocks written from mark until now - * rt: remaining time - */ - dt = ((jiffies - mddev->resync_mark) / HZ); - if (!dt) dt++; - db = resync - (mddev->resync_mark_cnt/2); - rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; - - PROCPRINT(" finish=%lu.%lumin", rt / 60, (rt % 60)/6); - - PROCPRINT(" speed=%ldK/sec", db/dt); - -out: - *offset = off; - return sz; -} - -static int evms_md_status_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int sz = 0, j, size; - struct list_head *tmp, *tmp2; - mdk_rdev_t *rdev; - mddev_t *mddev; - - PROCPRINT("Enterprise Volume Management System: MD Status\n"); - PROCPRINT("Personalities : "); - for (j = 0; j < MAX_PERSONALITY; j++) - if (pers[j]) - PROCPRINT("[%s] ", pers[j]->name); - - PROCPRINT("\n"); - - - ITERATE_MDDEV(mddev,tmp) { - PROCPRINT("md%d : %sactive", mdidx(mddev), - mddev->pers ? "" : "in"); - if (mddev->pers) { - if (mddev->ro) - PROCPRINT(" (read-only)"); - PROCPRINT(" %s", mddev->pers->name); - } - - size = 0; - ITERATE_RDEV(mddev,rdev,tmp2) { - PROCPRINT(" %s[%d]", - rdev->node->name, rdev->desc_nr); - if (rdev->faulty) { - PROCPRINT("(F)"); - continue; - } - size += rdev->size; - } - - if (mddev->nb_dev) { - if (mddev->pers) - PROCPRINT("\n "PFU64" blocks", - mddev->node->total_vsectors >> 1); - else - PROCPRINT("\n %d blocks", size); - } - - if (!mddev->pers) { - PROCPRINT("\n"); - continue; - } - - sz += mddev->pers->status (page+sz, mddev); - - PROCPRINT("\n "); - if (mddev->curr_resync) { - sz += status_resync (page+sz, &off, count, mddev); - } else { - if (atomic_read(&mddev->resync_sem.count) != 1) - PROCPRINT(" resync=DELAYED"); - } - - PROCPRINT("\n"); - } - *eof = 1; -out: - *start = page + off; - sz -= off; - if (sz < 0) - sz = 0; - return sz > count ? count : sz; -} -#endif - -/* Function: md_core_init - */ -int __init md_core_init(void) -{ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *evms_proc_dir; -#endif - -#ifdef CONFIG_PROC_FS - evms_proc_dir = evms_cs_get_evms_proc_dir(); - if (evms_proc_dir) { - create_proc_read_entry("mdstat", 0, evms_proc_dir, evms_md_status_read_proc, NULL); - } - md_table_header = register_sysctl_table(dev_dir_table, 1); -#endif - - return evms_cs_register_plugin(&md_plugin_header); -} - -static void __exit md_core_exit(void) -{ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *evms_proc_dir; - - evms_proc_dir = evms_cs_get_evms_proc_dir(); - if (evms_proc_dir) { - remove_proc_entry("mdstat", evms_proc_dir); - } - unregister_sysctl_table(md_table_header); -#endif - evms_cs_unregister_plugin(&md_plugin_header); -} - -module_init(md_core_init); -module_exit(md_core_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -/* - * In order to have the coexistence of this EVMS plugin and the orginal MD - * module, the symbols exported by this plugin are prefixed with "evms_" - */ - -MD_EXPORT_SYMBOL(evms_md_size); -MD_EXPORT_SYMBOL(evms_register_md_personality); -MD_EXPORT_SYMBOL(evms_unregister_md_personality); - /* Export the following function for use with rdev->node in evms_md_k.h */ -MD_EXPORT_SYMBOL(evms_md_partition_name); - /* Export the following function for use with disks[] in md_p.h */ -MD_EXPORT_SYMBOL(evms_md_error); -MD_EXPORT_SYMBOL(evms_md_error_dev); -MD_EXPORT_SYMBOL(evms_md_update_sb); -MD_EXPORT_SYMBOL(evms_md_find_rdev_nr); -MD_EXPORT_SYMBOL(evms_md_find_rdev); -MD_EXPORT_SYMBOL(evms_md_find_rdev_from_node); -MD_EXPORT_SYMBOL(evms_md_print_devices); -MD_EXPORT_SYMBOL(evms_mddev_map); -MD_EXPORT_SYMBOL(evms_md_check_ordering); -MD_EXPORT_SYMBOL(evms_md_partial_sync_io); -MD_EXPORT_SYMBOL(evms_md_sync_io); -MD_EXPORT_SYMBOL(evms_md_do_sync); -MD_EXPORT_SYMBOL(evms_md_sync_acct); -MD_EXPORT_SYMBOL(evms_md_done_sync); -MD_EXPORT_SYMBOL(evms_md_recover_arrays); -MD_EXPORT_SYMBOL(evms_md_get_spare); - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_linear.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_linear.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_linear.c 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_linear.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,285 +0,0 @@ -/* - linear.c : Multiple Devices driver for Linux - Copyright (C) 1994-96 Marc ZYNGIER - or - - - Linear mode management functions. - - 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. -*/ - -#include -#include -#include -#include - - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - -#define LOG_PREFIX "md linear: " -static int linear_run (mddev_t *mddev) -{ - linear_conf_t *conf; - struct linear_hash *table; - mdk_rdev_t *rdev; - int size, i, j, nb_zone; - unsigned int curr_offset; - - MOD_INC_USE_COUNT; - - conf = kmalloc (sizeof (*conf), GFP_KERNEL); - if (!conf) - goto out; - mddev->private = conf; - - if (evms_md_check_ordering(mddev)) { - printk("linear: disks are not ordered, aborting!\n"); - goto out; - } - - /* - * Find the smallest device. - */ - - conf->smallest = NULL; - curr_offset = 0; - ITERATE_RDEV_ORDERED(mddev,rdev,j) { - dev_info_t *disk = conf->disks + j; - disk->node = rdev->node; - disk->dev = rdev->dev; - disk->size = rdev->size; - disk->offset = curr_offset; - - curr_offset += disk->size; - - if (!conf->smallest || (disk->size < conf->smallest->size)) - conf->smallest = disk; - } - - nb_zone = conf->nr_zones = evms_md_size[mdidx(mddev)] / conf->smallest->size + - ((evms_md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0); - - conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, - GFP_KERNEL); - if (!conf->hash_table) - goto out; - - /* - * Here we generate the linear hash table - */ - table = conf->hash_table; - i = 0; - size = 0; - for (j = 0; j < mddev->nb_dev; j++) { - dev_info_t *disk = conf->disks + j; - - if (size < 0) { - table[-1].dev1 = disk; - } - size += disk->size; - - while (size>0) { - table->dev0 = disk; - table->dev1 = NULL; - size -= conf->smallest->size; - table++; - } - } - if (table-conf->hash_table != nb_zone) - BUG(); - LOG_DETAILS("%s: nr_zones=%d, smallest=%lu\n", - __FUNCTION__, conf->nr_zones, conf->smallest->size); - return 0; - -out: - if (conf) - kfree(conf); - MOD_DEC_USE_COUNT; - return 1; -} - -static int linear_stop (mddev_t *mddev) -{ - linear_conf_t *conf = mddev_to_conf(mddev); - - kfree(conf->hash_table); - kfree(conf); - - MOD_DEC_USE_COUNT; - - return 0; -} - -/* - * Function: linear_map - */ -static int linear_map( - mddev_t *mddev, - struct evms_logical_node **node, - struct buffer_head *bh) -{ - linear_conf_t *conf = mddev_to_conf(mddev); - struct linear_hash *hash; - dev_info_t *tmp_dev; - unsigned long block; - - block = (bh->b_rsector >> 1); - hash = conf->hash_table + (block / conf->smallest->size); - if (block >= (hash->dev0->size + hash->dev0->offset)) { - if (!hash->dev1) { - LOG_ERROR("%s: hash->dev1==NULL for block %ld\n", __FUNCTION__, block); - return -ENXIO; - } - tmp_dev = hash->dev1; - } else - tmp_dev = hash->dev0; - - if ( (block + (bh->b_size >> 10)) > (tmp_dev->size + tmp_dev->offset) - || block < tmp_dev->offset) { - LOG_ERROR("%s: Block %ld out of bounds on node %s size %ld offset %ld\n", - __FUNCTION__, - block, - tmp_dev->node->name, - tmp_dev->size, - tmp_dev->offset); - return -ENXIO; - } - bh->b_rsector -= (tmp_dev->offset << 1); - *node = tmp_dev->node; - return 0; -} - -static void linear_read( - struct evms_logical_node *md_node, - struct buffer_head *bh) -{ - mddev_t *mddev = EVMS_MD_NODE_TO_MDDEV(md_node); - struct evms_logical_node *node; - - if (evms_md_check_boundary(md_node, bh)) return; - - if (!linear_map(mddev, &node, bh)) { - R_IO(node, bh); - } else { - bh->b_end_io(bh, 0); - } -} - -static void linear_write( - struct evms_logical_node *md_node, - struct buffer_head *bh) -{ - mddev_t *mddev = EVMS_MD_NODE_TO_MDDEV(md_node); - struct evms_logical_node *node; - - if (evms_md_check_boundary(md_node, bh)) return; - - if (!linear_map(mddev, &node, bh)) { - W_IO(node, bh); - } else { - bh->b_end_io(bh, 0); - } -} - -static int linear_status (char *page, mddev_t *mddev) -{ - int sz = 0; - -#undef MD_DEBUG -#ifdef MD_DEBUG - int j; - linear_conf_t *conf = mddev_to_conf(mddev); - - sz += sprintf(page+sz, " "); - for (j = 0; j < conf->nr_zones; j++) - { - sz += sprintf(page+sz, "[%s", - partition_name(conf->hash_table[j].dev0->dev)); - - if (conf->hash_table[j].dev1) - sz += sprintf(page+sz, "/%s] ", - partition_name(conf->hash_table[j].dev1->dev)); - else - sz += sprintf(page+sz, "] "); - } - sz += sprintf(page+sz, "\n"); -#endif - sz += sprintf(page+sz, " %dk rounding", mddev->chunk_size/1024); - return sz; -} - -static int linear_evms_ioctl ( - mddev_t * mddev, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - struct evms_logical_node *node; - - switch (cmd) { - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = (struct evms_get_bmap_pkt *)arg; - struct buffer_head *bh = - evms_cs_allocate_from_pool(evms_bh_pool, FALSE); - if (bh) { - bh->b_rsector = (unsigned long)bmap->rsector; - bh->b_size = node->block_size; - rc = linear_map(mddev, &node, bh); - if (!rc) { - bmap->rsector = (u64)bh->b_rsector; - if (node) - rc = IOCTL(node, inode, file, cmd, arg); - else - rc = -ENODEV; - } - evms_cs_deallocate_to_pool(evms_bh_pool, bh); - } else - rc = -ENOMEM; - break; - } - - default: - rc = -EINVAL; - } - return rc; -} - -static mdk_personality_t linear_personality = { - .name = "evms_linear", - .read = linear_read, - .write = linear_write, - .run = linear_run, - .stop = linear_stop, - .status = linear_status, - .evms_ioctl = linear_evms_ioctl -}; - -static int md__init linear_init (void) -{ - return evms_register_md_personality (LINEAR, &linear_personality); -} - -static void linear_exit (void) -{ - evms_unregister_md_personality (LINEAR); -} - - -module_init(linear_init); -module_exit(linear_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_raid0.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_raid0.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_raid0.c 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_raid0.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,448 +0,0 @@ -/* - raid0.c : Multiple Devices driver for Linux - Copyright (C) 1994-96 Marc ZYNGIER - or - - Copyright (C) 1999, 2000 Ingo Molnar, Red Hat - - - RAID-0 management functions. - - 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. -*/ - -#include -#include - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - -#define LOG_PREFIX "md raid0: " - -static int create_strip_zones (mddev_t *mddev) -{ - int i, c, j, j1, j2; - unsigned long current_offset, curr_zone_offset, rdev_size_in_sects; - raid0_conf_t *conf = mddev_to_conf(mddev); - mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; - - /* - * The number of 'same size groups' - */ - conf->nr_strip_zones = 0; - - ITERATE_RDEV_ORDERED(mddev,rdev1,j1) { - LOG_DEBUG(" looking at %s\n", evms_md_partition_name(rdev1->node)); - c = 0; - ITERATE_RDEV_ORDERED(mddev,rdev2,j2) { - LOG_DEBUG(" comparing %s(%ld sectors) with %s(%ld sectors)\n", - evms_md_partition_name(rdev1->node), rdev1->size << 1, - evms_md_partition_name(rdev2->node), rdev2->size << 1); - if (rdev2 == rdev1) { - LOG_DEBUG(" END\n"); - break; - } - if (rdev2->size == rdev1->size) - { - /* - * Not unique, dont count it as a new - * group - */ - LOG_DEBUG(" EQUAL\n"); - c = 1; - break; - } - LOG_DEBUG(" NOT EQUAL\n"); - } - if (!c) { - LOG_DEBUG(" ==> UNIQUE\n"); - conf->nr_strip_zones++; - LOG_DEBUG(" %d zones\n",conf->nr_strip_zones); - } - } - LOG_DEBUG(" FINAL %d zones\n",conf->nr_strip_zones); - - conf->strip_zone = vmalloc(sizeof(struct strip_zone)* - conf->nr_strip_zones); - if (!conf->strip_zone) - return 1; - - - conf->smallest = NULL; - current_offset = 0; - curr_zone_offset = 0; - - for (i = 0; i < conf->nr_strip_zones; i++) - { - struct strip_zone *zone = conf->strip_zone + i; - - LOG_DEBUG(" zone %d\n", i); - zone->dev_offset = current_offset; - smallest = NULL; - c = 0; - - ITERATE_RDEV_ORDERED(mddev,rdev,j) { - - LOG_DEBUG(" checking %s ...",evms_md_partition_name(rdev->node)); - rdev_size_in_sects = rdev->size << 1; - if (rdev_size_in_sects > current_offset) - { - LOG_DEBUG(" contained as device %d\n", c); - zone->node[c] = rdev->node; - c++; - if (!smallest || (rdev_size_in_sects < (smallest->size <<1) )) { - smallest = rdev; - LOG_DEBUG(" (%ld) is smallest!.\n", rdev_size_in_sects); - } - } else - LOG_DEBUG(" nope.\n"); - } - - zone->nb_dev = c; - zone->size_in_sects = ((smallest->size <<1) - current_offset) * c; - LOG_DEBUG(" zone->nb_dev: %d, size: %ld\n", - zone->nb_dev,zone->size_in_sects); - - if (!conf->smallest || (zone->size_in_sects < conf->smallest->size_in_sects)) - conf->smallest = zone; - - zone->zone_offset = curr_zone_offset; - curr_zone_offset += zone->size_in_sects; - - current_offset = smallest->size << 1; - LOG_DEBUG(" current zone offset: %ld\n",current_offset); - } - LOG_DEBUG(" done.\n"); - return 0; -} - -static int raid0_run (mddev_t *mddev) -{ - unsigned long cur=0, i=0, size, zone0_size, nb_zone; - unsigned long mddev_size_in_sects = evms_md_size[mdidx(mddev)] << 1; - raid0_conf_t *conf; - - MOD_INC_USE_COUNT; - - conf = vmalloc(sizeof (raid0_conf_t)); - if (!conf) - goto out; - mddev->private = (void *)conf; - - if (evms_md_check_ordering(mddev)) { - LOG_ERROR("disks are not ordered, aborting!\n"); - goto out_free_conf; - } - - if (create_strip_zones (mddev)) - goto out_free_conf; - - LOG_DETAILS("evms_md_size is %ld sectors.\n", mddev_size_in_sects); - LOG_DETAILS("conf->smallest->size_in_sects is %ld sectors.\n", conf->smallest->size_in_sects); - nb_zone = mddev_size_in_sects / conf->smallest->size_in_sects + - (mddev_size_in_sects % conf->smallest->size_in_sects ? 1 : 0); - LOG_DETAILS("nb_zone is %ld.\n", nb_zone); - conf->nr_zones = nb_zone; - - LOG_DEBUG("Allocating %ld bytes for hash.\n", nb_zone*sizeof(struct raid0_hash)); - - conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone); - if (!conf->hash_table) - goto out_free_zone_conf; - size = conf->strip_zone[cur].size_in_sects; - - i = 0; - while (cur < conf->nr_strip_zones) { - conf->hash_table[i].zone0 = conf->strip_zone + cur; - - /* - * If we completely fill the slot - */ - if (size >= conf->smallest->size_in_sects) { - conf->hash_table[i++].zone1 = NULL; - size -= conf->smallest->size_in_sects; - - if (!size) { - if (++cur == conf->nr_strip_zones) - continue; - size = conf->strip_zone[cur].size_in_sects; - } - continue; - } - if (++cur == conf->nr_strip_zones) { - /* - * Last dev, set unit1 as NULL - */ - conf->hash_table[i].zone1=NULL; - continue; - } - - /* - * Here we use a 2nd dev to fill the slot - */ - zone0_size = size; - size = conf->strip_zone[cur].size_in_sects; - conf->hash_table[i++].zone1 = conf->strip_zone + cur; - size -= (conf->smallest->size_in_sects - zone0_size); - } - return 0; - -out_free_zone_conf: - vfree(conf->strip_zone); - conf->strip_zone = NULL; - -out_free_conf: - vfree(conf); - mddev->private = NULL; -out: - MOD_DEC_USE_COUNT; - return 1; -} - -static int raid0_stop (mddev_t *mddev) -{ - raid0_conf_t *conf = mddev_to_conf(mddev); - - vfree (conf->hash_table); - conf->hash_table = NULL; - vfree (conf->strip_zone); - conf->strip_zone = NULL; - vfree (conf); - mddev->private = NULL; - - MOD_DEC_USE_COUNT; - return 0; -} - - -/* - * Function: raid0_map - * - * Return 0 for success, else error - * - */ - -static inline int raid0_map( - mddev_t *mddev, - unsigned long lsn, - unsigned long size, - struct evms_logical_node **node, - unsigned long *new_lsn, - unsigned long *new_size) -{ - unsigned int sect_in_chunk, chunksize_bits, chunk_size_in_sects; - raid0_conf_t *conf = mddev_to_conf(mddev); - struct raid0_hash *hash; - struct strip_zone *zone; - unsigned long chunk; - - chunk_size_in_sects = mddev->chunk_size >> EVMS_VSECTOR_SIZE_SHIFT; - chunksize_bits = ffz(~chunk_size_in_sects); - hash = conf->hash_table + (lsn / conf->smallest->size_in_sects); - - /* Sanity check */ - if (!hash) - goto bad_hash; - - if (!hash->zone0) - goto bad_zone0; - - if (lsn >= (hash->zone0->size_in_sects + hash->zone0->zone_offset)) { - if (!hash->zone1) - goto bad_zone1; - zone = hash->zone1; - } else - zone = hash->zone0; - - sect_in_chunk = lsn & (chunk_size_in_sects - 1); - chunk = (lsn - zone->zone_offset) / (zone->nb_dev << chunksize_bits); - *node = zone->node[(lsn >> chunksize_bits) % zone->nb_dev]; - - *new_lsn = ((chunk << chunksize_bits) + zone->dev_offset) + sect_in_chunk; - - *new_size = (size <= chunk_size_in_sects - sect_in_chunk) ? - size : chunk_size_in_sects - sect_in_chunk; - - return 0; - -bad_hash: - LOG_ERROR("%s: bug: hash==NULL for lsn %lu\n", __FUNCTION__, lsn); - goto outerr; -bad_zone0: - LOG_ERROR("%s: bug: hash->zone0==NULL for lsn %lu\n", __FUNCTION__, lsn); - goto outerr; -bad_zone1: - LOG_ERROR("%s: bug: hash->zone1==NULL for lsn %lu\n", __FUNCTION__, lsn); -outerr: - return -EINVAL; -} - -void raid0_error(int rw, struct evms_logical_node *node, struct buffer_head *bh) -{ - LOG_ERROR(" %s FAILED on node(%s) rsector(%lu) size(%d)\n", - (rw == READ) ? "READ" : "WRITE", - node->name, - bh->b_rsector, - bh->b_size); - - bh->b_end_io(bh, 0); -} - -static inline void raid0_rw ( - struct evms_logical_node *md_node, - struct buffer_head *bh, - int rw) -{ - mddev_t *mddev = EVMS_MD_NODE_TO_MDDEV(md_node); - struct evms_logical_node *node; - unsigned long new_lsn, size_in_sects, new_size; - - if (evms_md_check_boundary(md_node, bh)) return; - size_in_sects = bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - if (!raid0_map(mddev, bh->b_rsector, size_in_sects, &node, &new_lsn, &new_size)) { - if (new_size == size_in_sects) { - /* - * This is the normal case: - * the request is entirely within the stripe boundary - */ - bh->b_rsector = new_lsn; - if (rw == READ) { - R_IO(node, bh); - } else { - W_IO(node, bh); - } - return; - } else { - /* - * BUGBUG! - * Need more processing here (ie. break up the request) - */ - LOG_ERROR("This version of EVMS RAID0 does not support I/O requests that are:\n"); - LOG_ERROR(" - larger than the stripe size\n"); - LOG_ERROR(" - cross the stripe boundary\n"); - } - } - raid0_error(rw, node, bh); -} - -static void raid0_read( - struct evms_logical_node *md_node, - struct buffer_head *bh) -{ - raid0_rw(md_node, bh, READ); -} - -static void raid0_write( - struct evms_logical_node *md_node, - struct buffer_head *bh) -{ - raid0_rw(md_node, bh, WRITE); -} - -static int raid0_status (char *page, mddev_t *mddev) -{ - int sz = 0; -#undef MD_DEBUG -#ifdef MD_DEBUG - int j, k; - raid0_conf_t *conf = mddev_to_conf(mddev); - - sz += sprintf(page + sz, " "); - for (j = 0; j < conf->nr_zones; j++) { - sz += sprintf(page + sz, "[z%d", - conf->hash_table[j].zone0 - conf->strip_zone); - if (conf->hash_table[j].zone1) - sz += sprintf(page+sz, "/z%d] ", - conf->hash_table[j].zone1 - conf->strip_zone); - else - sz += sprintf(page+sz, "] "); - } - - sz += sprintf(page + sz, "\n"); - - for (j = 0; j < conf->nr_strip_zones; j++) { - sz += sprintf(page + sz, " z%d=[", j); - for (k = 0; k < conf->strip_zone[j].nb_dev; k++) - sz += sprintf (page+sz, "%s/", conf->strip_zone[j].node[k]->name); - sz--; - sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n", - conf->strip_zone[j].zone_offset, - conf->strip_zone[j].dev_offset, - conf->strip_zone[j].size_in_sects); - } -#endif - sz += sprintf(page + sz, " %dk chunks", mddev->chunk_size/1024); - return sz; -} - -static int raid0_evms_ioctl ( - mddev_t * mddev, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - struct evms_logical_node *node; - - switch (cmd) { - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = (struct evms_get_bmap_pkt *)arg; - unsigned long new_lsn, new_size; - unsigned long size = mddev->node->block_size >> EVMS_VSECTOR_SIZE_SHIFT; - rc = raid0_map(mddev, - (unsigned long)bmap->rsector, - size, - &node, - &new_lsn, - &new_size); - if (!rc) { - if (node) { - bmap->rsector = (u64)new_lsn; - rc = IOCTL(node, inode, file, cmd, arg); - } else - rc = -ENODEV; - } - break; - } - - default: - rc = -EINVAL; - } - return rc; -} - -static mdk_personality_t raid0_personality = { - .name = "evms_raid0", - .read = raid0_read, - .write = raid0_write, - .run = raid0_run, - .stop = raid0_stop, - .status = raid0_status, - .evms_ioctl = raid0_evms_ioctl -}; - -static int md__init raid0_init (void) -{ - return evms_register_md_personality (RAID0, &raid0_personality); -} - -static void raid0_exit (void) -{ - evms_unregister_md_personality (RAID0); -} - -module_init(raid0_init); -module_exit(raid0_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_raid1.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_raid1.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_raid1.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_raid1.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1937 +0,0 @@ -/* - * md_raid1.c : Multiple Devices driver for Linux - * - * Copyright (C) 1999, 2000 Ingo Molnar, Red Hat - * - * Copyright (C) 1996, 1997, 1998 Ingo Molnar, Miguel de Icaza, Gadi Oxman - * - * RAID-1 management functions. - * - * Better read-balancing code written by Mika Kuoppala , 2000 - * - * Fixes to reconstruction by Jakob Østergaard" - * Various fixes by Neil Brown - * - * 'md_raid1.c' is an EVMS version of linux/drivers/md/raid1.c modified - * by Cuong (Mike) Tran , January 2002. - * - * 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. - */ - -#include -#include -#include -#include - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - -#define MAX_WORK_PER_DISK 128 - -#define NR_RESERVED_BUFS 32 - -#define LOG_PREFIX "md raid1: " -/* - * The following can be used to debug the driver - */ -#define RAID1_DEBUG 0 - -#if RAID1_DEBUG -#define PRINTK(x...) LOG_DEFAULT(x) -#define inline -#define __inline__ -#else -#define PRINTK(x...) do { } while (0) -#endif - - -static mdk_personality_t raid1_personality; -static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED; -struct raid1_bh *evms_raid1_retry_list = NULL, **evms_raid1_retry_tail; - -static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt) -{ - /* return a linked list of "cnt" struct buffer_heads. - * don't take any off the free list unless we know we can - * get all we need, otherwise we could deadlock - */ - struct buffer_head *bh=NULL; - - while(cnt) { - struct buffer_head *t; - md_spin_lock_irq(&conf->device_lock); - if (!conf->freebh_blocked && conf->freebh_cnt >= cnt) - while (cnt) { - t = conf->freebh; - conf->freebh = t->b_next; - t->b_next = bh; - bh = t; - t->b_state = 0; - conf->freebh_cnt--; - cnt--; - } - md_spin_unlock_irq(&conf->device_lock); - if (cnt == 0) - break; - t = kmem_cache_alloc(bh_cachep, SLAB_NOIO); - if (t) { - t->b_next = bh; - bh = t; - cnt--; - } else { - PRINTK("raid1: waiting for %d bh\n", cnt); - conf->freebh_blocked = 1; - wait_disk_event(conf->wait_buffer, - !conf->freebh_blocked || - conf->freebh_cnt > conf->raid_disks * NR_RESERVED_BUFS/2); - conf->freebh_blocked = 0; - } - } - return bh; -} - -static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh) -{ - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - while (bh) { - struct buffer_head *t = bh; - bh=bh->b_next; - if (t->b_pprev == NULL) - kmem_cache_free(bh_cachep, t); - else { - t->b_next= conf->freebh; - conf->freebh = t; - conf->freebh_cnt++; - } - } - spin_unlock_irqrestore(&conf->device_lock, flags); - wake_up(&conf->wait_buffer); -} - -static int raid1_grow_bh(raid1_conf_t *conf, int cnt) -{ - /* allocate cnt buffer_heads, possibly less if kmalloc fails */ - int i = 0; - - while (i < cnt) { - struct buffer_head *bh; - bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL); - if (!bh) break; - - md_spin_lock_irq(&conf->device_lock); - bh->b_pprev = &conf->freebh; - bh->b_next = conf->freebh; - conf->freebh = bh; - conf->freebh_cnt++; - md_spin_unlock_irq(&conf->device_lock); - - i++; - } - return i; -} - -static void raid1_shrink_bh(raid1_conf_t *conf) -{ - /* discard all buffer_heads */ - - md_spin_lock_irq(&conf->device_lock); - while (conf->freebh) { - struct buffer_head *bh = conf->freebh; - conf->freebh = bh->b_next; - kmem_cache_free(bh_cachep, bh); - conf->freebh_cnt--; - } - md_spin_unlock_irq(&conf->device_lock); -} - - -static struct raid1_bh *raid1_alloc_r1bh(raid1_conf_t *conf) -{ - struct raid1_bh *r1_bh = NULL; - - do { - md_spin_lock_irq(&conf->device_lock); - if (!conf->freer1_blocked && conf->freer1) { - r1_bh = conf->freer1; - conf->freer1 = r1_bh->next_r1; - conf->freer1_cnt--; - r1_bh->next_r1 = NULL; - r1_bh->state = (1 << R1BH_PreAlloc); - r1_bh->bh_req.b_state = 0; - } - md_spin_unlock_irq(&conf->device_lock); - if (r1_bh) - return r1_bh; - r1_bh = (struct raid1_bh *) kmalloc(sizeof(struct raid1_bh), GFP_NOIO); - if (r1_bh) { - memset(r1_bh, 0, sizeof(*r1_bh)); - return r1_bh; - } - conf->freer1_blocked = 1; - wait_disk_event(conf->wait_buffer, - !conf->freer1_blocked || - conf->freer1_cnt > NR_RESERVED_BUFS/2 - ); - conf->freer1_blocked = 0; - } while (1); -} - -static inline void raid1_free_r1bh(struct raid1_bh *r1_bh) -{ - struct buffer_head *bh = r1_bh->mirror_bh_list; - raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); - - r1_bh->mirror_bh_list = NULL; - - if (test_bit(R1BH_PreAlloc, &r1_bh->state)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - r1_bh->next_r1 = conf->freer1; - conf->freer1 = r1_bh; - conf->freer1_cnt++; - spin_unlock_irqrestore(&conf->device_lock, flags); - /* don't need to wakeup wait_buffer because - * raid1_free_bh below will do that - */ - } else { - kfree(r1_bh); - } - raid1_free_bh(conf, bh); -} - -static int raid1_grow_r1bh (raid1_conf_t *conf, int cnt) -{ - int i = 0; - - while (i < cnt) { - struct raid1_bh *r1_bh; - r1_bh = (struct raid1_bh*)kmalloc(sizeof(*r1_bh), GFP_KERNEL); - if (!r1_bh) - break; - memset(r1_bh, 0, sizeof(*r1_bh)); - set_bit(R1BH_PreAlloc, &r1_bh->state); - r1_bh->mddev = conf->mddev; - - raid1_free_r1bh(r1_bh); - i++; - } - return i; -} - -static void raid1_shrink_r1bh(raid1_conf_t *conf) -{ - md_spin_lock_irq(&conf->device_lock); - while (conf->freer1) { - struct raid1_bh *r1_bh = conf->freer1; - conf->freer1 = r1_bh->next_r1; - conf->freer1_cnt--; - kfree(r1_bh); - } - md_spin_unlock_irq(&conf->device_lock); -} - - - -static inline void raid1_free_buf(struct raid1_bh *r1_bh) -{ - unsigned long flags; - struct buffer_head *bh = r1_bh->mirror_bh_list; - raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); - r1_bh->mirror_bh_list = NULL; - - spin_lock_irqsave(&conf->device_lock, flags); - r1_bh->next_r1 = conf->freebuf; - conf->freebuf = r1_bh; - spin_unlock_irqrestore(&conf->device_lock, flags); - raid1_free_bh(conf, bh); -} - -static struct raid1_bh *raid1_alloc_buf(raid1_conf_t *conf) -{ - struct raid1_bh *r1_bh; - - md_spin_lock_irq(&conf->device_lock); - wait_event_lock_irq(conf->wait_buffer, conf->freebuf, conf->device_lock); - r1_bh = conf->freebuf; - conf->freebuf = r1_bh->next_r1; - r1_bh->next_r1= NULL; - md_spin_unlock_irq(&conf->device_lock); - return r1_bh; -} - -static int raid1_grow_buffers (raid1_conf_t *conf, int cnt) -{ - int i = 0; - - md_spin_lock_irq(&conf->device_lock); - while (i < cnt) { - struct raid1_bh *r1_bh; - struct page *page; - - page = alloc_page(GFP_KERNEL); - if (!page) - break; - - r1_bh = (struct raid1_bh *) kmalloc(sizeof(*r1_bh), GFP_KERNEL); - if (!r1_bh) { - __free_page(page); - break; - } - memset(r1_bh, 0, sizeof(*r1_bh)); - r1_bh->bh_req.b_page = page; - r1_bh->bh_req.b_data = page_address(page); - r1_bh->next_r1 = conf->freebuf; - conf->freebuf = r1_bh; - i++; - } - md_spin_unlock_irq(&conf->device_lock); - return i; -} - -static void raid1_shrink_buffers (raid1_conf_t *conf) -{ - md_spin_lock_irq(&conf->device_lock); - while (conf->freebuf) { - struct raid1_bh *r1_bh = conf->freebuf; - conf->freebuf = r1_bh->next_r1; - __free_page(r1_bh->bh_req.b_page); - kfree(r1_bh); - } - md_spin_unlock_irq(&conf->device_lock); -} - -/* - * evms_raid1_map - * EVMS raid1 version of raid1_map() - */ -static int evms_raid1_map (mddev_t *mddev, struct evms_logical_node **node, kdev_t *rdev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - int i; - - /* - * Later we do read balancing on the read side - * now we use the first available disk. - */ - - for (i = 0; i < MD_SB_DISKS; i++) { - if (conf->mirrors[i].operational) { - *node = conf->mirrors[i].node; - *rdev = conf->mirrors[i].dev; - return (0); - } - } - - LOG_ERROR("huh, no more operational devices?\n"); - return (-1); -} - -static void raid1_reschedule_retry (struct raid1_bh *r1_bh) -{ - unsigned long flags; - mddev_t *mddev = r1_bh->mddev; - raid1_conf_t *conf = mddev_to_conf(mddev); - - md_spin_lock_irqsave(&retry_list_lock, flags); - if (evms_raid1_retry_list == NULL) - evms_raid1_retry_tail = &evms_raid1_retry_list; - *evms_raid1_retry_tail = r1_bh; - evms_raid1_retry_tail = &r1_bh->next_r1; - r1_bh->next_r1 = NULL; - md_spin_unlock_irqrestore(&retry_list_lock, flags); - evms_cs_wakeup_thread(conf->thread); -} - - -static void inline io_request_done(unsigned long sector, raid1_conf_t *conf, int phase) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector < conf->start_active) - conf->cnt_done--; - else if (sector >= conf->start_future && conf->phase == phase) - conf->cnt_future--; - else if (!--conf->cnt_pending) - wake_up(&conf->wait_ready); - - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - -static void inline sync_request_done (unsigned long sector, raid1_conf_t *conf) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector >= conf->start_ready) - --conf->cnt_ready; - else if (sector >= conf->start_active) { - if (!--conf->cnt_active) { - conf->start_active = conf->start_ready; - wake_up(&conf->wait_done); - } - } - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - -/* - * raid1_end_bh_io() is called when we have finished servicing a mirrored - * operation and are ready to return a success/failure code to the buffer - * cache layer. - */ -static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate) -{ - struct buffer_head *bh = r1_bh->master_bh; - - io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev), - test_bit(R1BH_SyncPhase, &r1_bh->state)); - - bh->b_end_io(bh, uptodate); - raid1_free_r1bh(r1_bh); -} - -void raid1_end_read_request (struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - evms_cs_volume_request_in_progress(r1_bh->master_bh->b_rdev, -1, NULL); - if (uptodate) { - set_bit (R1BH_Uptodate, &r1_bh->state); - raid1_end_bh_io(r1_bh, uptodate); - } else { - evms_md_error_dev(r1_bh->mddev, bh->b_dev); - LOG_ERROR("rescheduling block %lu\n", bh->b_blocknr); - raid1_reschedule_retry(r1_bh); - } -} - -void raid1_end_write_request (struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - - evms_cs_volume_request_in_progress(r1_bh->master_bh->b_rdev, -1, NULL); - if (!uptodate) - evms_md_error_dev(r1_bh->mddev, bh->b_dev); - else - set_bit (R1BH_Uptodate, &r1_bh->state); - - /* - * Let's see if all mirrored write operations have finished - * already. - */ - if (atomic_dec_and_test(&r1_bh->remaining)) - raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state)); -} - -/* - * This routine returns the disk from which the requested read should - * be done. It bookkeeps the last read position for every disk - * in array and when new read requests come, the disk which last - * position is nearest to the request, is chosen. - * - * TODO: now if there are 2 mirrors in the same 2 devices, performance - * degrades dramatically because position is mirror, not device based. - * This should be changed to be device based. Also atomic sequential - * reads should be somehow balanced. - */ - -static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh) -{ - int new_disk = conf->last_used; - const int sectors = bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - const unsigned long this_sector = bh->b_rsector; - int disk = new_disk; - unsigned long new_distance; - unsigned long current_distance; - - /* - * Check if it is sane at all to balance - */ - - if (conf->resync_mirrors || conf->mddev->recovery_running) - goto rb_out; - - - /* make sure that disk is operational */ - while( !conf->mirrors[new_disk].operational) { - if (new_disk <= 0) new_disk = conf->raid_disks; - new_disk--; - if (new_disk == disk) { - /* - * This means no working disk was found - * Nothing much to do, lets not change anything - * and hope for the best... - */ - - new_disk = conf->last_used; - - goto rb_out; - } - } - disk = new_disk; - /* now disk == new_disk == starting point for search */ - - /* - * Don't touch anything for sequential reads. - */ - - if (this_sector == conf->mirrors[new_disk].head_position) - goto rb_out; - - /* - * If reads have been done only on a single disk - * for a time, lets give another disk a change. - * This is for kicking those idling disks so that - * they would find work near some hotspot. - */ - - if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) { - conf->sect_count = 0; - - do { - if (new_disk<=0) - new_disk = conf->raid_disks; - new_disk--; - if (new_disk == disk) - break; - } while ((conf->mirrors[new_disk].write_only) || - (!conf->mirrors[new_disk].operational)); - - goto rb_out; - } - - current_distance = abs(this_sector - - conf->mirrors[disk].head_position); - - /* Find the disk which is closest */ - - do { - if (disk <= 0) - disk = conf->raid_disks; - disk--; - - if ((conf->mirrors[disk].write_only) || - (!conf->mirrors[disk].operational)) - continue; - - new_distance = abs(this_sector - - conf->mirrors[disk].head_position); - - if (new_distance < current_distance) { - conf->sect_count = 0; - current_distance = new_distance; - new_disk = disk; - } - } while (disk != conf->last_used); - -rb_out: - conf->mirrors[new_disk].head_position = this_sector + sectors; - - conf->last_used = new_disk; - conf->sect_count += sectors; - - return new_disk; -} - -static void raid1_read(struct evms_logical_node *md_node, struct buffer_head *bh) -{ - mddev_t *mddev = EVMS_MD_NODE_TO_MDDEV(md_node); - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info *mirror; - struct buffer_head *bh_req; - struct raid1_bh * r1_bh; - - if (evms_md_check_boundary(md_node, bh)) return; - - if (!buffer_locked(bh)) - BUG(); - - r1_bh = raid1_alloc_r1bh (conf); - - spin_lock_irq(&conf->segment_lock); - wait_event_lock_irq(conf->wait_done, - bh->b_rsector < conf->start_active || - bh->b_rsector >= conf->start_future, - conf->segment_lock); - if (bh->b_rsector < conf->start_active) - conf->cnt_done++; - else { - conf->cnt_future++; - if (conf->phase) - set_bit(R1BH_SyncPhase, &r1_bh->state); - } - spin_unlock_irq(&conf->segment_lock); - - r1_bh->mddev = mddev; - r1_bh->cmd = READ; - r1_bh->master_bh = bh; - - mirror = conf->mirrors + raid1_read_balance(conf, bh); - - bh_req = &r1_bh->bh_req; - memcpy(bh_req, bh, sizeof(*bh)); - bh_req->b_blocknr = bh->b_rsector; - bh_req->b_dev = mirror->dev; - bh_req->b_end_io = raid1_end_read_request; - bh_req->b_private = r1_bh; - evms_cs_volume_request_in_progress(bh->b_rdev, 1, NULL); - R_IO(mirror->node, bh_req); -} - -static void raid1_write( - struct evms_logical_node *md_node, - struct buffer_head *bh) -{ - mddev_t *mddev = EVMS_MD_NODE_TO_MDDEV(md_node); - raid1_conf_t *conf = mddev_to_conf(mddev); - struct raid1_bh * r1_bh; - struct buffer_head *bhl; - struct buffer_head *mbh; - int i, sum_bhs; - - if (evms_md_check_boundary(md_node, bh)) return; - - if (!buffer_locked(bh)) - BUG(); - - r1_bh = raid1_alloc_r1bh (conf); - - spin_lock_irq(&conf->segment_lock); - wait_event_lock_irq(conf->wait_done, - bh->b_rsector < conf->start_active || - bh->b_rsector >= conf->start_future, - conf->segment_lock); - if (bh->b_rsector < conf->start_active) - conf->cnt_done++; - else { - conf->cnt_future++; - if (conf->phase) - set_bit(R1BH_SyncPhase, &r1_bh->state); - } - spin_unlock_irq(&conf->segment_lock); - - /* - * i think the read and write branch should be separated completely, - * since we want to do read balancing on the read side for example. - * Alternative implementations? :) --mingo - */ - - r1_bh->mddev = mddev; - r1_bh->cmd = WRITE; - r1_bh->master_bh = bh; - - bhl = raid1_alloc_bh(conf, conf->raid_disks); - - for (i=0, sum_bhs=0; - (sum_bhs < conf->raid_disks) && (i < MD_SB_DISKS); - i++) { - if (!conf->mirrors[i].operational) - continue; - - /* - * We should use a private pool (size depending on NR_REQUEST), - * to avoid writes filling up the memory with bhs - * - * Such pools are much faster than kmalloc anyways (so we waste - * almost nothing by not using the master bh when writing and - * win alot of cleanness) but for now we are cool enough. --mingo - * - * It's safe to sleep here, buffer heads cannot be used in a shared - * manner in the write branch. Look how we lock the buffer at the - * beginning of this function to grok the difference ;) - */ - mbh = bhl; - if (mbh == NULL) { - MD_BUG(); - break; - } - bhl = mbh->b_next; - mbh->b_next = NULL; - mbh->b_this_page = (struct buffer_head *)1; - - /* - * prepare mirrored mbh (fields ordered for max mem throughput): - */ - mbh->b_blocknr = bh->b_rsector; - mbh->b_rdev = bh->b_rdev; - mbh->b_dev = conf->mirrors[i].dev; - mbh->b_rsector = bh->b_rsector; - mbh->b_state = (1<b_count, 1); - mbh->b_size = bh->b_size; - mbh->b_page = bh->b_page; - mbh->b_data = bh->b_data; - mbh->b_list = BUF_LOCKED; - mbh->b_end_io = raid1_end_write_request; - mbh->b_private = conf->mirrors[i].node; - - mbh->b_next = r1_bh->mirror_bh_list; - r1_bh->mirror_bh_list = mbh; - sum_bhs++; - } - - if (bhl) raid1_free_bh(conf,bhl); - if (!sum_bhs) { - /* Gag - all mirrors non-operational.. */ - raid1_end_bh_io(r1_bh, 0); - return; - } - atomic_set(&r1_bh->remaining, sum_bhs); - - /* - * We have to be a bit careful about the semaphore above, thats - * why we start the requests separately. Since kmalloc() could - * fail, sleep and make_request() can sleep too, this is the - * safer solution. Imagine, end_request decreasing the semaphore - * before we could have set it up ... We could play tricks with - * the semaphore (presetting it and correcting at the end if - * sum_bhs is not 'n' but we have to do end_request by hand if - * all requests finish until we had a chance to set up the - * semaphore correctly ... lots of races). - */ - bhl = r1_bh->mirror_bh_list; - while(bhl) { - struct evms_logical_node *node; - - mbh = bhl; - bhl = mbh->b_next; - node = (struct evms_logical_node *)mbh->b_private; - mbh->b_private = r1_bh; - - evms_cs_volume_request_in_progress(mbh->b_rdev, 1, NULL); - W_IO(node, mbh); - } -} - - -static int raid1_status (char *page, mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - int sz = 0, i; - - sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, - conf->working_disks); - for (i = 0; i < conf->raid_disks; i++) - sz += sprintf (page+sz, "%s", - conf->mirrors[i].operational ? "U" : "_"); - sz += sprintf (page+sz, "]"); - return sz; -} - -#define LAST_DISK \ -"only one disk left and IO error.\n" - -#define NO_SPARE_DISK \ -"no spare disk left, degrading mirror level by one.\n" - -#define DISK_FAILED \ -"disk failure on %s, disabling device. \n" \ -" Operation continuing on %d devices\n" - -#define START_SYNCING \ -"start syncing spare disk.\n" - -#define ALREADY_SYNCING \ -"syncing already in progress.\n" - -static void mark_disk_bad (mddev_t *mddev, int failed) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info *mirror = conf->mirrors+failed; - mdp_super_t *sb = mddev->sb; - - mirror->operational = 0; - mark_disk_faulty(sb->disks+mirror->number); - mark_disk_nonsync(sb->disks+mirror->number); - mark_disk_inactive(sb->disks+mirror->number); - if (!mirror->write_only) - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; - mddev->sb_dirty = 1; - evms_cs_wakeup_thread(conf->thread); - if (!mirror->write_only) - conf->working_disks--; - LOG_SERIOUS(DISK_FAILED, evms_md_partition_name(mirror->node),conf->working_disks); -} - -static int raid1_error ( - mddev_t *mddev, - struct evms_logical_node *node) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info * mirrors = conf->mirrors; - int disks = MD_SB_DISKS; - int i; - - /* Find the drive. - * If it is not operational, then we have already marked it as dead - * else if it is the last working disks, ignore the error, let the - * next level up know. - * else mark the drive as failed - */ - - for (i = 0; i < disks; i++) - if (mirrors[i].node==node && mirrors[i].operational) - break; - if (i == disks) - return 0; - - if (i < conf->raid_disks && conf->working_disks == 1) { - /* Don't fail the drive, act as though we were just a - * normal single drive - */ - - return 1; - } - mark_disk_bad(mddev, i); - return 0; -} - -#undef LAST_DISK -#undef NO_SPARE_DISK -#undef DISK_FAILED -#undef START_SYNCING - - -static void print_raid1_conf (raid1_conf_t *conf) -{ - int i; - struct mirror_info *tmp; - - LOG_DEFAULT("RAID1 conf printout:\n"); - if (!conf) { - LOG_DEFAULT("(conf==NULL)\n"); - return; - } - LOG_DEFAULT(" --- wd:%d rd:%d nd:%d\n", - conf->working_disks,conf->raid_disks, conf->nr_disks); - - for (i = 0; i < conf->nr_disks; i++) { - tmp = conf->mirrors + i; - LOG_DEFAULT(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", - i, tmp->spare,tmp->operational, - tmp->number,tmp->raid_disk,tmp->used_slot, - evms_md_partition_name(tmp->node)); - } -} - -static void close_sync(raid1_conf_t *conf) -{ - mddev_t *mddev = conf->mddev; - /* If reconstruction was interrupted, we need to close the "active" and "pending" - * holes. - * we know that there are no active rebuild requests, os cnt_active == cnt_ready ==0 - */ - /* this is really needed when recovery stops too... */ - spin_lock_irq(&conf->segment_lock); - conf->start_active = conf->start_pending; - conf->start_ready = conf->start_pending; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active =conf->start_ready = conf->start_pending = conf->start_future; - conf->start_future = mddev->sb->size+1; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - conf->phase = conf->phase ^1; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0; - conf->phase = 0; - conf->cnt_future = conf->cnt_done;; - conf->cnt_done = 0; - spin_unlock_irq(&conf->segment_lock); - wake_up(&conf->wait_done); -} - -static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state) -{ - int err = 0; - int i, failed_disk=-1, spare_disk=-1, removed_disk=-1; - raid1_conf_t *conf = mddev->private; - struct mirror_info *tmp, *sdisk, *fdisk, *rdisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc; - mdk_rdev_t *spare_rdev, *failed_rdev; - - print_raid1_conf(conf); - md_spin_lock_irq(&conf->device_lock); - /* - * find the disk ... - */ - switch (state) { - - case DISKOP_SPARE_ACTIVE: - - /* - * Find the failed disk within the RAID1 configuration ... - * (this can only be in the first conf->working_disks part) - */ - for (i = 0; i < conf->raid_disks; i++) { - tmp = conf->mirrors + i; - if ((!tmp->operational && !tmp->spare) || - !tmp->used_slot) { - failed_disk = i; - break; - } - } - /* - * When we activate a spare disk we _must_ have a disk in - * the lower (active) part of the array to replace. - */ -/* if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - */ /* fall through */ - - case DISKOP_HOT_SPARE_ACTIVE: - case DISKOP_SPARE_WRITE: - case DISKOP_SPARE_INACTIVE: - - /* - * Find the spare disk ... (can only be in the 'high' - * area of the array) - ##### Actually it can be sooner now that we have improved MD ##### - This support required for expanding number of active mirrors. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_REMOVE_SPARE: - - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (tmp->used_slot && (tmp->number == (*d)->number)) { - if (tmp->operational) { - err = -EBUSY; - goto abort; - } else if (!tmp->spare){ - MD_BUG(); - err = 1; - goto abort; - } - removed_disk = i; - break; - } - } - if (removed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_REMOVE_DISK: - if (conf->working_disks <= 1) { - err = -EBUSY; - goto abort; - } - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (tmp->used_slot && (tmp->number == (*d)->number)) { - removed_disk = i; - break; - } - } - if (removed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_ADD_DISK: - err = -ENOSYS; - goto abort; - break; - } - - switch (state) { - /* - * Switch the spare disk to write-only mode: - */ - case DISKOP_SPARE_WRITE: - sdisk = conf->mirrors + spare_disk; - sdisk->operational = 1; - sdisk->write_only = 1; - break; - /* - * Deactivate a spare disk: - */ - case DISKOP_SPARE_INACTIVE: - close_sync(conf); - sdisk = conf->mirrors + spare_disk; - sdisk->operational = 0; - sdisk->write_only = 0; - break; - /* - * Activate (mark read-write) the (now sync) spare disk, - * which means we switch it's 'raid position' (->raid_disk) - * with the failed disk. (only the first 'conf->nr_disks' - * slots are used for 'real' disks and we must preserve this - * property) - */ - case DISKOP_SPARE_ACTIVE: - close_sync(conf); - sdisk = conf->mirrors + spare_disk; - if (failed_disk < 0) { - // preset failed disk to itself if no failed disk. - failed_disk = spare_disk; - // try to find spare earlier in array - for (i = conf->raid_disks; i < spare_disk; i++) { - tmp = conf->mirrors + i; - if ((tmp->spare) || !tmp->used_slot) { - failed_disk = i; - break; - } - } - } - fdisk = conf->mirrors + failed_disk; - - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if (spare_desc != *d) { - MD_BUG(); - err = 1; - goto abort; - } - - if (spare_desc->raid_disk != sdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (sdisk->raid_disk != spare_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (fdisk->raid_disk != failed_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - /* - * do the switch finally - */ - spare_rdev = evms_md_find_rdev_nr(mddev, spare_desc->number); - failed_rdev = evms_md_find_rdev_nr(mddev, failed_desc->number); - - /* There must be a spare_rdev, but there may not be a - * failed_rdev. That slot might be empty... - */ - spare_rdev->desc_nr = failed_desc->number; - if (failed_rdev) - failed_rdev->desc_nr = spare_desc->number; - - xchg_values(*spare_desc, *failed_desc); - xchg_values(*fdisk, *sdisk); - - /* - * (careful, 'failed' and 'spare' are switched from now on) - * - * we want to preserve linear numbering and we want to - * give the proper raid_disk number to the now activated - * disk. (this means we switch back these values) - */ - - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); - xchg_values(sdisk->number, fdisk->number); - - *d = failed_desc; - - if (sdisk->dev == MKDEV(0,0)) - sdisk->used_slot = 0; - /* - * this really activates the spare. - */ - fdisk->spare = 0; - fdisk->write_only = 0; - - /* - * if we activate a spare, we definitely replace a - * non-operational disk slot in the 'low' area of - * the disk array. - */ - - conf->working_disks++; - - break; - - /* Activate a spare disk without a failed disk */ - case DISKOP_HOT_SPARE_ACTIVE: - sdisk = conf->mirrors + spare_disk; - sdisk->spare = 0; - sdisk->write_only = 0; - conf->working_disks++; - conf->raid_disks++; - if (raid1_grow_bh(conf, NR_RESERVED_BUFS) < NR_RESERVED_BUFS) - LOG_WARNING("%s: Cannot grow BH pool\n", __FUNCTION__); - break; - - case DISKOP_HOT_REMOVE_SPARE: - rdisk = conf->mirrors + removed_disk; - - if (removed_disk < conf->raid_disks) { - MD_BUG(); - err = 1; - goto abort; - } - - LOG_WARNING("%s: removing spare %s, [md%d] nr_disks=%d\n", - __FUNCTION__, evms_md_partition_name(rdisk->node), - conf->mddev->__minor, conf->nr_disks-1); - - rdisk->dev = MKDEV(0,0); - rdisk->node = NULL; - rdisk->used_slot = 0; - conf->nr_disks--; - break; - - case DISKOP_HOT_REMOVE_DISK: - rdisk = conf->mirrors + removed_disk; - - LOG_WARNING("%s: removing active disk %s, [md%d] nr_disks=%d\n", - __FUNCTION__, evms_md_partition_name(rdisk->node), - conf->mddev->__minor, conf->nr_disks-1); - - rdisk->dev = MKDEV(0,0); - rdisk->node = NULL; - rdisk->used_slot = 0; - rdisk->operational = 0; - conf->working_disks--; - conf->nr_disks--; - sb->raid_disks--; //decrement raid disks. md_core now increments - //when activating new spare, don't assume add spare here - break; - default: - MD_BUG(); - err = 1; - goto abort; - } -abort: - md_spin_unlock_irq(&conf->device_lock); - if (state == DISKOP_SPARE_ACTIVE || state == DISKOP_SPARE_INACTIVE) - /* should move to "END_REBUILD" when such exists */ - raid1_shrink_buffers(conf); - - print_raid1_conf(conf); - return err; -} - - -#define IO_ERROR \ -"%s: unrecoverable I/O read error for block %lu\n" - -#define REDIRECT_SECTOR \ -"%s: redirecting sector %lu to another mirror\n" - -/* - * This is a kernel thread which: - * - * 1. Retries failed read operations on working mirrors. - * 2. Updates the raid superblock when problems encounter. - * 3. Performs writes following reads for array syncronising. - */ -static void end_sync_write(struct buffer_head *bh, int uptodate); -static void end_sync_read(struct buffer_head *bh, int uptodate); - -static void raid1d (void *data) -{ - struct raid1_bh *r1_bh; - struct buffer_head *bh; - unsigned long flags; - mddev_t *mddev; - mdk_rdev_t *rdev; - kdev_t dev; - struct evms_logical_node *node; - raid1_conf_t *conf = (raid1_conf_t *) data; - - for (;;) { - mddev = conf->mddev; - if (mddev->sb_dirty) { - LOG_DEFAULT("dirty sb detected, updating.\n"); - mddev->sb_dirty = 0; - evms_md_update_sb(mddev); - } - md_spin_lock_irqsave(&retry_list_lock, flags); - r1_bh = evms_raid1_retry_list; - if (!r1_bh) - break; - evms_raid1_retry_list = r1_bh->next_r1; - md_spin_unlock_irqrestore(&retry_list_lock, flags); - - mddev = r1_bh->mddev; - bh = &r1_bh->bh_req; - switch(r1_bh->cmd) { - case SPECIAL: - /* have to allocate lots of bh structures and - * schedule writes - */ - if (test_bit(R1BH_Uptodate, &r1_bh->state)) { - int i, sum_bhs = 0; - int disks = MD_SB_DISKS; - struct buffer_head *bhl, *mbh; - - conf = mddev_to_conf(mddev); - bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */ - if (r1_bh->mirror_bh_list) { - MD_BUG(); - r1_bh->mirror_bh_list = NULL; - } - for (i = 0; i < disks ; i++) { - if (!conf->mirrors[i].operational) - continue; - if (i==conf->last_used) - /* we read from here, no need to write */ - continue; - if (i < conf->raid_disks - && !conf->resync_mirrors - && !conf->mirrors[i].write_only) - /* don't need to write this, - * we are just rebuilding */ - continue; - mbh = bhl; - if (!mbh) { - MD_BUG(); - break; - } - bhl = mbh->b_next; - mbh->b_this_page = (struct buffer_head *)1; - - - /* - * prepare mirrored bh (fields ordered for max mem throughput): - */ - mbh->b_blocknr = bh->b_blocknr; - mbh->b_dev = conf->mirrors[i].dev; - mbh->b_rsector = bh->b_blocknr; - mbh->b_state = (1<b_count, 1); - mbh->b_size = bh->b_size; - mbh->b_page = bh->b_page; - mbh->b_data = bh->b_data; - mbh->b_list = BUF_LOCKED; - mbh->b_end_io = end_sync_write; - mbh->b_private = conf->mirrors[i].node; - - mbh->b_next = r1_bh->mirror_bh_list; - r1_bh->mirror_bh_list = mbh; - - sum_bhs++; - } - atomic_set(&r1_bh->remaining, sum_bhs); - if (bhl) raid1_free_bh(conf, bhl); - - if (!sum_bhs) { - /* nowhere to write this too... I guess we - * must be done - */ - sync_request_done(bh->b_blocknr, conf); - evms_md_done_sync(mddev, - bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT, - 0); - raid1_free_buf(r1_bh); - } else { - for (mbh = r1_bh->mirror_bh_list; mbh; mbh = bhl) { - bhl = mbh->b_next; - - node = (struct evms_logical_node *)mbh->b_private; - mbh->b_private = r1_bh; - evms_md_sync_acct(mbh->b_dev, - bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT); - W_IO(node, mbh); - } - } - } else { - /* There is no point trying a read-for-reconstruct - * as reconstruct is about to be aborted - */ - rdev = evms_md_find_rdev(mddev,bh->b_dev); - if (rdev) - LOG_ERROR(IO_ERROR, - evms_md_partition_name(rdev->node), - bh->b_blocknr); - evms_md_done_sync(mddev, bh->b_size>>EVMS_VSECTOR_SIZE_SHIFT, 0); - } - - break; - case READ: - case READA: - - dev = bh->b_dev; - evms_raid1_map(mddev, &node, &bh->b_dev); - if (bh->b_dev == dev) { - rdev = evms_md_find_rdev(mddev,dev); - if (rdev) - LOG_ERROR(" unrecoverable read error on %s at LBA(%lu)\n", - evms_md_partition_name(rdev->node), - r1_bh->master_bh->b_rsector); - raid1_end_bh_io(r1_bh, 0); - } else { - /* retry I/O on new device */ - bh->b_rdev = r1_bh->master_bh->b_rdev; - bh->b_rsector = bh->b_blocknr; - evms_cs_volume_request_in_progress(r1_bh->master_bh->b_rdev, 1, NULL); - R_IO(node, bh); - } - break; - } - } - md_spin_unlock_irqrestore(&retry_list_lock, flags); -} -#undef IO_ERROR -#undef REDIRECT_SECTOR - -/* - * Private kernel thread to reconstruct mirrors after an unclean - * shutdown. - */ -static void raid1syncd (void *data) -{ - raid1_conf_t *conf = data; - mddev_t *mddev = conf->mddev; - - if (!conf->resync_mirrors) - return; - if (conf->resync_mirrors == 2) - return; - down(&mddev->recovery_sem); - if (!evms_md_do_sync(mddev, NULL)) { - /* - * Only if everything went Ok. - */ - conf->resync_mirrors = 0; - } - - close_sync(conf); - - up(&mddev->recovery_sem); - raid1_shrink_buffers(conf); -} - -/* - * perform a "sync" on one "block" - * - * We need to make sure that no normal I/O request - particularly write - * requests - conflict with active sync requests. - * This is achieved by conceptually dividing the device space into a - * number of sections: - * DONE: 0 .. a-1 These blocks are in-sync - * ACTIVE: a.. b-1 These blocks may have active sync requests, but - * no normal IO requests - * READY: b .. c-1 These blocks have no normal IO requests - sync - * request may be happening - * PENDING: c .. d-1 These blocks may have IO requests, but no new - * ones will be added - * FUTURE: d .. end These blocks are not to be considered yet. IO may - * be happening, but not sync - * - * We keep a - * phase which flips (0 or 1) each time d moves and - * a count of: - * z = active io requests in FUTURE since d moved - marked with - * current phase - * y = active io requests in FUTURE before d moved, or PENDING - - * marked with previous phase - * x = active sync requests in READY - * w = active sync requests in ACTIVE - * v = active io requests in DONE - * - * Normally, a=b=c=d=0 and z= active io requests - * or a=b=c=d=END and v= active io requests - * Allowed changes to a,b,c,d: - * A: c==d && y==0 -> d+=window, y=z, z=0, phase=!phase - * B: y==0 -> c=d - * C: b=c, w+=x, x=0 - * D: w==0 -> a=b - * E: a==b==c==d==end -> a=b=c=d=0, z=v, v=0 - * - * At start of sync we apply A. - * When y reaches 0, we apply B then A then being sync requests - * When sync point reaches c-1, we wait for y==0, and W==0, and - * then apply apply B then A then D then C. - * Finally, we apply E - * - * The sync request simply issues a "read" against a working drive - * This is marked so that on completion the raid1d thread is woken to - * issue suitable write requests - */ - -static int raid1_sync_request (mddev_t *mddev, unsigned long sector_nr) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info *mirror; - struct raid1_bh *r1_bh; - struct buffer_head *bh; - int bsize; - int disk; - int block_nr; - - spin_lock_irq(&conf->segment_lock); - if (!sector_nr) { - /* initialize ...*/ - int buffs; - conf->start_active = 0; - conf->start_ready = 0; - conf->start_pending = 0; - conf->start_future = 0; - conf->phase = 0; - /* we want enough buffers to hold twice the window of 128*/ - buffs = 128 *2 / (PAGE_SIZE>>9); - buffs = raid1_grow_buffers(conf, buffs); - if (buffs < 2) - goto nomem; - - conf->window = buffs*(PAGE_SIZE>>9)/2; - conf->cnt_future += conf->cnt_done+conf->cnt_pending; - conf->cnt_done = conf->cnt_pending = 0; - if (conf->cnt_ready || conf->cnt_active) - MD_BUG(); - } - while (sector_nr >= conf->start_pending) { - PRINTK("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n", - sector_nr, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, - conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future); - wait_event_lock_irq(conf->wait_done, - !conf->cnt_active, - conf->segment_lock); - wait_event_lock_irq(conf->wait_ready, - !conf->cnt_pending, - conf->segment_lock); - conf->start_active = conf->start_ready; - conf->start_ready = conf->start_pending; - conf->start_pending = conf->start_future; - conf->start_future = conf->start_future+conf->window; - // Note: falling off the end is not a problem - conf->phase = conf->phase ^1; - conf->cnt_active = conf->cnt_ready; - conf->cnt_ready = 0; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - wake_up(&conf->wait_done); - } - conf->cnt_ready++; - spin_unlock_irq(&conf->segment_lock); - - - /* If reconstructing, and >1 working disc, - * could dedicate one to rebuild and others to - * service read requests .. - */ - disk = conf->last_used; - /* make sure disk is operational */ - while (!conf->mirrors[disk].operational) { - if (disk <= 0) disk = conf->raid_disks; - disk--; - if (disk == conf->last_used) - break; - } - conf->last_used = disk; - - mirror = conf->mirrors+conf->last_used; - - r1_bh = raid1_alloc_buf (conf); - r1_bh->mddev = mddev; - r1_bh->cmd = SPECIAL; - bh = &r1_bh->bh_req; - - block_nr = sector_nr; - bsize = 512; - while (!(block_nr & 1) && bsize < PAGE_SIZE - && (block_nr+2)*(bsize>>9) <= (mddev->sb->size *2)) { - block_nr >>= 1; - bsize <<= 1; - } - bh->b_size = bsize; - bh->b_list = BUF_LOCKED; - bh->b_dev = mirror->dev; - bh->b_state = (1<b_page) - BUG(); - if (!bh->b_data) - BUG(); - if (bh->b_data != page_address(bh->b_page)) - BUG(); - bh->b_end_io = end_sync_read; - bh->b_private = r1_bh; - bh->b_blocknr = sector_nr; - bh->b_rsector = sector_nr; - init_waitqueue_head(&bh->b_wait); - - R_IO(mirror->node, bh); - evms_md_sync_acct(bh->b_dev, bsize/512); - - return (bsize >> 9); - -nomem: - raid1_shrink_buffers(conf); - spin_unlock_irq(&conf->segment_lock); - return -ENOMEM; -} - -static void end_sync_read(struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - - /* we have read a block, now it needs to be re-written, - * or re-read if the read failed. - * We don't do much here, just schedule handling by raid1d - */ - if (!uptodate) - evms_md_error_dev(r1_bh->mddev, bh->b_dev); - else - set_bit(R1BH_Uptodate, &r1_bh->state); - raid1_reschedule_retry(r1_bh); -} - -static void end_sync_write(struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - - if (!uptodate) - evms_md_error_dev(r1_bh->mddev, bh->b_dev); - if (atomic_dec_and_test(&r1_bh->remaining)) { - mddev_t *mddev = r1_bh->mddev; - unsigned long sect = bh->b_blocknr; - int size = bh->b_size; - - raid1_free_buf(r1_bh); - sync_request_done(sect, mddev_to_conf(mddev)); - evms_md_done_sync(mddev, size>>EVMS_VSECTOR_SIZE_SHIFT, uptodate); - } -} - -#define INVALID_LEVEL \ -"md%d: raid level not set to mirroring (%d)\n" - -#define NO_SB \ -"disabled mirror %s (couldn't access raid superblock)\n" - -#define ERRORS \ -"disabled mirror %s (errors detected)\n" - -#define NOT_IN_SYNC \ -"disabled mirror %s (not in sync)\n" - -#define INCONSISTENT \ -"disabled mirror %s (inconsistent descriptor)\n" - -#define ALREADY_RUNNING \ -"disabled mirror %s (mirror %d already operational)\n" - -#define OPERATIONAL \ -"device %s operational as mirror %d\n" - -#define MEM_ERROR \ -"couldn't allocate memory for md%d\n" - -#define SPARE \ -"spare disk %s\n" - -#define NONE_OPERATIONAL \ -"no operational mirrors for md%d\n" - -#define ARRAY_IS_ACTIVE \ -"raid set md%d active with %d out of %d mirrors\n" - -#define THREAD_ERROR \ -"couldn't allocate thread for md%d\n" - -#define START_RESYNC \ -"raid set md%d not clean; reconstructing mirrors\n" - -static int raid1_run (mddev_t *mddev) -{ - raid1_conf_t *conf; - int i, j, disk_idx; - struct mirror_info *disk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *descriptor; - mdk_rdev_t *rdev; - struct md_list_head *tmp; - int start_recovery = 0; - - MOD_INC_USE_COUNT; - - LOG_EXTRA("%s ENTRY\n", __FUNCTION__); - if (sb->level != 1) { - LOG_ERROR(INVALID_LEVEL, mdidx(mddev), sb->level); - goto out; - } - /* - * copy the already verified devices into our private RAID1 - * bookkeeping area. [whatever we allocate in raid1_run(), - * should be freed in raid1_stop()] - */ - - conf = kmalloc(sizeof(raid1_conf_t), GFP_KERNEL); - mddev->private = conf; - if (!conf) { - LOG_ERROR(MEM_ERROR, mdidx(mddev)); - goto out; - } - memset(conf, 0, sizeof(*conf)); - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) { - LOG_ERROR(ERRORS, evms_md_partition_name(rdev->node)); - } else { - if (!rdev->sb) { - MD_BUG(); - continue; - } - } - if (rdev->desc_nr == -1) { - MD_BUG(); - continue; - } - descriptor = &sb->disks[rdev->desc_nr]; - disk_idx = descriptor->raid_disk; - disk = conf->mirrors + disk_idx; - - if (disk_faulty(descriptor)) { - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->node = rdev->node; - disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - disk->head_position = 0; - continue; - } - if (disk_active(descriptor)) { - if (!disk_sync(descriptor)) { - LOG_ERROR(NOT_IN_SYNC, evms_md_partition_name(rdev->node)); - continue; - } - if ((descriptor->number > MD_SB_DISKS) || - (disk_idx > sb->raid_disks)) { - - LOG_ERROR(INCONSISTENT,evms_md_partition_name(rdev->node)); - continue; - } - if (disk->operational) { - LOG_ERROR(ALREADY_RUNNING, evms_md_partition_name(rdev->node), disk_idx); - continue; - } - LOG_DEFAULT(OPERATIONAL, evms_md_partition_name(rdev->node), disk_idx); - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->node = rdev->node; - disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; - disk->operational = 1; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - disk->head_position = 0; - conf->working_disks++; - } else { - /* - * Must be a spare disk .. - */ - LOG_DEFAULT(SPARE, evms_md_partition_name(rdev->node)); - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->node = rdev->node; - disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; - disk->operational = 0; - disk->write_only = 0; - disk->spare = 1; - disk->used_slot = 1; - disk->head_position = 0; - } - } - conf->raid_disks = sb->raid_disks; - conf->nr_disks = sb->nr_disks; - conf->mddev = mddev; - conf->device_lock = MD_SPIN_LOCK_UNLOCKED; - - conf->segment_lock = MD_SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&conf->wait_buffer); - init_waitqueue_head(&conf->wait_done); - init_waitqueue_head(&conf->wait_ready); - - if (!conf->working_disks) { - LOG_ERROR(NONE_OPERATIONAL, mdidx(mddev)); - goto out_free_conf; - } - - - /* pre-allocate some buffer_head structures. - * As a minimum, 1 r1bh and raid_disks buffer_heads - * would probably get us by in tight memory situations, - * but a few more is probably a good idea. - * For now, try NR_RESERVED_BUFS r1bh and - * NR_RESERVED_BUFS*raid_disks bufferheads - * This will allow at least NR_RESERVED_BUFS concurrent - * reads or writes even if kmalloc starts failing - */ - if (raid1_grow_r1bh(conf, NR_RESERVED_BUFS) < NR_RESERVED_BUFS || - raid1_grow_bh(conf, NR_RESERVED_BUFS*conf->raid_disks) - < NR_RESERVED_BUFS*conf->raid_disks) { - LOG_ERROR(MEM_ERROR, mdidx(mddev)); - goto out_free_conf; - } - - for (i = 0; i < MD_SB_DISKS; i++) { - - descriptor = sb->disks+i; - disk_idx = descriptor->raid_disk; - disk = conf->mirrors + disk_idx; - - if (disk_faulty(descriptor) && (disk_idx < conf->raid_disks) && - !disk->used_slot) { - - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->dev = MKDEV(0,0); - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - disk->head_position = 0; - } - } - - /* - * find the first working one and use it as a starting point - * to read balancing. - */ - for (j = 0; !conf->mirrors[j].operational && j < MD_SB_DISKS; j++) - /* nothing */; - conf->last_used = j; - - - if (conf->working_disks != sb->raid_disks) { - LOG_SERIOUS(" md%d, not all disks are operational -- trying to recover array\n", - mdidx(mddev)); - start_recovery = 1; - } - - { - const char * name = "evms_raid1d"; - - conf->thread = evms_cs_register_thread(raid1d, conf, name); - if (!conf->thread) { - LOG_ERROR(THREAD_ERROR, mdidx(mddev)); - goto out_free_conf; - } - } - - if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN)) && - (conf->working_disks > 1)) { - const char * name = "evms_raid1syncd"; - - conf->resync_thread = evms_cs_register_thread(raid1syncd, conf,name); - if (!conf->resync_thread) { - LOG_ERROR(THREAD_ERROR, mdidx(mddev)); - goto out_free_conf; - } - - LOG_WARNING(START_RESYNC, mdidx(mddev)); - conf->resync_mirrors = 1; - evms_cs_wakeup_thread(conf->resync_thread); - } - - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mark_disk_nonsync(sb->disks+i); - for (j = 0; j < sb->raid_disks; j++) { - if (!conf->mirrors[j].operational) - continue; - if (sb->disks[i].number == conf->mirrors[j].number) - mark_disk_sync(sb->disks+i); - } - } - sb->active_disks = conf->working_disks; - - if (start_recovery) - evms_md_recover_arrays(); - - - LOG_DEFAULT(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks); - /* - * Ok, everything is just fine now - */ - return 0; - -out_free_conf: - raid1_shrink_r1bh(conf); - raid1_shrink_bh(conf); - raid1_shrink_buffers(conf); - kfree(conf); - mddev->private = NULL; -out: - MOD_DEC_USE_COUNT; - return -EIO; -} - -#undef INVALID_LEVEL -#undef NO_SB -#undef ERRORS -#undef NOT_IN_SYNC -#undef INCONSISTENT -#undef ALREADY_RUNNING -#undef OPERATIONAL -#undef SPARE -#undef NONE_OPERATIONAL -#undef ARRAY_IS_ACTIVE - -static int raid1_stop_resync (mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - - LOG_EXTRA("%s ENTRY\n", __FUNCTION__); - if (conf->resync_thread) { - if (conf->resync_mirrors) { - conf->resync_mirrors = 2; - evms_cs_interrupt_thread(conf->resync_thread); - LOG_WARNING(" mirror resync was not fully finished, restarting next time.\n"); - return 1; - } - return 0; - } - return 0; -} - -static int raid1_restart_resync (mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - - LOG_EXTRA("%s ENTRY\n", __FUNCTION__); - if (conf->resync_mirrors) { - if (!conf->resync_thread) { - MD_BUG(); - return 0; - } - conf->resync_mirrors = 1; - evms_cs_wakeup_thread(conf->resync_thread); - return 1; - } - return 0; -} - -static int raid1_stop (mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - - LOG_EXTRA("%s ENTRY\n", __FUNCTION__); - evms_cs_unregister_thread(conf->thread); - if (conf->resync_thread) - evms_cs_unregister_thread(conf->resync_thread); - raid1_shrink_r1bh(conf); - raid1_shrink_bh(conf); - raid1_shrink_buffers(conf); - kfree(conf); - mddev->private = NULL; - MOD_DEC_USE_COUNT; - return 0; -} - -static int raid1_evms_ioctl ( - mddev_t * mddev, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - int i, rc = 0; - struct evms_logical_node *node = NULL; - raid1_conf_t *conf = mddev_to_conf(mddev); - - switch (cmd) { - case EVMS_GET_BMAP: - { - for (i = 0; i < MD_SB_DISKS; i++) { - if (conf->mirrors[i].operational) { - node = conf->mirrors[i].node; - break; - } - } - - if (node) - rc = IOCTL(node, inode, file, cmd, arg); - else - rc = -ENODEV; - - break; - } - - default: - rc = -EINVAL; - } - return rc; -} - -static mdk_personality_t raid1_personality = { - .name = "evms_raid1", - .read = raid1_read, - .write = raid1_write, - .run = raid1_run, - .stop = raid1_stop, - .status = raid1_status, - .error_handler = raid1_error, - .diskop = raid1_diskop, - .stop_resync = raid1_stop_resync, - .restart_resync = raid1_restart_resync, - .sync_request = raid1_sync_request, - .evms_ioctl = raid1_evms_ioctl -}; - -static int md__init raid1_init (void) -{ - return evms_register_md_personality (RAID1, &raid1_personality); -} - -static void raid1_exit (void) -{ - evms_unregister_md_personality (RAID1); -} - -module_init(raid1_init); -module_exit(raid1_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_raid5.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_raid5.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_raid5.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_raid5.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,2283 +0,0 @@ -/* - * md_raid5.c : Multiple Devices driver for Linux - * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman - * Copyright (C) 1999, 2000 Ingo Molnar - * - * RAID-5 management functions. - * - * 'md_raid5.c' is an EVMS version of linux/drivers/md/raid5.c modified - * by Cuong (Mike) Tran , January 2002. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define LOG_PREFIX "md raid5: " - -static mdk_personality_t raid5_personality; - -/* - * Stripe cache - */ - -#define NR_STRIPES 256 -#define IO_THRESHOLD 1 -#define HASH_PAGES 1 -#define HASH_PAGES_ORDER 0 -#define NR_HASH (HASH_PAGES * PAGE_SIZE / sizeof(struct stripe_head *)) -#define HASH_MASK (NR_HASH - 1) -#define stripe_hash(conf, sect) ((conf)->stripe_hashtbl[((sect) / ((conf)->buffer_size >> 9)) & HASH_MASK]) - -/* - * The following can be used to debug the driver - */ -#define RAID5_DEBUG 0 -#define RAID5_PARANOIA 1 -#if RAID5_PARANOIA && CONFIG_SMP -#define CHECK_DEVLOCK() if (!spin_is_locked(&conf->device_lock)) BUG() -#else -#define CHECK_DEVLOCK() -#endif - -static void print_raid5_conf(raid5_conf_t * conf); - -static inline void -__release_stripe(raid5_conf_t * conf, struct stripe_head *sh) -{ - if (atomic_dec_and_test(&sh->count)) { - if (!list_empty(&sh->lru)) - BUG(); - if (atomic_read(&conf->active_stripes) == 0) - BUG(); - if (test_bit(STRIPE_HANDLE, &sh->state)) { - if (test_bit(STRIPE_DELAYED, &sh->state)) - list_add_tail(&sh->lru, &conf->delayed_list); - else - list_add_tail(&sh->lru, &conf->handle_list); - evms_cs_wakeup_thread(conf->thread); - } else { - if (test_and_clear_bit - (STRIPE_PREREAD_ACTIVE, &sh->state)) { - atomic_dec(&conf->preread_active_stripes); - if (atomic_read(&conf->preread_active_stripes) < - IO_THRESHOLD) - evms_cs_wakeup_thread(conf->thread); - } - list_add_tail(&sh->lru, &conf->inactive_list); - atomic_dec(&conf->active_stripes); - if (!conf->inactive_blocked || - atomic_read(&conf->active_stripes) < - (NR_STRIPES * 3 / 4)) - wake_up(&conf->wait_for_stripe); - } - } -} -static void -release_stripe(struct stripe_head *sh) -{ - raid5_conf_t *conf = sh->raid_conf; - unsigned long flags; - - spin_lock_irqsave(&conf->device_lock, flags); - __release_stripe(conf, sh); - spin_unlock_irqrestore(&conf->device_lock, flags); -} - -static void -remove_hash(struct stripe_head *sh) -{ - - if (sh->hash_pprev) { - if (sh->hash_next) - sh->hash_next->hash_pprev = sh->hash_pprev; - *sh->hash_pprev = sh->hash_next; - sh->hash_pprev = NULL; - } -} - -static __inline__ void -insert_hash(raid5_conf_t * conf, struct stripe_head *sh) -{ - struct stripe_head **shp = &stripe_hash(conf, sh->sector); - - CHECK_DEVLOCK(); - if ((sh->hash_next = *shp) != NULL) - (*shp)->hash_pprev = &sh->hash_next; - *shp = sh; - sh->hash_pprev = shp; -} - -/* find an idle stripe, make sure it is unhashed, and return it. */ -static struct stripe_head * -get_free_stripe(raid5_conf_t * conf) -{ - struct stripe_head *sh = NULL; - struct list_head *first; - - CHECK_DEVLOCK(); - if (list_empty(&conf->inactive_list)) - goto out; - first = conf->inactive_list.next; - sh = list_entry(first, struct stripe_head, lru); - list_del_init(first); - remove_hash(sh); - atomic_inc(&conf->active_stripes); - out: - return sh; -} - -static void -shrink_buffers(struct stripe_head *sh, int num) -{ - struct buffer_head *bh; - int i; - - for (i = 0; i < num; i++) { - bh = sh->bh_cache[i]; - if (!bh) - return; - sh->bh_cache[i] = NULL; - free_page((unsigned long) bh->b_data); - kfree(bh); - } -} - -static int -grow_buffers(struct stripe_head *sh, int num, int b_size, int priority) -{ - struct buffer_head *bh; - int i; - - for (i = 0; i < num; i++) { - struct page *page; - bh = kmalloc(sizeof (struct buffer_head), priority); - if (!bh) - return 1; - memset(bh, 0, sizeof (struct buffer_head)); - init_waitqueue_head(&bh->b_wait); - if ((page = alloc_page(priority))) - bh->b_data = page_address(page); - else { - kfree(bh); - return 1; - } - atomic_set(&bh->b_count, 0); - bh->b_page = page; - sh->bh_cache[i] = bh; - - } - return 0; -} - -static struct buffer_head *raid5_build_block(struct stripe_head *sh, int i); - -static inline void -init_stripe(struct stripe_head *sh, unsigned long sector) -{ - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks, i; - - if (atomic_read(&sh->count) != 0) - BUG(); - if (test_bit(STRIPE_HANDLE, &sh->state)) - BUG(); - - CHECK_DEVLOCK(); - - remove_hash(sh); - - sh->sector = sector; - sh->size = conf->buffer_size; - sh->state = 0; - - for (i = disks; i--;) { - if (sh->bh_read[i] || sh->bh_write[i] || sh->bh_written[i] || - buffer_locked(sh->bh_cache[i])) { - LOG_ERROR("sector=%lx i=%d %p %p %p %d\n", - sh->sector, i, sh->bh_read[i], - sh->bh_write[i], sh->bh_written[i], - buffer_locked(sh->bh_cache[i])); - BUG(); - } - clear_bit(BH_Uptodate, &sh->bh_cache[i]->b_state); - raid5_build_block(sh, i); - } - insert_hash(conf, sh); -} - -/* the buffer size has changed, so unhash all stripes - * as active stripes complete, they will go onto inactive list - */ -static void -shrink_stripe_cache(raid5_conf_t * conf) -{ - int i; - CHECK_DEVLOCK(); - if (atomic_read(&conf->active_stripes)) - BUG(); - for (i = 0; i < NR_HASH; i++) { - struct stripe_head *sh; - while ((sh = conf->stripe_hashtbl[i])) - remove_hash(sh); - } -} - -static struct stripe_head * -__find_stripe(raid5_conf_t * conf, unsigned long sector) -{ - struct stripe_head *sh; - - CHECK_DEVLOCK(); - for (sh = stripe_hash(conf, sector); sh; sh = sh->hash_next) - if (sh->sector == sector) - return sh; - return NULL; -} - -static struct stripe_head * -get_active_stripe(raid5_conf_t * conf, unsigned long sector, int size) -{ - struct stripe_head *sh; - - md_spin_lock_irq(&conf->device_lock); - - do { - if (conf->buffer_size == 0 || - (size && size != conf->buffer_size)) { - /* either the size is being changed (buffer_size==0) or - * we need to change it. - * If size==0, we can proceed as soon as buffer_size gets set. - * If size>0, we can proceed when active_stripes reaches 0, or - * when someone else sets the buffer_size to size. - * If someone sets the buffer size to something else, we will need to - * assert that we want to change it again - */ - if (size == 0) - wait_event_lock_irq(conf->wait_for_stripe, - conf->buffer_size, - conf->device_lock); - else { - while (conf->buffer_size != size - && atomic_read(&conf->active_stripes)) { - conf->buffer_size = 0; - wait_event_lock_irq(conf-> - wait_for_stripe, - atomic_read(&conf-> - active_stripes) - == 0 - || conf-> - buffer_size, - conf->device_lock); - } - - if (conf->buffer_size != size) { - shrink_stripe_cache(conf); - if (size == 0) - BUG(); - conf->buffer_size = size; - } - } - } - if (size == 0) - sector -= sector & ((conf->buffer_size >> 9) - 1); - - sh = __find_stripe(conf, sector); - if (!sh) { - if (!conf->inactive_blocked) - sh = get_free_stripe(conf); - if (!sh) { - conf->inactive_blocked = 1; - wait_event_lock_irq(conf->wait_for_stripe, - !list_empty(&conf-> - inactive_list) - && - (atomic_read - (&conf->active_stripes) < - (NR_STRIPES * 3 / 4) - || !conf-> - inactive_blocked), - conf->device_lock); - conf->inactive_blocked = 0; - } else - init_stripe(sh, sector); - } else { - if (atomic_read(&sh->count)) { - if (!list_empty(&sh->lru)) - BUG(); - } else { - if (!test_bit(STRIPE_HANDLE, &sh->state)) - atomic_inc(&conf->active_stripes); - if (list_empty(&sh->lru)) - BUG(); - list_del_init(&sh->lru); - } - } - } while (sh == NULL); - - if (sh) - atomic_inc(&sh->count); - - md_spin_unlock_irq(&conf->device_lock); - return sh; -} - -static int -grow_stripes(raid5_conf_t * conf, int num, int priority) -{ - struct stripe_head *sh; - - while (num--) { - sh = kmalloc(sizeof (struct stripe_head), priority); - if (!sh) - return 1; - memset(sh, 0, sizeof (*sh)); - sh->raid_conf = conf; - sh->lock = SPIN_LOCK_UNLOCKED; - - if (grow_buffers(sh, conf->raid_disks, PAGE_SIZE, priority)) { - shrink_buffers(sh, conf->raid_disks); - kfree(sh); - return 1; - } - /* we just created an active stripe so... */ - atomic_set(&sh->count, 1); - atomic_inc(&conf->active_stripes); - INIT_LIST_HEAD(&sh->lru); - release_stripe(sh); - } - return 0; -} - -static void -shrink_stripes(raid5_conf_t * conf, int num) -{ - struct stripe_head *sh; - - while (num--) { - spin_lock_irq(&conf->device_lock); - sh = get_free_stripe(conf); - spin_unlock_irq(&conf->device_lock); - if (!sh) - break; - if (atomic_read(&sh->count)) - BUG(); - shrink_buffers(sh, conf->raid_disks); - kfree(sh); - atomic_dec(&conf->active_stripes); - } -} - -static void -raid5_end_read_request(struct buffer_head *bh, int uptodate) -{ - struct stripe_head *sh = bh->b_private; - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks, i; - unsigned long flags; - - for (i = 0; i < disks; i++) - if (bh == sh->bh_cache[i]) - break; - - if (i == disks) { - BUG(); - return; - } - - if (uptodate) { - struct buffer_head *buffer; - spin_lock_irqsave(&conf->device_lock, flags); - /* we can return a buffer if we bypassed the cache or - * if the top buffer is not in highmem. If there are - * multiple buffers, leave the extra work to - * handle_stripe - */ - buffer = sh->bh_read[i]; - if (buffer && (!PageHighMem(buffer->b_page) - || buffer->b_page == bh->b_page) - ) { - sh->bh_read[i] = buffer->b_reqnext; - buffer->b_reqnext = NULL; - } else - buffer = NULL; - spin_unlock_irqrestore(&conf->device_lock, flags); - if (sh->bh_page[i] == NULL) - set_bit(BH_Uptodate, &bh->b_state); - if (buffer) { - if (buffer->b_page != bh->b_page) - memcpy(buffer->b_data, bh->b_data, bh->b_size); - evms_cs_volume_request_in_progress(buffer->b_rdev, -1, NULL); - buffer->b_end_io(buffer, 1); - } - } else { - /* I/O error */ - if (sh->node[i]) - evms_md_error(conf->mddev, sh->node[i]); - else - LOG_WARNING - ("NODE was not set, skipping evms_md_error()\n"); - clear_bit(BH_Uptodate, &bh->b_state); - } - /* must restore b_page before unlocking buffer... */ - if (sh->bh_page[i]) { - bh->b_page = sh->bh_page[i]; - bh->b_data = page_address(bh->b_page); - sh->bh_page[i] = NULL; - clear_bit(BH_Uptodate, &bh->b_state); - } - clear_bit(BH_Lock, &bh->b_state); - set_bit(STRIPE_HANDLE, &sh->state); - release_stripe(sh); - if (sh->node[i]) { - sh->node[i] = NULL; - } else { - LOG_WARNING(" evms node was not set.\n"); - } - -} - -static void -raid5_end_write_request(struct buffer_head *bh, int uptodate) -{ - struct stripe_head *sh = bh->b_private; - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks, i; - unsigned long flags; - - for (i = 0; i < disks; i++) - if (bh == sh->bh_cache[i]) - break; - - if (i == disks) { - BUG(); - return; - } - - md_spin_lock_irqsave(&conf->device_lock, flags); - if (!uptodate) { - /* I/O error */ - if (sh->node[i]) - evms_md_error(conf->mddev, sh->node[i]); - else - LOG_WARNING - (" NODE was not set, skipping evms_md_error()\n"); - } - clear_bit(BH_Lock, &bh->b_state); - set_bit(STRIPE_HANDLE, &sh->state); - __release_stripe(conf, sh); - md_spin_unlock_irqrestore(&conf->device_lock, flags); - if (sh->node[i]) { - sh->node[i] = NULL; - } else { - LOG_WARNING(" evms node was not set.\n"); - } -} - -static struct buffer_head * -raid5_build_block(struct stripe_head *sh, int i) -{ - raid5_conf_t *conf = sh->raid_conf; - struct buffer_head *bh = sh->bh_cache[i]; - unsigned long block = sh->sector / (sh->size >> 9); - - init_buffer(bh, raid5_end_read_request, sh); - bh->b_dev = conf->disks[i].dev; - bh->b_blocknr = block; - - bh->b_state = (1 << BH_Req) | (1 << BH_Mapped); - bh->b_size = sh->size; - bh->b_list = BUF_LOCKED; - return bh; -} - -static int -raid5_error(mddev_t * mddev, struct evms_logical_node * node) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - mdp_super_t *sb = mddev->sb; - struct disk_info *disk; - int i; - - LOG_WARNING("%s: called\n", __FUNCTION__); - - for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) { - if (disk->node == node) { - if (disk->operational) { - disk->operational = 0; - mark_disk_faulty(sb->disks + disk->number); - mark_disk_nonsync(sb->disks + disk->number); - mark_disk_inactive(sb->disks + disk->number); - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; - mddev->sb_dirty = 1; - conf->working_disks--; - conf->failed_disks++; - evms_cs_wakeup_thread(conf->thread); - LOG_WARNING - ("Disk failure on %s, disabling device." - " Operation continuing on %d devices\n", - evms_md_partition_name(disk->node), - conf->working_disks); - } - return 0; - } - } - /* - * handle errors in spares (during reconstruction) - */ - if (conf->spare) { - disk = conf->spare; - if (disk->node == node) { - LOG_WARNING("EVMS RAID5: Disk failure on spare %s\n", - evms_md_partition_name(disk->node)); - if (!conf->spare->operational) { - /* probably a SET_DISK_FAULTY ioctl */ - return -EIO; - } - disk->operational = 0; - disk->write_only = 0; - conf->spare = NULL; - mark_disk_faulty(sb->disks + disk->number); - mark_disk_nonsync(sb->disks + disk->number); - mark_disk_inactive(sb->disks + disk->number); - sb->spare_disks--; - sb->working_disks--; - sb->failed_disks++; - - mddev->sb_dirty = 1; - evms_cs_wakeup_thread(conf->thread); - - return 0; - } - } - MD_BUG(); - return -EIO; -} - -/* - * Input: a 'big' sector number, - * Output: index of the data and parity disk, and the sector # in them. - */ -static unsigned long -raid5_compute_sector(unsigned long r_sector, unsigned int raid_disks, - unsigned int data_disks, unsigned int *dd_idx, - unsigned int *pd_idx, raid5_conf_t * conf) -{ - unsigned long stripe; - unsigned long chunk_number; - unsigned int chunk_offset; - unsigned long new_sector; - int sectors_per_chunk = conf->chunk_size >> 9; - - /* First compute the information on this sector */ - - /* - * Compute the chunk number and the sector offset inside the chunk - */ - chunk_number = r_sector / sectors_per_chunk; - chunk_offset = r_sector % sectors_per_chunk; - - /* - * Compute the stripe number - */ - stripe = chunk_number / data_disks; - - /* - * Compute the data disk and parity disk indexes inside the stripe - */ - *dd_idx = chunk_number % data_disks; - - /* - * Select the parity disk based on the user selected algorithm. - */ - if (conf->level == 4) - *pd_idx = data_disks; - else - switch (conf->algorithm) { - case ALGORITHM_LEFT_ASYMMETRIC: - *pd_idx = data_disks - stripe % raid_disks; - if (*dd_idx >= *pd_idx) - (*dd_idx)++; - break; - case ALGORITHM_RIGHT_ASYMMETRIC: - *pd_idx = stripe % raid_disks; - if (*dd_idx >= *pd_idx) - (*dd_idx)++; - break; - case ALGORITHM_LEFT_SYMMETRIC: - *pd_idx = data_disks - stripe % raid_disks; - *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; - break; - case ALGORITHM_RIGHT_SYMMETRIC: - *pd_idx = stripe % raid_disks; - *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; - break; - default: - LOG_ERROR(" unsupported algorithm %d\n", - conf->algorithm); - } - - /* - * Finally, compute the new sector number - */ - new_sector = stripe * sectors_per_chunk + chunk_offset; - return new_sector; -} - -#define check_xor() do { \ - if (count == MAX_XOR_BLOCKS) { \ - evms_md_xor_block(count, bh_ptr); \ - count = 1; \ - } \ - } while(0) - -static void -compute_block(struct stripe_head *sh, int dd_idx) -{ - raid5_conf_t *conf = sh->raid_conf; - int i, count, disks = conf->raid_disks; - struct buffer_head *bh_ptr[MAX_XOR_BLOCKS], *bh; - - memset(sh->bh_cache[dd_idx]->b_data, 0, sh->size); - bh_ptr[0] = sh->bh_cache[dd_idx]; - count = 1; - for (i = disks; i--;) { - if (i == dd_idx) - continue; - bh = sh->bh_cache[i]; - if (buffer_uptodate(bh)) - bh_ptr[count++] = bh; - else - LOG_ERROR("%s: %d, stripe %lu, %d not present\n", - __FUNCTION__, dd_idx, sh->sector, i); - - check_xor(); - } - if (count != 1) - evms_md_xor_block(count, bh_ptr); - set_bit(BH_Uptodate, &sh->bh_cache[dd_idx]->b_state); -} - -static void -compute_parity(struct stripe_head *sh, int method) -{ - raid5_conf_t *conf = sh->raid_conf; - int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count; - struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; - struct buffer_head *chosen[MD_SB_DISKS]; - - memset(chosen, 0, sizeof (chosen)); - - count = 1; - bh_ptr[0] = sh->bh_cache[pd_idx]; - switch (method) { - case READ_MODIFY_WRITE: - if (!buffer_uptodate(sh->bh_cache[pd_idx])) - BUG(); - for (i = disks; i--;) { - if (i == pd_idx) - continue; - if (sh->bh_write[i] && buffer_uptodate(sh->bh_cache[i])) { - bh_ptr[count++] = sh->bh_cache[i]; - chosen[i] = sh->bh_write[i]; - sh->bh_write[i] = sh->bh_write[i]->b_reqnext; - chosen[i]->b_reqnext = sh->bh_written[i]; - sh->bh_written[i] = chosen[i]; - check_xor(); - } - } - break; - case RECONSTRUCT_WRITE: - memset(sh->bh_cache[pd_idx]->b_data, 0, sh->size); - for (i = disks; i--;) - if (i != pd_idx && sh->bh_write[i]) { - chosen[i] = sh->bh_write[i]; - sh->bh_write[i] = sh->bh_write[i]->b_reqnext; - chosen[i]->b_reqnext = sh->bh_written[i]; - sh->bh_written[i] = chosen[i]; - } - break; - case CHECK_PARITY: - break; - } - if (count > 1) { - evms_md_xor_block(count, bh_ptr); - count = 1; - } - - for (i = disks; i--;) - if (chosen[i]) { - struct buffer_head *bh = sh->bh_cache[i]; - char *bdata; - bdata = bh_kmap(chosen[i]); - memcpy(bh->b_data, bdata, sh->size); - bh_kunmap(chosen[i]); - set_bit(BH_Lock, &bh->b_state); - mark_buffer_uptodate(bh, 1); - } - - switch (method) { - case RECONSTRUCT_WRITE: - case CHECK_PARITY: - for (i = disks; i--;) - if (i != pd_idx) { - bh_ptr[count++] = sh->bh_cache[i]; - check_xor(); - } - break; - case READ_MODIFY_WRITE: - for (i = disks; i--;) - if (chosen[i]) { - bh_ptr[count++] = sh->bh_cache[i]; - check_xor(); - } - } - if (count != 1) - evms_md_xor_block(count, bh_ptr); - - if (method != CHECK_PARITY) { - mark_buffer_uptodate(sh->bh_cache[pd_idx], 1); - set_bit(BH_Lock, &sh->bh_cache[pd_idx]->b_state); - } else - mark_buffer_uptodate(sh->bh_cache[pd_idx], 0); -} - -static void -add_stripe_bh(struct stripe_head *sh, struct buffer_head *bh, int dd_idx, - int rw) -{ - struct buffer_head **bhp; - raid5_conf_t *conf = sh->raid_conf; - - spin_lock(&sh->lock); - spin_lock_irq(&conf->device_lock); - bh->b_reqnext = NULL; - if (rw == READ) - bhp = &sh->bh_read[dd_idx]; - else - bhp = &sh->bh_write[dd_idx]; - while (*bhp) { - LOG_DEFAULT("multiple %d requests for sector %ld\n", - rw, sh->sector); - bhp = &(*bhp)->b_reqnext; - } - *bhp = bh; - spin_unlock_irq(&conf->device_lock); - spin_unlock(&sh->lock); - -} - -/* - * handle_stripe - do things to a stripe. - * - * We lock the stripe and then examine the state of various bits - * to see what needs to be done. - * Possible results: - * return some read request which now have data - * return some write requests which are safely on disc - * schedule a read on some buffers - * schedule a write of some buffers - * return confirmation of parity correctness - * - * Parity calculations are done inside the stripe lock - * buffers are taken off read_list or write_list, and bh_cache buffers - * get BH_Lock set before the stripe lock is released. - * - */ - -static void -handle_stripe(struct stripe_head *sh) -{ - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks; - struct buffer_head *return_ok = NULL, *return_fail = NULL; - int action[MD_SB_DISKS]; - int i; - int syncing; - int locked = 0, uptodate = 0, to_read = 0, to_write = 0, failed = - 0, written = 0; - int failed_num = 0; - struct buffer_head *bh; - - memset(action, 0, sizeof (action)); - - spin_lock(&sh->lock); - clear_bit(STRIPE_HANDLE, &sh->state); - clear_bit(STRIPE_DELAYED, &sh->state); - - syncing = test_bit(STRIPE_SYNCING, &sh->state); - /* Now to look around and see what can be done */ - - for (i = disks; i--;) { - bh = sh->bh_cache[i]; - /* maybe we can reply to a read */ - if (buffer_uptodate(bh) && sh->bh_read[i]) { - struct buffer_head *rbh, *rbh2; - spin_lock_irq(&conf->device_lock); - rbh = sh->bh_read[i]; - sh->bh_read[i] = NULL; - spin_unlock_irq(&conf->device_lock); - while (rbh) { - char *bdata; - bdata = bh_kmap(rbh); - memcpy(bdata, bh->b_data, bh->b_size); - bh_kunmap(rbh); - rbh2 = rbh->b_reqnext; - rbh->b_reqnext = return_ok; - return_ok = rbh; - rbh = rbh2; - } - } - - /* now count some things */ - if (buffer_locked(bh)) - locked++; - if (buffer_uptodate(bh)) - uptodate++; - - if (sh->bh_read[i]) - to_read++; - if (sh->bh_write[i]) - to_write++; - if (sh->bh_written[i]) - written++; - if (!conf->disks[i].operational) { - failed++; - failed_num = i; - } - } - /* check if the array has lost two devices and, if so, some requests might - * need to be failed - */ - if (failed > 1 && to_read + to_write) { - for (i = disks; i--;) { - /* fail all writes first */ - if (sh->bh_write[i]) - to_write--; - while ((bh = sh->bh_write[i])) { - sh->bh_write[i] = bh->b_reqnext; - bh->b_reqnext = return_fail; - return_fail = bh; - } - /* fail any reads if this device is non-operational */ - if (!conf->disks[i].operational) { - spin_lock_irq(&conf->device_lock); - if (sh->bh_read[i]) - to_read--; - while ((bh = sh->bh_read[i])) { - sh->bh_read[i] = bh->b_reqnext; - bh->b_reqnext = return_fail; - return_fail = bh; - } - spin_unlock_irq(&conf->device_lock); - } - } - } - if (failed > 1 && syncing) { - evms_md_done_sync(conf->mddev, - (sh->size >> 9) - sh->sync_redone, 0); - clear_bit(STRIPE_SYNCING, &sh->state); - syncing = 0; - } - - /* might be able to return some write requests if the parity block - * is safe, or on a failed drive - */ - bh = sh->bh_cache[sh->pd_idx]; - if (written && - ((conf->disks[sh->pd_idx].operational && !buffer_locked(bh) - && buffer_uptodate(bh)) - || (failed == 1 && failed_num == sh->pd_idx)) - ) { - /* any written block on a uptodate or failed drive can be returned */ - for (i = disks; i--;) - if (sh->bh_written[i]) { - bh = sh->bh_cache[i]; - if (!conf->disks[sh->pd_idx].operational || - (!buffer_locked(bh) - && buffer_uptodate(bh))) { - /* maybe we can return some write requests */ - struct buffer_head *wbh, *wbh2; - wbh = sh->bh_written[i]; - sh->bh_written[i] = NULL; - while (wbh) { - wbh2 = wbh->b_reqnext; - wbh->b_reqnext = return_ok; - return_ok = wbh; - wbh = wbh2; - } - } - } - } - - /* Now we might consider reading some blocks, either to check/generate - * parity, or to satisfy requests - */ - if (to_read || (syncing && (uptodate + failed < disks))) { - for (i = disks; i--;) { - bh = sh->bh_cache[i]; - if (!buffer_locked(bh) && !buffer_uptodate(bh) && - (sh->bh_read[i] || syncing - || (failed && sh->bh_read[failed_num]))) { - /* we would like to get this block, possibly - * by computing it, but we might not be able to - */ - if (uptodate == disks - 1) { - compute_block(sh, i); - uptodate++; - } else if (conf->disks[i].operational) { - set_bit(BH_Lock, &bh->b_state); - action[i] = READ + 1; - /* if I am just reading this block and we don't have - a failed drive, or any pending writes then sidestep the cache */ - if (sh->bh_page[i]) - BUG(); - if (sh->bh_read[i] - && !sh->bh_read[i]->b_reqnext - && !syncing && !failed - && !to_write) { - sh->bh_page[i] = - sh->bh_cache[i]->b_page; - sh->bh_cache[i]->b_page = - sh->bh_read[i]->b_page; - sh->bh_cache[i]->b_data = - sh->bh_read[i]->b_data; - } - locked++; - if (syncing) - evms_md_sync_acct(conf-> - disks[i].dev, - bh-> - b_size >> 9); - } - } - } - set_bit(STRIPE_HANDLE, &sh->state); - } - - /* now to consider writing and what else, if anything should be read */ - if (to_write) { - int rmw = 0, rcw = 0; - for (i = disks; i--;) { - /* would I have to read this buffer for read_modify_write */ - bh = sh->bh_cache[i]; - if ((sh->bh_write[i] || i == sh->pd_idx) && - (!buffer_locked(bh) || sh->bh_page[i]) && - !buffer_uptodate(bh)) { - if (conf->disks[i].operational -/* && !(conf->resync_parity && i == sh->pd_idx) */ - ) - rmw++; - else - rmw += 2 * disks; /* cannot read it */ - } - /* Would I have to read this buffer for reconstruct_write */ - if (!sh->bh_write[i] && i != sh->pd_idx && - (!buffer_locked(bh) || sh->bh_page[i]) && - !buffer_uptodate(bh)) { - if (conf->disks[i].operational) - rcw++; - else - rcw += 2 * disks; - } - } - set_bit(STRIPE_HANDLE, &sh->state); - if (rmw < rcw && rmw > 0) - /* prefer read-modify-write, but need to get some data */ - for (i = disks; i--;) { - bh = sh->bh_cache[i]; - if ((sh->bh_write[i] || i == sh->pd_idx) && - !buffer_locked(bh) && !buffer_uptodate(bh) - && conf->disks[i].operational) { - if (test_bit - (STRIPE_PREREAD_ACTIVE, - &sh->state)) { - set_bit(BH_Lock, &bh->b_state); - action[i] = READ + 1; - locked++; - } else { - set_bit(STRIPE_DELAYED, - &sh->state); - set_bit(STRIPE_HANDLE, - &sh->state); - } - } - } - if (rcw <= rmw && rcw > 0) - /* want reconstruct write, but need to get some data */ - for (i = disks; i--;) { - bh = sh->bh_cache[i]; - if (!sh->bh_write[i] && i != sh->pd_idx && - !buffer_locked(bh) && !buffer_uptodate(bh) - && conf->disks[i].operational) { - if (test_bit - (STRIPE_PREREAD_ACTIVE, - &sh->state)) { - set_bit(BH_Lock, &bh->b_state); - action[i] = READ + 1; - locked++; - } else { - set_bit(STRIPE_DELAYED, - &sh->state); - set_bit(STRIPE_HANDLE, - &sh->state); - } - } - } - /* now if nothing is locked, and if we have enough data, we can start a write request */ - if (locked == 0 && (rcw == 0 || rmw == 0)) { - compute_parity(sh, - rcw == - 0 ? RECONSTRUCT_WRITE : - READ_MODIFY_WRITE); - /* now every locked buffer is ready to be written */ - for (i = disks; i--;) - if (buffer_locked(sh->bh_cache[i])) { - locked++; - action[i] = WRITE + 1; - if (!conf->disks[i].operational - || (i == sh->pd_idx && failed == 0)) - set_bit(STRIPE_INSYNC, - &sh->state); - } - if (test_and_clear_bit - (STRIPE_PREREAD_ACTIVE, &sh->state)) { - atomic_dec(&conf->preread_active_stripes); - if (atomic_read(&conf->preread_active_stripes) < - IO_THRESHOLD) - evms_cs_wakeup_thread(conf->thread); - } - } - } - - /* maybe we need to check and possibly fix the parity for this stripe - * Any reads will already have been scheduled, so we just see if enough data - * is available - */ - if (syncing && locked == 0 && - !test_bit(STRIPE_INSYNC, &sh->state) && failed <= 1) { - set_bit(STRIPE_HANDLE, &sh->state); - if (failed == 0) { - if (uptodate != disks) - BUG(); - compute_parity(sh, CHECK_PARITY); - uptodate--; - bh = sh->bh_cache[sh->pd_idx]; - if ((*(u32 *) bh->b_data) == 0 && - !memcmp(bh->b_data, bh->b_data + 4, - bh->b_size - 4)) { - /* parity is correct (on disc, not in buffer any more) */ - set_bit(STRIPE_INSYNC, &sh->state); - } - } - if (!test_bit(STRIPE_INSYNC, &sh->state)) { - struct disk_info *spare; - if (failed == 0) - failed_num = sh->pd_idx; - /* should be able to compute the missing block and write it to spare */ - if (!buffer_uptodate(sh->bh_cache[failed_num])) { - if (uptodate + 1 != disks) - BUG(); - compute_block(sh, failed_num); - uptodate++; - } - if (uptodate != disks) - BUG(); - bh = sh->bh_cache[failed_num]; - set_bit(BH_Lock, &bh->b_state); - action[failed_num] = WRITE + 1; - locked++; - set_bit(STRIPE_INSYNC, &sh->state); - if (conf->disks[failed_num].operational) - evms_md_sync_acct(conf->disks[failed_num].dev, - bh->b_size >> 9); - else if ((spare = conf->spare)) - evms_md_sync_acct(spare->dev, bh->b_size >> 9); - - } - } - if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) { - evms_md_done_sync(conf->mddev, - (sh->size >> 9) - sh->sync_redone, 1); - clear_bit(STRIPE_SYNCING, &sh->state); - } - - spin_unlock(&sh->lock); - - while ((bh = return_ok)) { - return_ok = bh->b_reqnext; - bh->b_reqnext = NULL; - evms_cs_volume_request_in_progress(bh->b_rdev, -1, NULL); - bh->b_end_io(bh, 1); - } - while ((bh = return_fail)) { - return_fail = bh->b_reqnext; - bh->b_reqnext = NULL; - evms_cs_volume_request_in_progress(bh->b_rdev, -1, NULL); - bh->b_end_io(bh, 0); - } - for (i = disks; i--;) - if (action[i]) { - struct buffer_head *bh = sh->bh_cache[i]; - struct disk_info *spare = conf->spare; - struct evms_logical_node *node = NULL; - int skip = 0; - if (action[i] == READ + 1) - bh->b_end_io = raid5_end_read_request; - else - bh->b_end_io = raid5_end_write_request; - if (conf->disks[i].operational) { - bh->b_dev = conf->disks[i].dev; - node = conf->disks[i].node; - } else if (spare && action[i] == WRITE + 1) { - bh->b_dev = spare->dev; - node = spare->node; - } else - skip = 1; - if (!skip) { - atomic_inc(&sh->count); - //bh->b_rdev = bh->b_dev; - bh->b_rsector = - bh->b_blocknr * (bh->b_size >> 9); - sh->node[i] = node; - if (action[i] == READ + 1) - R_IO(node, bh); - else - W_IO(node, bh); - } else { - clear_bit(BH_Lock, &bh->b_state); - set_bit(STRIPE_HANDLE, &sh->state); - } - } -} - -static inline void -raid5_activate_delayed(raid5_conf_t * conf) -{ - if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { - while (!list_empty(&conf->delayed_list)) { - struct list_head *l = conf->delayed_list.next; - struct stripe_head *sh; - sh = list_entry(l, struct stripe_head, lru); - list_del_init(l); - clear_bit(STRIPE_DELAYED, &sh->state); - if (!test_and_set_bit - (STRIPE_PREREAD_ACTIVE, &sh->state)) - atomic_inc(&conf->preread_active_stripes); - list_add_tail(&sh->lru, &conf->handle_list); - } - } -} -static void -raid5_unplug_device(void *data) -{ - raid5_conf_t *conf = (raid5_conf_t *) data; - unsigned long flags; - - spin_lock_irqsave(&conf->device_lock, flags); - - raid5_activate_delayed(conf); - - conf->plugged = 0; - evms_cs_wakeup_thread(conf->thread); - - spin_unlock_irqrestore(&conf->device_lock, flags); -} - -static inline void -raid5_plug_device(raid5_conf_t * conf) -{ - spin_lock_irq(&conf->device_lock); - if (list_empty(&conf->delayed_list)) - if (!conf->plugged) { - conf->plugged = 1; - queue_task(&conf->plug_tq, &tq_disk); - } - spin_unlock_irq(&conf->device_lock); -} - -static inline void -raid5_rw(struct evms_logical_node * md_node, struct buffer_head *bh, int rw) -{ - mddev_t *mddev = EVMS_MD_NODE_TO_MDDEV(md_node); - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - const unsigned int raid_disks = conf->raid_disks; - const unsigned int data_disks = raid_disks - 1; - unsigned int dd_idx, pd_idx; - unsigned long new_sector; - struct stripe_head *sh; - unsigned long sectors_per_chunk = conf->chunk_size >> 9; - unsigned long sect_in_chunk = bh->b_rsector & (sectors_per_chunk - 1); - - if (evms_md_check_boundary(md_node, bh)) - return; - if ((sect_in_chunk + (bh->b_size >> 9)) > sectors_per_chunk) { - bh->b_end_io(bh, 0); - return; - } - - new_sector = raid5_compute_sector(bh->b_rsector, - raid_disks, data_disks, &dd_idx, - &pd_idx, conf); - - sh = get_active_stripe(conf, new_sector, bh->b_size); - if (sh) { - sh->pd_idx = pd_idx; - - add_stripe_bh(sh, bh, dd_idx, rw); - - raid5_plug_device(conf); - - evms_cs_volume_request_in_progress(bh->b_rdev, 1, NULL); - handle_stripe(sh); - release_stripe(sh); - } else { - evms_cs_volume_request_in_progress(bh->b_rdev, -1, NULL); - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - } -} - -static void -raid5_read(struct evms_logical_node * md_node, struct buffer_head *bh) -{ - raid5_rw(md_node, bh, READ); -} - -static void -raid5_write(struct evms_logical_node * md_node, struct buffer_head *bh) -{ - raid5_rw(md_node, bh, WRITE); -} - -static int -raid5_sync_request(mddev_t * mddev, unsigned long sector_nr) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - struct stripe_head *sh; - int sectors_per_chunk = conf->chunk_size >> 9; - unsigned long stripe = sector_nr / sectors_per_chunk; - int chunk_offset = sector_nr % sectors_per_chunk; - int dd_idx, pd_idx; - unsigned long first_sector; - int raid_disks = conf->raid_disks; - int data_disks = raid_disks - 1; - int redone = 0; - int bufsize; - - sh = get_active_stripe(conf, sector_nr, 0); - bufsize = sh->size; - redone = sector_nr - sh->sector; - first_sector = - raid5_compute_sector(stripe * data_disks * sectors_per_chunk + - chunk_offset, raid_disks, data_disks, &dd_idx, - &pd_idx, conf); - sh->pd_idx = pd_idx; - spin_lock(&sh->lock); - set_bit(STRIPE_SYNCING, &sh->state); - clear_bit(STRIPE_INSYNC, &sh->state); - sh->sync_redone = redone; - spin_unlock(&sh->lock); - - handle_stripe(sh); - release_stripe(sh); - - return (bufsize >> 9) - redone; -} - -/* - * This is our raid5 kernel thread. - * - * We scan the hash table for stripes which can be handled now. - * During the scan, completed stripes are saved for us by the interrupt - * handler, so that they will not have to wait for our next wakeup. - */ -static void -raid5d(void *data) -{ - struct stripe_head *sh; - raid5_conf_t *conf = data; - mddev_t *mddev = conf->mddev; - int handled; - - handled = 0; - - if (mddev->sb_dirty) { - mddev->sb_dirty = 0; - evms_md_update_sb(mddev); - } - md_spin_lock_irq(&conf->device_lock); - while (1) { - struct list_head *first; - - if (list_empty(&conf->handle_list) && - atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && - !conf->plugged && !list_empty(&conf->delayed_list)) - raid5_activate_delayed(conf); - - if (list_empty(&conf->handle_list)) - break; - - first = conf->handle_list.next; - sh = list_entry(first, struct stripe_head, lru); - - list_del_init(first); - atomic_inc(&sh->count); - if (atomic_read(&sh->count) != 1) - BUG(); - md_spin_unlock_irq(&conf->device_lock); - - handled++; - handle_stripe(sh); - release_stripe(sh); - - md_spin_lock_irq(&conf->device_lock); - } - - md_spin_unlock_irq(&conf->device_lock); - -} - -/* - * Private kernel thread for parity reconstruction after an unclean - * shutdown. Reconstruction on spare drives in case of a failed drive - * is done by the generic mdsyncd. - */ -static void -raid5syncd(void *data) -{ - raid5_conf_t *conf = data; - mddev_t *mddev = conf->mddev; - - if (!conf->resync_parity) - return; - if (conf->resync_parity == 2) - return; - down(&mddev->recovery_sem); - if (evms_md_do_sync(mddev, NULL)) { - up(&mddev->recovery_sem); - LOG_WARNING("resync aborted!\n"); - return; - } - conf->resync_parity = 0; - up(&mddev->recovery_sem); - LOG_DEFAULT("resync finished.\n"); -} - -static int -raid5_run(mddev_t * mddev) -{ - raid5_conf_t *conf; - int i, j, raid_disk, memory; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *desc; - mdk_rdev_t *rdev; - struct disk_info *disk; - struct md_list_head *tmp; - int start_recovery = 0; - - MOD_INC_USE_COUNT; - - if (sb->level != 5 && sb->level != 4) { - LOG_ERROR("%s: [md%d] raid level not set to 4/5 (%d)\n", - __FUNCTION__, mdidx(mddev), sb->level); - MOD_DEC_USE_COUNT; - return -EIO; - } - - mddev->private = kmalloc(sizeof (raid5_conf_t), GFP_KERNEL); - if ((conf = mddev->private) == NULL) - goto abort; - memset(conf, 0, sizeof (*conf)); - conf->mddev = mddev; - - if ((conf->stripe_hashtbl = - (struct stripe_head **) md__get_free_pages(GFP_ATOMIC, - HASH_PAGES_ORDER)) == - NULL) - goto abort; - memset(conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); - - conf->device_lock = MD_SPIN_LOCK_UNLOCKED; - md_init_waitqueue_head(&conf->wait_for_stripe); - INIT_LIST_HEAD(&conf->handle_list); - INIT_LIST_HEAD(&conf->delayed_list); - INIT_LIST_HEAD(&conf->inactive_list); - atomic_set(&conf->active_stripes, 0); - atomic_set(&conf->preread_active_stripes, 0); - conf->buffer_size = PAGE_SIZE; /* good default for rebuild */ - - conf->plugged = 0; - conf->plug_tq.sync = 0; - conf->plug_tq.routine = &raid5_unplug_device; - conf->plug_tq.data = conf; - - ITERATE_RDEV(mddev, rdev, tmp) { - /* - * This is important -- we are using the descriptor on - * the disk only to get a pointer to the descriptor on - * the main superblock, which might be more recent. - */ - desc = sb->disks + rdev->desc_nr; - raid_disk = desc->raid_disk; - disk = conf->disks + raid_disk; - - if (disk_faulty(desc)) { - LOG_ERROR("%s: disabled device %s (errors detected)\n", - __FUNCTION__, - evms_md_partition_name(rdev->node)); - if (!rdev->faulty) { - MD_BUG(); - goto abort; - } - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = rdev->dev; - disk->node = rdev->node; - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - continue; - } - if (disk_active(desc)) { - if (!disk_sync(desc)) { - LOG_ERROR - ("%s: disabled device %s (not in sync)\n", - __FUNCTION__, - evms_md_partition_name(rdev->node)); - MD_BUG(); - goto abort; - } - if (raid_disk > sb->raid_disks) { - LOG_ERROR - ("%s: disabled device %s (inconsistent descriptor)\n", - __FUNCTION__, - evms_md_partition_name(rdev->node)); - continue; - } - if (disk->operational) { - LOG_ERROR - ("%s: disabled device %s (device %d already operational)\n", - __FUNCTION__, - evms_md_partition_name(rdev->node), - raid_disk); - continue; - } - LOG_DEFAULT - ("%s: device %s operational as raid disk %d\n", - __FUNCTION__, evms_md_partition_name(rdev->node), - raid_disk); - - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = rdev->dev; - disk->node = rdev->node; - disk->operational = 1; - disk->used_slot = 1; - - conf->working_disks++; - } else { - /* - * Must be a spare disk .. - */ - LOG_DEFAULT(" spare disk %s\n", - evms_md_partition_name(rdev->node)); - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = rdev->dev; - disk->node = rdev->node; - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 1; - disk->used_slot = 1; - } - } - - for (i = 0; i < MD_SB_DISKS; i++) { - desc = sb->disks + i; - raid_disk = desc->raid_disk; - disk = conf->disks + raid_disk; - - if (disk_faulty(desc) && (raid_disk < sb->raid_disks) && - !conf->disks[raid_disk].used_slot) { - - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = MKDEV(0, 0); - disk->node = NULL; - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - } - } - - conf->raid_disks = sb->raid_disks; - /* - * faied_disks: 0 for a fully functional array, 1 for a degraded array. - */ - conf->failed_disks = conf->raid_disks - conf->working_disks; - conf->mddev = mddev; - conf->chunk_size = sb->chunk_size; - conf->level = sb->level; - conf->algorithm = sb->layout; - conf->max_nr_stripes = NR_STRIPES; - - /* - * If chunk_size is validated in md_core.c, why do it again? - * And the check in md_core is: - * chunk_size has to be a power of 2 and multiples of PAGE_SIZE - */ - - if (!conf->chunk_size || - ((1 << ffz(~conf->chunk_size)) != conf->chunk_size) || - (conf->chunk_size < PAGE_SIZE)) { - LOG_ERROR("%s: invalid chunk size %d for md%d\n", __FUNCTION__, - conf->chunk_size, mdidx(mddev)); - goto abort; - } - if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { - LOG_ERROR(" unsupported parity algorithm %d for md%d\n", - conf->algorithm, mdidx(mddev)); - goto abort; - } - if (conf->failed_disks > 1) { - LOG_ERROR - (" not enough operational devices for md%d (%d/%d failed)\n", - mdidx(mddev), conf->failed_disks, conf->raid_disks); - goto abort; - } - - if (conf->working_disks != sb->raid_disks) { - LOG_WARNING - (" md%d, not all disks are operational -- trying to recover array\n", - mdidx(mddev)); - start_recovery = 1; - } - - { - const char *name = "evms_raid5d"; - - conf->thread = evms_cs_register_thread(raid5d, conf, name); - if (!conf->thread) { - LOG_ERROR("%s: couldn't allocate thread for md%d\n", - __FUNCTION__, mdidx(mddev)); - goto abort; - } - } - - memory = conf->max_nr_stripes * (sizeof (struct stripe_head) + - conf->raid_disks * - ((sizeof (struct buffer_head) + - PAGE_SIZE))) / 1024; - if (grow_stripes(conf, conf->max_nr_stripes, GFP_KERNEL)) { - LOG_ERROR("%s: couldn't allocate %dkB for buffers\n", - __FUNCTION__, memory); - shrink_stripes(conf, conf->max_nr_stripes); - goto abort; - } else - LOG_DETAILS("%s: allocated %dkB for md%d\n", __FUNCTION__, - memory, mdidx(mddev)); - - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mark_disk_nonsync(sb->disks + i); - for (j = 0; j < sb->raid_disks; j++) { - if (!conf->disks[j].operational) - continue; - if (sb->disks[i].number == conf->disks[j].number) - mark_disk_sync(sb->disks + i); - } - } - sb->active_disks = conf->working_disks; - - if (sb->active_disks == sb->raid_disks) { - LOG_DETAILS - ("%s: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", - __FUNCTION__, conf->level, mdidx(mddev), sb->active_disks, - sb->raid_disks, conf->algorithm); - } else { - LOG_WARNING - ("%s: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", - __FUNCTION__, conf->level, mdidx(mddev), sb->active_disks, - sb->raid_disks, conf->algorithm); - } - - if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { - const char *name = "evms_raid5syncd"; - - conf->resync_thread = - evms_cs_register_thread(raid5syncd, conf, name); - if (!conf->resync_thread) { - LOG_ERROR("%s: couldn't allocate thread for md%d\n", - __FUNCTION__, mdidx(mddev)); - goto abort; - } - - LOG_WARNING - ("%s: raid set md%d not clean; reconstructing parity\n", - __FUNCTION__, mdidx(mddev)); - conf->resync_parity = 1; - evms_cs_wakeup_thread(conf->resync_thread); - } - - print_raid5_conf(conf); - if (start_recovery) - evms_md_recover_arrays(); - print_raid5_conf(conf); - - /* Ok, everything is just fine now */ - return (0); - abort: - if (conf) { - print_raid5_conf(conf); - if (conf->stripe_hashtbl) - free_pages((unsigned long) conf->stripe_hashtbl, - HASH_PAGES_ORDER); - kfree(conf); - } - mddev->private = NULL; - LOG_WARNING("%s: failed to run raid set md%d\n", __FUNCTION__, - mdidx(mddev)); - MOD_DEC_USE_COUNT; - return -EIO; -} - -static int -raid5_stop_resync(mddev_t * mddev) -{ - raid5_conf_t *conf = mddev_to_conf(mddev); - struct evms_thread *thread; - - if (conf == NULL) { - return 0; - } - - thread = conf->resync_thread; - - if (thread) { - if (conf->resync_parity) { - conf->resync_parity = 2; - evms_cs_interrupt_thread(thread); - LOG_WARNING - ("%s: parity resync was not fully finished, restarting next time.\n", - __FUNCTION__); - return 1; - } - return 0; - } - return 0; -} - -static int -raid5_restart_resync(mddev_t * mddev) -{ - raid5_conf_t *conf = mddev_to_conf(mddev); - - if (conf->resync_parity) { - if (!conf->resync_thread) { - MD_BUG(); - return 0; - } - LOG_DEFAULT("%s: waking up raid5resync.\n", __FUNCTION__); - conf->resync_parity = 1; - evms_cs_wakeup_thread(conf->resync_thread); - return 1; - } else - LOG_DEFAULT("%s: no restart-resync needed.\n", __FUNCTION__); - return 0; -} - -static int -raid5_stop(mddev_t * mddev) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - - if (conf != NULL) { - if (conf->resync_thread) - evms_cs_unregister_thread(conf->resync_thread); - evms_cs_unregister_thread(conf->thread); - shrink_stripes(conf, conf->max_nr_stripes); - free_pages((unsigned long) conf->stripe_hashtbl, - HASH_PAGES_ORDER); - kfree(conf); - mddev->private = NULL; - } - MOD_DEC_USE_COUNT; - return 0; -} - -#if RAID5_DEBUG -static void -print_sh(struct stripe_head *sh) -{ - int i; - - LOG_DEFAULT("sh %lu, size %d, pd_idx %d, state %ld.\n", sh->sector, - sh->size, sh->pd_idx, sh->state); - LOG_DEFAULT("sh %lu, count %d.\n", sh->sector, - atomic_read(&sh->count)); - LOG_DEFAULT("sh %lu, ", sh->sector); - for (i = 0; i < MD_SB_DISKS; i++) { - if (sh->bh_cache[i]) - LOG_DEFAULT("(cache%d: %p %ld) ", i, sh->bh_cache[i], - sh->bh_cache[i]->b_state); - } - LOG_DEFAULT("\n"); -} - -static void -printall(raid5_conf_t * conf) -{ - struct stripe_head *sh; - int i; - - md_spin_lock_irq(&conf->device_lock); - for (i = 0; i < NR_HASH; i++) { - sh = conf->stripe_hashtbl[i]; - for (; sh; sh = sh->hash_next) { - if (sh->raid_conf != conf) - continue; - print_sh(sh); - } - } - md_spin_unlock_irq(&conf->device_lock); -} -#endif - -static int -raid5_status(char *page, mddev_t * mddev) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - mdp_super_t *sb = mddev->sb; - int sz = 0, i; - - sz += - sprintf(page + sz, " level %d, %dk chunk, algorithm %d", sb->level, - sb->chunk_size >> 10, sb->layout); - sz += - sprintf(page + sz, " [%d/%d] [", conf->raid_disks, - conf->working_disks); - for (i = 0; i < conf->raid_disks; i++) - sz += - sprintf(page + sz, "%s", - conf->disks[i].operational ? "U" : "_"); - sz += sprintf(page + sz, "]"); -#if RAID5_DEBUG -#define D(x) \ - sz += sprintf (page+sz, "<"#x":%d>", atomic_read(&conf->x)) - printall(conf); -#endif - return sz; -} - -static void -print_raid5_conf(raid5_conf_t * conf) -{ - int i; - struct disk_info *tmp; - - LOG_DEFAULT("RAID5 conf printout:\n"); - if (!conf) { - LOG_DEFAULT("(conf==NULL)\n"); - return; - } - LOG_DEFAULT(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, - conf->working_disks, conf->failed_disks); - -#if RAID5_DEBUG - for (i = 0; i < MD_SB_DISKS; i++) { -#else - for (i = 0; i < conf->working_disks + conf->failed_disks; i++) { -#endif - tmp = conf->disks + i; - LOG_DEFAULT(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", - i, tmp->spare, tmp->operational, - tmp->number, tmp->raid_disk, tmp->used_slot, - evms_md_partition_name(tmp->node)); - } -} - -static int -raid5_diskop(mddev_t * mddev, mdp_disk_t ** d, int state) -{ - int err = 0; - int i, failed_disk = -1, spare_disk = -1, removed_disk = -1; - raid5_conf_t *conf = mddev->private; - struct disk_info *tmp, *sdisk, *fdisk, *rdisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc; - mdk_rdev_t *spare_rdev, *failed_rdev; - - print_raid5_conf(conf); - md_spin_lock_irq(&conf->device_lock); - /* - * find the disk ... - */ - switch (state) { - - case DISKOP_SPARE_ACTIVE: - - /* - * Find the failed disk within the RAID5 configuration ... - * (this can only be in the first conf->raid_disks part) - */ - for (i = 0; i < conf->raid_disks; i++) { - tmp = conf->disks + i; - if ((!tmp->operational && !tmp->spare) || - !tmp->used_slot) { - failed_disk = i; - break; - } - } - /* - * When we activate a spare disk we _must_ have a disk in - * the lower (active) part of the array to replace. - */ - if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - /* fall through */ - - case DISKOP_SPARE_WRITE: - case DISKOP_SPARE_INACTIVE: - - /* - * Find the spare disk ... (can only be in the 'high' - * area of the array) - */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_REMOVE_SPARE: - - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (tmp->used_slot && (tmp->number == (*d)->number)) { - if (tmp->operational) { - err = -EBUSY; - goto abort; - } else if (!tmp->spare) { - MD_BUG(); - err = 1; - goto abort; - } - removed_disk = i; - break; - } - } - if (removed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_REMOVE_DISK: - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (tmp->used_slot && (tmp->number == (*d)->number)) { - if (i < conf->raid_disks) { - if (conf->working_disks != - conf->raid_disks) { - /* - * Can't remove a disk from an - * array that is running in - * degrade mode. - */ - err = -EBUSY; - goto abort; - } - if (sb->spare_disks == 0) { - /* - * Must have a spare ready - * before removing an active - * disk. - */ - err = -EBUSY; - goto abort; - } - } - removed_disk = i; - break; - } - } - if (removed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_ADD_DISK: - err = -ENOSYS; - goto abort; - break; - } - - switch (state) { - /* - * Switch the spare disk to write-only mode: - */ - case DISKOP_SPARE_WRITE: - if (conf->spare) { - MD_BUG(); - err = 1; - goto abort; - } - sdisk = conf->disks + spare_disk; - sdisk->operational = 1; - sdisk->write_only = 1; - conf->spare = sdisk; - break; - /* - * Deactivate a spare disk: - */ - case DISKOP_SPARE_INACTIVE: - sdisk = conf->disks + spare_disk; - sdisk->operational = 0; - sdisk->write_only = 0; - /* - * Was the spare being resynced? - */ - if (conf->spare == sdisk) - conf->spare = NULL; - break; - /* - * Activate (mark read-write) the (now sync) spare disk, - * which means we switch it's 'raid position' (->raid_disk) - * with the failed disk. (only the first 'conf->raid_disks' - * slots are used for 'real' disks and we must preserve this - * property) - */ - case DISKOP_SPARE_ACTIVE: - if (!conf->spare) { - MD_BUG(); - err = 1; - goto abort; - } - sdisk = conf->disks + spare_disk; - fdisk = conf->disks + failed_disk; - - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if (spare_desc != *d) { - MD_BUG(); - err = 1; - goto abort; - } - - if (spare_desc->raid_disk != sdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (sdisk->raid_disk != spare_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (fdisk->raid_disk != failed_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - /* - * do the switch finally - */ - spare_rdev = evms_md_find_rdev_nr(mddev, spare_desc->number); - failed_rdev = evms_md_find_rdev_nr(mddev, failed_desc->number); - - /* There must be a spare_rdev, but there may not be a - * failed_rdev. That slot might be empty... - */ - spare_rdev->desc_nr = failed_desc->number; - if (failed_rdev) - failed_rdev->desc_nr = spare_desc->number; - - xchg_values(*spare_desc, *failed_desc); - xchg_values(*fdisk, *sdisk); - - /* - * (careful, 'failed' and 'spare' are switched from now on) - * - * we want to preserve linear numbering and we want to - * give the proper raid_disk number to the now activated - * disk. (this means we switch back these values) - */ - - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); - xchg_values(sdisk->number, fdisk->number); - - *d = failed_desc; - - //if (sdisk->dev == MKDEV(0,0)) - if (sdisk->node == NULL) - sdisk->used_slot = 0; - - /* - * this really activates the spare. - */ - fdisk->spare = 0; - fdisk->write_only = 0; - - /* - * if we activate a spare, we definitely replace a - * non-operational disk slot in the 'low' area of - * the disk array. - */ - conf->failed_disks--; - conf->working_disks++; - conf->spare = NULL; - - break; - - case DISKOP_HOT_REMOVE_SPARE: - rdisk = conf->disks + removed_disk; - - if (rdisk->spare && (removed_disk < conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - if (conf->spare != NULL) { - if (conf->spare->number == removed_disk) { - conf->spare = NULL; - } - } - - rdisk->dev = MKDEV(0, 0); - rdisk->node = NULL; - rdisk->used_slot = 0; - - break; - - case DISKOP_HOT_REMOVE_DISK: - rdisk = conf->disks + removed_disk; - if (rdisk->operational) { - /* We're removing a running disk in the array. */ - conf->working_disks--; - conf->failed_disks++; - } - rdisk->dev = MKDEV(0, 0); - rdisk->node = NULL; - rdisk->used_slot = 0; - rdisk->operational = 0; - break; - - default: - MD_BUG(); - err = 1; - goto abort; - } - abort: - md_spin_unlock_irq(&conf->device_lock); - print_raid5_conf(conf); - return err; -} - -static int -raid5_bmap(mddev_t * mddev, - u64 * rsector, - struct evms_logical_node ** node) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - const unsigned int raid_disks = conf->raid_disks; - const unsigned int data_disks = raid_disks - 1; - unsigned int dd_idx, pd_idx; - - *rsector = (u64) raid5_compute_sector( (unsigned long) *rsector, - raid_disks, data_disks, - &dd_idx, &pd_idx, conf); - *node = conf->disks[dd_idx].node; - return 0; /* always successful */ -} - -static int -raid5_evms_ioctl(mddev_t * mddev, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct evms_logical_node *node; - - switch (cmd) { - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = (struct evms_get_bmap_pkt *)arg; - rc = raid5_bmap(mddev, &bmap->rsector, &node); - if (!rc) { - if (node) - rc = IOCTL(node, inode, file, cmd, arg); - else - rc = -ENODEV; - } - break; - } - - default: - rc = -EINVAL; - } - return rc; -} - -#define MAX_IO_SIZE 128 -static int -raid5_pers_ioctl(mddev_t * mddev, int cmd, void *args) -{ - - int rc = 0; - struct r5_sync_io init_io_args; - void *data; - int io_size = MAX_IO_SIZE; - - LOG_DETAILS("%s: cmd == %d.\n", __FUNCTION__, cmd); - switch (cmd) { - case EVMS_MD_RAID5_INIT_IO: - - if (copy_from_user - (&init_io_args, (struct r5_sync_io *) args, - sizeof (init_io_args))) { - return -EFAULT; - } - /* allocate a io buffer upto 64Kbytes in size */ - if (init_io_args.nr_sects < MAX_IO_SIZE) - io_size = init_io_args.nr_sects; - - /* allocate buffer large enough to hold a single sector */ - data = kmalloc(io_size << EVMS_VSECTOR_SIZE_SHIFT, GFP_KERNEL); - if (!data) { - rc = -ENOMEM; - } else { - u64 io_sector_offset, io_remaining; - u64 io_bytes; - u_char *user_buffer_ptr; - - io_remaining = init_io_args.nr_sects; - io_sector_offset = 0; - user_buffer_ptr = init_io_args.data; - while (io_remaining) { - /* compute the io_size for this pass */ - io_size = (io_remaining >= MAX_IO_SIZE) ? - MAX_IO_SIZE : io_remaining; - - io_bytes = io_size << EVMS_VSECTOR_SIZE_SHIFT; - if (init_io_args.rw == WRITE) { - if (copy_from_user(data, - user_buffer_ptr, - io_bytes)) - rc = -EFAULT; - } - if (rc) - break; - - rc = evms_md_sync_io(mddev->node, - init_io_args.rw, - init_io_args.lsn + - io_sector_offset, io_size, - data); - - if (rc) - break; - - if (init_io_args.rw != WRITE) { - if (copy_to_user(user_buffer_ptr, - data, io_bytes)) - rc = -EFAULT; - } - if (rc) - break; - - user_buffer_ptr += io_bytes; - io_sector_offset += io_size; - io_remaining -= io_size; - } - } - break; - - default: - rc = -ENOSYS; - } - - return rc; -} - -static mdk_personality_t raid5_personality = { - .name = "evms_raid5", - .read = raid5_read, - .write = raid5_write, - .run = raid5_run, - .stop = raid5_stop, - .status = raid5_status, - .error_handler = raid5_error, - .diskop = raid5_diskop, - .stop_resync = raid5_stop_resync, - .restart_resync = raid5_restart_resync, - .sync_request = raid5_sync_request, - .evms_ioctl = raid5_evms_ioctl, - .md_pers_ioctl = raid5_pers_ioctl -}; - -static int md__init -raid5_init(void) -{ - return evms_register_md_personality(RAID5, &raid5_personality); -} - -static void -raid5_exit(void) -{ - evms_unregister_md_personality(RAID5); -} - -module_init(raid5_init); -module_exit(raid5_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_xor.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_xor.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/md_xor.c 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/md_xor.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,149 +0,0 @@ -/* - * md_xor.c : Multiple Devices driver for Linux - * - * Copyright (C) 1996, 1997, 1998, 1999, 2000, - * Ingo Molnar, Matti Aarnio, Jakub Jelinek, Richard Henderson. - * - * Dispatch optimized RAID-5 checksumming functions. - * - * 'md_xor.c' is an EVMS version of linux/drivers/md/xor.c modified - * by Cuong (Mike) Tran , January 2002. - * - * 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. - */ - -#define BH_TRACE 0 -#include -#include -#include -#include - -#define LOG_PREFIX "md raid5: " -/* The xor routines to use. */ -static struct xor_block_template *active_template; - -void -evms_md_xor_block(unsigned int count, struct buffer_head **bh_ptr) -{ - unsigned long *p0, *p1, *p2, *p3, *p4; - unsigned long bytes = bh_ptr[0]->b_size; - - p0 = (unsigned long *) bh_ptr[0]->b_data; - p1 = (unsigned long *) bh_ptr[1]->b_data; - if (count == 2) { - active_template->do_2(bytes, p0, p1); - return; - } - - p2 = (unsigned long *) bh_ptr[2]->b_data; - if (count == 3) { - active_template->do_3(bytes, p0, p1, p2); - return; - } - - p3 = (unsigned long *) bh_ptr[3]->b_data; - if (count == 4) { - active_template->do_4(bytes, p0, p1, p2, p3); - return; - } - - p4 = (unsigned long *) bh_ptr[4]->b_data; - active_template->do_5(bytes, p0, p1, p2, p3, p4); -} - -/* Set of all registered templates. */ -static struct xor_block_template *template_list; - -#define BENCH_SIZE (PAGE_SIZE) - -static void -do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2) -{ - int speed; - unsigned long now; - int i, count, max; - - tmpl->next = template_list; - template_list = tmpl; - - /* - * Count the number of XORs done during a whole jiffy, and use - * this to calculate the speed of checksumming. We use a 2-page - * allocation to have guaranteed color L1-cache layout. - */ - max = 0; - for (i = 0; i < 5; i++) { - now = jiffies; - count = 0; - while (jiffies == now) { - mb(); - tmpl->do_2(BENCH_SIZE, b1, b2); - mb(); - count++; - mb(); - } - if (count > max) - max = count; - } - - speed = max * (HZ * BENCH_SIZE / 1024); - tmpl->speed = speed; - - LOG_DEFAULT(" %-10s: %5d.%03d MB/sec\n", tmpl->name, - speed / 1000, speed % 1000); -} - -static int -calibrate_xor_block(void) -{ - void *b1, *b2; - struct xor_block_template *f, *fastest; - - b1 = (void *) md__get_free_pages(GFP_KERNEL, 2); - if (! b1) { - LOG_ERROR("Yikes! No memory available.\n"); - return -ENOMEM; - } - b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE; - - LOG_DEFAULT("measuring checksumming speed\n"); - sti(); - -#define xor_speed(templ) do_xor_speed((templ), b1, b2) - - XOR_TRY_TEMPLATES; - -#undef xor_speed - - free_pages((unsigned long)b1, 2); - - fastest = template_list; - for (f = fastest; f; f = f->next) - if (f->speed > fastest->speed) - fastest = f; - -#ifdef XOR_SELECT_TEMPLATE - fastest = XOR_SELECT_TEMPLATE(fastest); -#endif - - active_template = fastest; - LOG_DEFAULT("using function: %s (%d.%03d MB/sec)\n", - fastest->name, fastest->speed / 1000, fastest->speed % 1000); - - return 0; -} - -MD_EXPORT_SYMBOL(evms_md_xor_block); - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -module_init(calibrate_xor_block); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/os2lvm_vge.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/os2lvm_vge.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/os2lvm_vge.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/os2lvm_vge.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,2393 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * 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 - * - */ - -/* - * linux/drivers/evms/os2lvm_vge.c - * - * EVMS OS/2 LVM Emulator - * - * This Volume Group Emulator will take the type 0x35 partitions created by - * OS/2 versions 4.5 and later and build them into volumes. It emulates - * the Drive Linking and Bad Block Relocation features and therefore - * provides binary compatibility with the OS/2 version. Of course, if - * you select to mkfs a file system OS/2 doesn't support, you're on your - * own... - * - * Since OS/2 LVM volumes can only exist on DOS-style partitioned disks, - * this VGE has a dependency on dospart.c to report a list of the - * candidate partitions. This module will then take the appropriate partitions - * from the list and use them to build the OS/2-style volumes. - * - * Change Activity: - * - * 7/01/2001 John Stiles getting started. - * 9/14/2001 John Stiles original version. - * 11/01/2001 John Stiles new naming scheme. - * 11/21/2001 John Stiles i/o path changes. - */ - -#define EVMS_DEBUG 1 -#define EVMS_OS2_DEBUG 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_PREFIX "os2lvm: " - -// Global Structure and Type definitions -struct transfer_record { - int Write_Flag; /* 0 = read, 1 = write */ - struct os2_dl_entry *Partition_Data; - struct buffer_head *bh; - struct transfer_record *next; -}; - -struct tracking_record { /* structure used to track IO requests that must be broken into two pieces due to drive linking */ - unsigned int io_in_progress; - int up_to_date; - struct buffer_head *org_bh; /* Original IO */ - struct buffer_head *link1_bh; /* First child. */ - struct os2_dl_entry *link1_data; - struct transfer_record *link1_transfer_rec; - int link1_bbr_attempted; - struct buffer_head *link2_bh; /* Second child */ - struct os2_dl_entry *link2_data; - struct transfer_record *link2_transfer_rec; - int link2_bbr_attempted; -}; - -// Prototypes for local VGE functions -static int discover_os2lvm_partitions(struct evms_logical_node **); -static struct evms_logical_node *find_os2_volume(u32); -static int add_os2link(struct os2_dl_entry *, - struct evms_logical_node *); -static struct os2_dl_entry - *find_link_data(struct os2_dl_entry **, u32); -static int find_drive_link(struct evms_logical_node *, - struct os2_dl_entry **, u64 *, u64 *); -static int validate_signaturesector(struct evms_logical_node *, - LVM_Signature_Sector *, u32); -static int validate_drivelinksector(void *, int, u32); -static int validate_bbrtablesector(void *, int, u32); -static u32 check_for_os2_bbr_relocations(char *); -static int check_os2_volumes(struct evms_logical_node **); -static int OS2_ioctl_cmd_broadcast(struct evms_logical_node *node, - struct inode *inode, struct file *file, - unsigned long cmd, unsigned long arg); -static int os2_ioctl_cmd_plugin_ioctl(struct evms_logical_node *node, - struct inode *inode, struct file *file, - unsigned long cmd, unsigned long arg); -static void BBR_Worker(void *); -static void OS2_BBR_Write_Callback(struct transfer_record * Transfer_Record, - struct buffer_head *bh, - int uptodate, int *redrive); -static void BBR_Transfer_IO(struct transfer_record * Transfer_Record); -static void OS2_DL_Callback(struct buffer_head *bh, int uptodate); -static int Sector_Is_Remapped(struct os2_dl_entry * io_dlentry, - u64 Source_Sector, u64 * Replacement_Sector); -static void Invalidate_Mapping(struct os2_dl_entry * io_dlentry, - u64 Source_Sector, - int Replacement_Sector_Is_Bad); -static int Create_New_BBR_Table_Entry(struct os2_dl_entry * - io_dlentry, u64 starting_lsn, - unsigned int count, void *buffer); -static void Clone_Bufferhead(struct buffer_head *Source, - struct buffer_head *Child); - -// Prototypes for local memory allocation/deallocation functions -static struct os2_dl_entry *new_os2_drive_link(LVM_Signature_Sector *, - struct - evms_logical_node *); -static char *new_os2_link_data(u32, u32, u32, struct evms_logical_node *); -static char *new_os2_bbr_data(u32, u32, u32, struct evms_logical_node *); -static struct evms_logical_node *new_os2volume(u32, char *); -static int delete_os2lvm_volume(struct evms_logical_node *); -static int delete_os2_drive_link(struct os2_dl_entry *, int); - -// Prototypes for Function Table interface -static int discover_os2lvm(struct evms_logical_node **); -static int delete_os2lvm(struct evms_logical_node *); -static void read_os2lvm(struct evms_logical_node *, struct buffer_head *); -static void write_os2lvm(struct evms_logical_node *, struct buffer_head *); -static int init_io_os2lvm(struct evms_logical_node *, int, u64, u64, void *); -static int ioctl_os2lvm(struct evms_logical_node *, struct inode *, - struct file *, unsigned int, unsigned long); -static int do_os2_bbr_io(struct os2_dl_entry *, int, u64, u64, - void *); - -// Global data structures -static struct evms_logical_node *os2lvm_nodes = NULL; -static struct evms_thread *BBR_Worker_Thread = NULL; -static spinlock_t BBR_Queue_Lock = SPIN_LOCK_UNLOCKED; -static const char *BBR_Worker_Name = "evms_os2_bbr_io"; -static struct transfer_record *BBR_IO_List_Head = NULL; -static struct transfer_record *BBR_IO_List_Tail = NULL; -static struct evms_pool_mgmt *BBR_Transfer_Pool = NULL; -static char *BBR_Transfer_Pool_Name = "OS-2 Transfer Pool"; -static char *DL_Tracking_Pool_Name = "OS-2 Tracking Pool"; -static struct evms_pool_mgmt *DL_Tracking_Pool = NULL; - -// Required plug-in Function Table definition -static struct evms_plugin_fops function_table = { - .discover = discover_os2lvm, - .delete = delete_os2lvm, - .read = read_os2lvm, - .write = write_os2lvm, - .init_io = init_io_os2lvm, - .ioctl = ioctl_os2lvm -}; - -// Required plug-in Header definition -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_REGION_MANAGER, - 2), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2 - }, - .required_services_version = { - .major = EVMS_COMMON_SERVICES_MAJOR, - .minor = EVMS_COMMON_SERVICES_MINOR, - .patchlevel = EVMS_COMMON_SERVICES_PATCHLEVEL - }, - .fops = &function_table -}; - -// Required Plugin Functions - -/* - * Function: discover_os2lvm - * - * This is the entry point into the discovery process. - */ -static int -discover_os2lvm(struct evms_logical_node **evms_partition_list) -{ - int rc; - - MOD_INC_USE_COUNT; - - if (!BBR_Transfer_Pool) { - BBR_Transfer_Pool = - evms_cs_create_pool(sizeof (struct transfer_record), - BBR_Transfer_Pool_Name, NULL, NULL); - if (!BBR_Transfer_Pool) { - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - } - - if (!DL_Tracking_Pool) { - DL_Tracking_Pool = - evms_cs_create_pool(sizeof (struct tracking_record), - DL_Tracking_Pool_Name, NULL, NULL); - if (!DL_Tracking_Pool) { - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - } - - rc = discover_os2lvm_partitions(evms_partition_list); - - if (!rc) { - rc = check_os2_volumes(evms_partition_list); - } - - MOD_DEC_USE_COUNT; - return rc; -} - -/* - * Function: delete_os2lvm - * - * This is the entry point for deleting a node. - */ -static int -delete_os2lvm(struct evms_logical_node *logical_node) -{ - LOG_EXTRA("Deleting volume: %s\n", logical_node->name); - - return delete_os2lvm_volume(logical_node); -} - -/* - * Function: read_os2lvm - */ -static void -read_os2lvm(struct evms_logical_node *node, struct buffer_head *bh) -{ - int rc; - u64 sector_count; - u64 rsector; - struct buffer_head *Link1 = NULL; - struct buffer_head *Link2 = NULL; - struct tracking_record *Tracking_Record = NULL; - struct os2_dl_entry *cur_dlentry = NULL; - struct transfer_record *Transfer_Record; - - rsector = bh->b_rsector; - sector_count = bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - rc = find_drive_link(node, &cur_dlentry, &rsector, §or_count); - bh->b_rsector = rsector; - switch (rc) { - case 1: - if (cur_dlentry->bbr_is_active) { - Transfer_Record = evms_cs_allocate_from_pool(BBR_Transfer_Pool, 1); /* Block until we get a transfer record. */ - /* Transfer the IO to the BBR Worker Thread. */ - Transfer_Record->Write_Flag = 0; - Transfer_Record->Partition_Data = cur_dlentry; - Transfer_Record->bh = bh; - Transfer_Record->next = NULL; - BBR_Transfer_IO(Transfer_Record); - } else - R_IO(cur_dlentry->link_partition, bh); - break; - case 2: - /* We must split the IO. Duplicate the buffer head twice and allocate the tracking record. */ - Tracking_Record = evms_cs_allocate_from_pool(DL_Tracking_Pool, 1); /* Block until we get a tracking record. */ - Link1 = evms_cs_allocate_from_pool(evms_bh_pool, 1); - Link2 = evms_cs_allocate_from_pool(evms_bh_pool, 1); - - /* Initialize the tracking record so we can associate the two new I/Os with the original. */ - Tracking_Record->io_in_progress = 2; - Tracking_Record->up_to_date = 0; - Tracking_Record->org_bh = bh; - - /* Create the I/O to the first link. */ - Clone_Bufferhead(bh, Link1); - Link1->b_private = Tracking_Record; - Link1->b_end_io = OS2_DL_Callback; - Link1->b_size = sector_count << EVMS_VSECTOR_SIZE_SHIFT; - Tracking_Record->link1_bh = Link1; - Tracking_Record->link1_data = cur_dlentry; - Tracking_Record->link1_bbr_attempted = 0; - Tracking_Record->link1_transfer_rec = NULL; - - /* Create the I/O to the second link */ - Clone_Bufferhead(bh, Link2); - Link2->b_private = Tracking_Record; - Link2->b_end_io = OS2_DL_Callback; - Link2->b_data += sector_count << EVMS_VSECTOR_SIZE_SHIFT; - Link2->b_rsector = 0; - Link2->b_size = - bh->b_size - (sector_count << EVMS_VSECTOR_SIZE_SHIFT); - Tracking_Record->link2_bh = Link2; - Tracking_Record->link2_data = cur_dlentry->next; - Tracking_Record->link2_bbr_attempted = 0; - Tracking_Record->link2_transfer_rec = NULL; - - /* Process the I/O to the first link. */ - if (cur_dlentry->bbr_is_active) { - Transfer_Record = evms_cs_allocate_from_pool(BBR_Transfer_Pool, 1); /* Block until we get a transfer record. */ - /* Transfer the IO to the BBR Worker Thread. */ - Transfer_Record->Write_Flag = 0; - Transfer_Record->Partition_Data = cur_dlentry; - Transfer_Record->bh = Tracking_Record->link1_bh; - Transfer_Record->next = NULL; - BBR_Transfer_IO(Transfer_Record); - } else - R_IO(cur_dlentry->link_partition, - Tracking_Record->link1_bh); - - /* Process the I/O to the second link. */ - cur_dlentry = cur_dlentry->next; - if (cur_dlentry->bbr_is_active) { - Transfer_Record = evms_cs_allocate_from_pool(BBR_Transfer_Pool, 1); /* Block until we get a transfer record. */ - /* Transfer the IO to the BBR Worker Thread. */ - Transfer_Record->Write_Flag = 0; - Transfer_Record->Partition_Data = cur_dlentry; - Transfer_Record->bh = Tracking_Record->link2_bh; - Transfer_Record->next = NULL; - BBR_Transfer_IO(Transfer_Record); - } else - R_IO(cur_dlentry->link_partition, - Tracking_Record->link2_bh); - - break; - default: - LOG_SERIOUS("READ error, request exceeds volume size.\n"); - bh->b_end_io(bh, 0); - break; - } -} - -/* - * Function: write_os2lvm - */ -static void -write_os2lvm(struct evms_logical_node *node, struct buffer_head *bh) -{ - int rc; - u64 rsector; - u64 sector_count; - struct buffer_head *Link1 = NULL; - struct buffer_head *Link2 = NULL; - struct tracking_record *Tracking_Record = NULL; - struct os2_dl_entry *cur_dlentry = NULL; - struct transfer_record *Transfer_Record; - - rsector = bh->b_rsector; - sector_count = bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT; - rc = find_drive_link(node, &cur_dlentry, &rsector, §or_count); - bh->b_rsector = rsector; - switch (rc) { - case 1: - /* Set up a Transfer Record. If there are Bad Blocks on the partition that this I/O is - directed to, then we will need the Transfer Record to put the I/O in the queue for the - BBR Worker Thread. If there are no bad blocks, then we will need the Transfer Record - for the OS2_BBR_Write_Callback function. This function expects the Transfer Record to - be pre-allocated and available because it is running on an interrupt thread and should - not do memory allocation. If there is an error during the write, then the - OS2_BBR_Write_Callback function will use the Transfer Record to transfer the I/O - to the BBR worker thread for further processing. If there are no errors during the I/O, - then the OS2_BBR_Write_Callback will deallocate the Transfer Record. */ - Transfer_Record = evms_cs_allocate_from_pool(BBR_Transfer_Pool, 1); /* Block until we get a transfer record. */ - Transfer_Record->Write_Flag = 1; - Transfer_Record->Partition_Data = cur_dlentry; - Transfer_Record->bh = bh; - Transfer_Record->next = NULL; - if (cur_dlentry->bbr_is_active) { - /* Transfer the IO to the BBR Worker Thread. */ - BBR_Transfer_IO(Transfer_Record); - } else { - evms_cs_register_for_end_io_notification - (Transfer_Record, bh, OS2_BBR_Write_Callback); - W_IO(cur_dlentry->link_partition, bh); - } - break; - case 2: - /* We must split the IO. Duplicate the buffer head twice and allocate the tracking record. */ - Tracking_Record = evms_cs_allocate_from_pool(DL_Tracking_Pool, 1); /* Block until we get a tracking record. */ - Link1 = evms_cs_allocate_from_pool(evms_bh_pool, 1); - Link2 = evms_cs_allocate_from_pool(evms_bh_pool, 1); - - /* Initialize the tracking record so we can associate the two new I/Os with the original. */ - Tracking_Record->io_in_progress = 2; - Tracking_Record->up_to_date = 0; - Tracking_Record->org_bh = bh; - - /* Create the I/O to the first link. */ - Clone_Bufferhead(bh, Link1); - Link1->b_private = Tracking_Record; - Link1->b_end_io = OS2_DL_Callback; - Link1->b_size = sector_count << EVMS_VSECTOR_SIZE_SHIFT; - Tracking_Record->link1_bh = Link1; - Tracking_Record->link1_data = cur_dlentry; - - /* Create the I/O to the second link */ - Clone_Bufferhead(bh, Link2); - Link2->b_private = Tracking_Record; - Link2->b_end_io = OS2_DL_Callback; - Link2->b_data += sector_count << EVMS_VSECTOR_SIZE_SHIFT; - Link2->b_rsector = 0; - Link2->b_size = - bh->b_size - (sector_count << EVMS_VSECTOR_SIZE_SHIFT); - Tracking_Record->link2_bh = Link2; - Tracking_Record->link2_data = cur_dlentry->next; - - Transfer_Record = evms_cs_allocate_from_pool(BBR_Transfer_Pool, 1); /* Block until we get a transfer record. */ - Transfer_Record->Write_Flag = 1; - Transfer_Record->Partition_Data = cur_dlentry; - Transfer_Record->bh = Tracking_Record->link1_bh; - Transfer_Record->next = NULL; - Tracking_Record->link1_transfer_rec = Transfer_Record; - /* Process the I/O to the first link. */ - if (cur_dlentry->bbr_is_active) { - /* Transfer the IO to the BBR Worker Thread. */ - Tracking_Record->link1_bbr_attempted = 1; - BBR_Transfer_IO(Transfer_Record); - } else { - Tracking_Record->link1_bbr_attempted = 0; - W_IO(cur_dlentry->link_partition, - Tracking_Record->link1_bh); - } - - /* Process the I/O to the second link. */ - cur_dlentry = cur_dlentry->next; - Transfer_Record = evms_cs_allocate_from_pool(BBR_Transfer_Pool, 1); /* Block until we get a transfer record. */ - Transfer_Record->Write_Flag = 1; - Transfer_Record->Partition_Data = cur_dlentry; - Transfer_Record->bh = Tracking_Record->link2_bh; - Transfer_Record->next = NULL; - Tracking_Record->link2_transfer_rec = Transfer_Record; - if (cur_dlentry->bbr_is_active) { - /* Transfer the IO to the BBR Worker Thread. */ - Tracking_Record->link2_bbr_attempted = 1; - BBR_Transfer_IO(Transfer_Record); - } else { - Tracking_Record->link2_bbr_attempted = 0; - W_IO(cur_dlentry->link_partition, - Tracking_Record->link2_bh); - } - - break; - default: - LOG_SERIOUS("WRITE error, request exceeds volume size.\n"); - bh->b_end_io(bh, 0); - break; - } -} - -static int -os2_ioctl_cmd_plugin_ioctl(struct evms_logical_node *node, - struct inode *inode, - struct file *file, - unsigned long cmd, unsigned long arg) -{ - int rc = 0; - os2_volume_runtime_entry_t *Node_Data; - struct os2_dl_entry *curlink, *nextlink; - struct evms_plugin_ioctl_pkt tmp, *user_parms; - - user_parms = (struct evms_plugin_ioctl_pkt *) arg; - /* copy user's parameters to kernel space */ - if (copy_from_user(&tmp, user_parms, sizeof (tmp))) - rc = -EFAULT; - - if (!rc) { - Node_Data = (os2_volume_runtime_entry_t *) node->private; - /* is this cmd targetted at this feature ? */ - if (tmp.feature_id == node->plugin->id) { - switch (tmp.feature_command) { - default: - break; - } - } else { /* broadcast this cmd to all children */ - curlink = Node_Data->drive_link; - - /* broadcast this cmd to all children */ - while (curlink) { - nextlink = curlink->next; - - rc = IOCTL(curlink->link_partition, inode, file, - cmd, arg); - - if (rc) { - break; - } - curlink = nextlink; - } - - } - /* copy info to userspace */ - if (copy_to_user(user_parms, &tmp, sizeof (tmp))) - rc = -EFAULT; - } - return (rc); -} - -static int -OS2_ioctl_cmd_broadcast(struct evms_logical_node *node, - struct inode *inode, - struct file *file, unsigned long cmd, unsigned long arg) -{ - int rc = 0; - os2_volume_runtime_entry_t *Node_Data; - struct os2_dl_entry *curlink, *nextlink; - - Node_Data = (os2_volume_runtime_entry_t *) node->private; - curlink = Node_Data->drive_link; - - /* broadcast this cmd to all children */ - while (curlink) { - nextlink = curlink->next; - - rc |= IOCTL(curlink->link_partition, inode, file, cmd, arg); - - curlink = nextlink; - } - - return (rc); -} - -/* - * Function: ioctl_os2lvm - */ -static int -ioctl_os2lvm(struct evms_logical_node *logical_node, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - u64 Sectors_Per_Cylinder; - u64 Total_Sectors; - struct evms_logical_node *partition_node; - - partition_node = - ((os2_volume_runtime_entry_t *) logical_node->private)->drive_link-> - link_partition; - - if (!inode) - return -EINVAL; - - LOG_EVERYTHING("Ioctl %d\n", cmd); - - switch (cmd) { - case HDIO_GETGEO: - { - // Return fake geometry - struct hd_geometry *hd = (struct hd_geometry *) arg; - short cylinders; - unsigned char heads = 255; - unsigned char sectors = - OS2LVM_SYNTHETIC_SECTORS_PER_TRACK; - long start = 0; - - /* OS/2 always created a fake geometry using the maximum cylinder size. */ - Sectors_Per_Cylinder = heads * sectors; - for (cylinders = 0, Total_Sectors = 0; - Total_Sectors < - ((os2_volume_runtime_entry_t *) logical_node-> - private)->size_in_sectors; cylinders++) - Total_Sectors += Sectors_Per_Cylinder; - - cylinders--; - - if (copy_to_user - ((short *) (&hd->cylinders), &cylinders, - sizeof (cylinders)) - || copy_to_user((char *) (&hd->heads), &heads, - sizeof (heads)) - || copy_to_user((char *) (&hd->sectors), §ors, - sizeof (sectors)) - || copy_to_user((long *) (&hd->start), &start, - sizeof (start))) { - return -EFAULT; - } - } - break; - - case EVMS_GET_BMAP: - // No kernel images allowed on OS/2 volumes right now. - rc = -EINVAL; - break; - - case EVMS_QUIESCE_VOLUME: - case EVMS_GET_DISK_LIST: - case EVMS_CHECK_MEDIA_CHANGE: - case EVMS_REVALIDATE_DISK: - case EVMS_OPEN_VOLUME: - case EVMS_CLOSE_VOLUME: - case EVMS_CHECK_DEVICE_STATUS: - rc = OS2_ioctl_cmd_broadcast(logical_node, inode, file, cmd, - arg); - break; - case EVMS_PLUGIN_IOCTL: - rc = os2_ioctl_cmd_plugin_ioctl(logical_node, inode, file, cmd, - arg); - break; - default: - rc = -EINVAL; - break; - } - - return rc; -} - -/* - * Function: init_io_os2lvm - */ -static int -init_io_os2lvm(struct evms_logical_node *node, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr) -{ /* buffer address */ - int rc = 0; - u64 sector_count; - struct evms_logical_node *partition_node; - struct os2_dl_entry *cur_dlentry = NULL; - - sector_count = num_sects; - rc = find_drive_link(node, &cur_dlentry, §_nr, §or_count); - switch (rc) { - case 1: - partition_node = cur_dlentry->link_partition; - if (cur_dlentry->bbr_is_active) - rc = do_os2_bbr_io(cur_dlentry, io_flag, sect_nr, - num_sects, buf_addr); - else { - rc = INIT_IO(partition_node, io_flag, sect_nr, - num_sects, buf_addr); - if (rc && io_flag) { - cur_dlentry->bbr_is_active = 1; - rc = do_os2_bbr_io(cur_dlentry, io_flag, - sect_nr, num_sects, - buf_addr); - } - } - break; - case 2: - partition_node = cur_dlentry->link_partition; - if (cur_dlentry->bbr_is_active) - rc = do_os2_bbr_io(cur_dlentry, io_flag, sect_nr, - sector_count, buf_addr); - else { - rc = INIT_IO(partition_node, io_flag, sect_nr, - sector_count, buf_addr); - if (rc && io_flag) { - cur_dlentry->bbr_is_active = 1; - rc = do_os2_bbr_io(cur_dlentry, io_flag, - sect_nr, sector_count, - buf_addr); - } - } - - if (!rc) { - cur_dlentry = cur_dlentry->next; - partition_node = cur_dlentry->link_partition; - num_sects -= sector_count; - buf_addr += sector_count << OS2_SECTOR_SHIFT; - rc = 1; - if (cur_dlentry->bbr_is_active) - rc = do_os2_bbr_io(cur_dlentry, io_flag, 0, - num_sects, buf_addr); - else { - rc = INIT_IO(partition_node, io_flag, 0, - num_sects, buf_addr); - if (rc && io_flag) { - cur_dlentry->bbr_is_active = 1; - rc = do_os2_bbr_io(cur_dlentry, io_flag, - 0, num_sects, - buf_addr); - } - - } - } - break; - default: - LOG_SERIOUS("INITIO error, request exceeds volume size.\n"); - break; - } - - return rc; -} - -/* - * Function: do_os2_bbr_io - * - * Check the Bad Block Relocation list for relocated sectors. If any are found, - * this function will do the i/o directly. - * Return values: 0 == i/o done, 1 == unable to complete i/o - */ -static int -do_os2_bbr_io(struct os2_dl_entry * io_dlentry, int rw, /* 0=read, 1=write */ - u64 starting_lsn, /* disk LBA */ - u64 count, /* # of sectors */ - void *buffer) -{ /* buffer address */ - u64 lsn, remapped_lsn; - int rc; - - // For each sector in this request, check if this sector has already - // been remapped. If so, process all previous sectors in this request, - // followed by the remapped sector. Then reset the starting lsn and - // count and keep going with the rest of the request as if it were - // a whole new request. - for (lsn = 0; lsn < count; lsn++) { - remapped_lsn = starting_lsn + lsn; - rc = Sector_Is_Remapped(io_dlentry, remapped_lsn, - &remapped_lsn); - if (rc) { - // Process all sectors in the request up to this one. - if (lsn > 0) { - rc = INIT_IO(io_dlentry->link_partition, rw, - starting_lsn, lsn, buffer); - if (rc) { - /* If this is a read, then we are done. */ - if (!rw) { - return 1; - } - - /* Since this was a write, we must see if we can remap the bad sector to a replacement sector. */ - if (!Create_New_BBR_Table_Entry - (io_dlentry, starting_lsn, lsn, - buffer)) { - /* We were unable to remap the bad sector(s) in the I/O. We can not complete the I/O. */ - return 1; - } - } - buffer += (lsn * OS2_BYTES_PER_SECTOR); - } - // Process the remapped sector. - rc = INIT_IO(io_dlentry->link_partition, rw, - remapped_lsn, 1, buffer); - if (rc) { - /* If this is a read, then we are done. */ - if (!rw) { - return 1; - } - - /* Get the original sector that was remapped. */ - remapped_lsn = starting_lsn + lsn; - - /* Invalidate the current remapping. */ - Invalidate_Mapping(io_dlentry, remapped_lsn, 1); - - /* Try to remap the bad sector to another replacement sector. */ - if (!Create_New_BBR_Table_Entry - (io_dlentry, remapped_lsn, 1, buffer)) { - /* We were unable to remap the bad sector(s) in the I/O. We can not complete the I/O. */ - return 1; - } - - } - - buffer += OS2_BYTES_PER_SECTOR; - - starting_lsn += (lsn + 1); - count -= (lsn + 1); - lsn = -1; - } - - } - - /* Are there any sectors left to process? */ - if (count > 0) { - rc = INIT_IO(io_dlentry->link_partition, rw, starting_lsn, - count, buffer); - if (rc) { - /* If this is a read, then we are done. */ - if (!rw) { - return 1; - } - - /* Since this was a write, we must see if we can remap the bad sector to a replacement sector. */ - if (!Create_New_BBR_Table_Entry - (io_dlentry, starting_lsn, count, buffer)) { - /* We were unable to remap the bad sector(s) in the I/O. We can not complete the I/O. */ - return 1; - } - - } - - } - - return 0; -} - -/* - * Function: os2lvm_vge_init - */ -int __init -os2lvm_vge_init(void) -{ - /* Should I be allocating the pools and BBR Worker Thread here? */ - return evms_cs_register_plugin(&plugin_header); /* register with EVMS */ -} - -void __exit -os2lvm_vge_exit(void) -{ - /* BUGBUG - Is there where I need to kill the BBR Worker Thread and free any memory I am still holding? */ - - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(os2lvm_vge_init); -module_exit(os2lvm_vge_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -// Local VGE Functions - -/* - * Function: discover_os2lvm_partitions - * - * Examine the list of logical partitions. Any type 0x35 partition that contains - * a valid OS/2 signature sector is consumed and added to the appropriate logical - * volume. - */ -static int -discover_os2lvm_partitions(struct evms_logical_node **evms_partition_list) -{ - struct evms_logical_node *evms_partition; - struct evms_logical_node *next_partition; - struct evms_logical_node *new_volume; - u64 sectornum = 0; - u32 volumeserial; - char *sigsect; - char *volumename; - char driveletter[8]; - LVM_Signature_Sector *sigsector; - struct os2_dl_entry *new_dlentry; - - LOG_ENTRY_EXIT("Discovering OS/2 Logical Volumes\n"); - sigsect = kmalloc(OS2_BYTES_PER_SECTOR, GFP_KERNEL); - if (!sigsect) { - LOG_SERIOUS("Could not allocate Signature sector data\n"); - return -ENOMEM; - } - - for (evms_partition = *evms_partition_list; evms_partition; - evms_partition = next_partition) { - // Save the next node. We may remove this one from the list. - next_partition = evms_partition->next; - - // The node must not have the OS/2 vge id. - if (evms_partition->plugin->id == plugin_header.id) { - continue; - } - - LOG_EXTRA("Examining partition serial %s\n", - evms_partition->name); - - // Have to go to the last accessible sector of the partition and - // read it in. It should be the LVM Signature Sector. - sectornum = evms_partition->total_vsectors - 1; - if (INIT_IO(evms_partition, 0, sectornum, 1, sigsect)) { - // On an I/O error, continue on to the next partition. - // This means that the volume it belongs to will be incomplete - // and later deleted in the completeness check. - LOG_SERIOUS("I/O error on Signature sector read\n"); - continue; - } - sigsector = (LVM_Signature_Sector *) sigsect; - - // Validate the Signature Sector - if (validate_signaturesector - (evms_partition, sigsector, OS2_BYTES_PER_SECTOR)) { - LOG_EXTRA("Signature sector is not valid\n"); - continue; - } -// Bugbug - At this point, we have validated an OS/2 LVM Signature Sector. However, if the partition -// is not marked as a type 0x35, then this Signature Sector may be erroneous. The problem here is that -// there is currently no way to find out if this partition was marked as a type 0x35. Also, if we -// should reject this partition due to some problem with the drive linking or BBR metadata, should we -// leave the partition in the evms partition list or not? If the partition was marked as a type 0x35 -// and the Signature Sector was valid, then I would say that we should remove it from the evms partition -// partition list. If the partition is not marked as a type 0x35 but the Signature Sector is valid, then -// we could have a stray Signature Sector, in which case the partition should remain in the evms partition -// list. The OS/2 LVM Signature Sector does have additional information that could be used to resolve -// this issue, such as the starting LBA of the partition that the Signature Sector belongs to, but -// we can not get the starting LBA of the partition to compare against. If we leave the partition in -// the evms partition list when we should not, then an extraneous compatibility volume could result. - // Build the Metadata for this partition - if (! - (new_dlentry = - new_os2_drive_link(sigsector, evms_partition))) { - continue; - } - // Search for the parent Volume for this partition - volumeserial = sigsector->Volume_Serial_Number; - if (!(new_volume = find_os2_volume(volumeserial))) { - - // If not found, allocate a new Volume - LOG_EVERYTHING("Parent not found, allocate new.\n"); - if (sigsector->Drive_Letter != '\0') { - driveletter[0] = sigsector->Drive_Letter; - driveletter[1] = '\0'; - volumename = driveletter; - } else - volumename = sigsector->Volume_Name; - - if (! - (new_volume = - new_os2volume(volumeserial, volumename))) { - delete_os2_drive_link(new_dlentry, 0); - new_dlentry = NULL; - continue; - } - } - // Now remove the partition from the List - evms_cs_remove_logical_node_from_list(evms_partition_list, - evms_partition); - - if (((os2_volume_runtime_entry_t *) new_volume->private)-> - complete) { - // Volume is complete, delete this duplicate - delete_os2_drive_link(new_dlentry, 0); - LOG_EVERYTHING("Deleting duplicate node.\n"); - ((os2_volume_runtime_entry_t *) new_volume->private)->Export_Needed = 1; //We must export this volume again! - } else /* Add this partition to its parent Volume */ - add_os2link(new_dlentry, new_volume); - - } - - kfree(sigsect); - LOG_ENTRY_EXIT("Finished Discovering OS/2 Logical Volumes\n"); - - return 0; -} - -/* - * Function: find_os2_volume - * - * Search for the OS/2 volume that matches the volume serial. - */ -static struct evms_logical_node * -find_os2_volume(u32 volumeserial) -{ - os2_volume_runtime_entry_t *cur_volume; - struct evms_logical_node *cur_node; - - cur_node = os2lvm_nodes; - - while (cur_node) { - cur_volume = (os2_volume_runtime_entry_t *) cur_node->private; - if (cur_volume->Volume_Serial_Number == volumeserial) { - LOG_EVERYTHING("%s: found volser match.\n", - __FUNCTION__); - return cur_node; - } - LOG_EVERYTHING("%s: volser does not match.\n", __FUNCTION__); - cur_node = cur_volume->next_os2lvm_node; - } - - return NULL; -} - -/* - * Function: add_os2link - * - * Add the Drive Link metadata to the parent OS/2 volume. - */ -static int -add_os2link(struct os2_dl_entry * newlink, - struct evms_logical_node *parent_volume) -{ - os2_volume_runtime_entry_t *parent_metadata = - (os2_volume_runtime_entry_t *) parent_volume->private; - struct os2_dl_entry *curlink = - parent_metadata->drive_link, *nextlink; - - if (curlink) { - nextlink = curlink->next; - while (nextlink) { - curlink = nextlink; - nextlink = curlink->next; - } - curlink->next = newlink; - } else { - parent_metadata->drive_link = newlink; - } - parent_metadata->drive_link_count++; - parent_metadata->size_in_sectors += newlink->sector_count; - parent_volume->total_vsectors += newlink->sector_count; - return 0; -} - -/* - * Function: find_link_data - * - * Find the Drive Link metadata that matches the partition serial number. - * Remove it from the link_list passed in. - */ -static struct os2_dl_entry * -find_link_data(struct os2_dl_entry ** link_list, u32 partitionser) -{ - struct os2_dl_entry *curlink = *link_list, *prevlink = NULL; - - while (curlink) { - if (curlink->partition_serial == partitionser) { - if (prevlink) { - prevlink->next = curlink->next; - } else { - *link_list = curlink->next; - } - curlink->next = NULL; - return curlink; - } - prevlink = curlink; - curlink = prevlink->next; - } - - return NULL; -} - -/* - * Function: find_drive_link - * - * Walk the linked list of drive links to find the proper - * target partition. Returns the metadata associated with - * the drive link. - * Return values: 1 == data contained in 1 partition, 2 == data crosses 2 partitions, - * 0 == target partition not found - */ -static int -find_drive_link(struct evms_logical_node *node, - struct os2_dl_entry ** dlentry, - u64 * sector, u64 * num_sectors) -{ - u64 last_link_sector, cur_last_sector; - struct os2_dl_entry *curlink = - ((os2_volume_runtime_entry_t *) node->private)->drive_link, - *nextlink; - - while (curlink) { - nextlink = curlink->next; - last_link_sector = - curlink->start_sector + curlink->sector_count; - if (*sector < last_link_sector) { - *dlentry = curlink; - cur_last_sector = *sector + *num_sectors; - *sector -= curlink->start_sector; - LOG_EVERYTHING - ("I/O start_RBA == "PFU64" , sector_count == "PFU64"\n", - *sector, *num_sectors); - if (cur_last_sector <= last_link_sector) - return 1; - else { - if ((*dlentry)->next) - *num_sectors -= - cur_last_sector - last_link_sector; - else - return 0; - } - return 2; - } - - curlink = nextlink; - } - - return 0; -} - -// Allocation/Deallocation Functions - -/* - * Function: new_os2_drive_link - * - * Allocate space for a new OS/2 drive link structure. - * Initialize the appropriate fields. - * Note: since the BBR info applies to each link, the BBR structures - * are also initialized here. - */ -static struct os2_dl_entry * -new_os2_drive_link(LVM_Signature_Sector * signature_sector, - struct evms_logical_node *evms_partition) -{ - int i; - u32 feature, feature_size, sectoroffset; - struct os2_dl_entry *new_dlentry; - - new_dlentry = - kmalloc(sizeof (struct os2_dl_entry), GFP_KERNEL); - if (!new_dlentry) { - LOG_SERIOUS("Could not allocate drivelink metadata\n"); - return NULL; - } - memset(new_dlentry, 0, sizeof (struct os2_dl_entry)); - new_dlentry->sector_count = - signature_sector->Partition_Size_To_Report_To_User; - new_dlentry->partition_serial = - signature_sector->partition_serial; - new_dlentry->bbr_is_active = 0; // initialize to not active - new_dlentry->link_partition = evms_partition; - init_MUTEX(&(new_dlentry->bbr_table_lock)); - - sectoroffset = signature_sector->Partition_Start; - LOG_EVERYTHING("Partition Start is at LBA %i\n", sectoroffset); - for (i = 0; i < OS2LVM_MAX_FEATURES_PER_VOLUME; i++) { - feature = signature_sector->LVM_Feature_Array[i].Feature_ID; - if (feature) { - feature_size = - signature_sector->LVM_Feature_Array[i]. - Feature_Data_Size; - LOG_EVERYTHING("Entry %d in Feature Table is valid,\n", - i + 1); - LOG_EVERYTHING("Feature Data size is %i sectors.\n", - feature_size); - if (feature == DRIVE_LINKING_FEATURE_ID) { - if (!new_dlentry->link_data) { - new_dlentry->dl_lsn1 = - signature_sector-> - LVM_Feature_Array[i]. - Location_Of_Primary_Feature_Data - - sectoroffset; - new_dlentry->dl_lsn2 = - signature_sector-> - LVM_Feature_Array[i]. - Location_Of_Secondary_Feature_Data - - sectoroffset; - new_dlentry->link_data = - new_os2_link_data(new_dlentry-> - dl_lsn1, - new_dlentry-> - dl_lsn2, - feature_size, - evms_partition); - if (new_dlentry->link_data == NULL) { - delete_os2_drive_link - (new_dlentry, 0); - new_dlentry = NULL; - } - } else { - LOG_WARNING - ("os2lvm_vge: Drive Linking Feature encountered twice in the same Feature Array!\n"); - delete_os2_drive_link(new_dlentry, 0); - new_dlentry = NULL; - } - } else if (feature == BBR_FEATURE_ID) { - if (!new_dlentry->bbr_data) { - new_dlentry->bbr_lsn1 = - signature_sector-> - LVM_Feature_Array[i]. - Location_Of_Primary_Feature_Data; - new_dlentry->bbr_lsn2 = - signature_sector-> - LVM_Feature_Array[i]. - Location_Of_Secondary_Feature_Data; - new_dlentry->bbr_feature_size = - feature_size; - new_dlentry->bbr_data = - new_os2_bbr_data(new_dlentry-> - bbr_lsn1, - new_dlentry-> - bbr_lsn2, - feature_size, - evms_partition); - if (new_dlentry->bbr_data == NULL) { - delete_os2_drive_link - (new_dlentry, 0); - new_dlentry = NULL; - } else if (signature_sector-> - LVM_Feature_Array[i]. - Feature_Active) { - new_dlentry->bbr_is_active = - check_for_os2_bbr_relocations - (new_dlentry->bbr_data); - } - } else { - LOG_WARNING - ("os2lvm_vge: BBR Feature encountered twice in the same Feature Array!\n"); - delete_os2_drive_link(new_dlentry, 0); - new_dlentry = NULL; - } - } else { - LOG_WARNING - ("os2lvm_vge: Unknown Feature entry %d found.\n", - feature); - delete_os2_drive_link(new_dlentry, 0); - new_dlentry = NULL; - } - - if (signature_sector->LVM_Feature_Array[i]. - Feature_Active) { - LOG_EVERYTHING("Feature is active.\n"); - } - } - } - - if (new_dlentry && - ((!new_dlentry->bbr_data) || (!new_dlentry->link_data)) - ) { - LOG_WARNING("os2lvm_vge: Incomplete Feature Data found.\n"); - delete_os2_drive_link(new_dlentry, 0); - new_dlentry = NULL; - } - return new_dlentry; -} - -/* - * Function: new_os2_link_data - * - * Allocate space for OS/2 drive link information. - * Read in and validate the information from disk. - * Note: assumes 512 byte sectors. - */ -static char * -new_os2_link_data(u32 linksector1, - u32 linksector2, - u32 linknumsectors, struct evms_logical_node *link_partition) -{ - char *new_data1; /* Buffer used to hold the primary copy of the drive linking data. */ - char *new_data2; /* Buffer used to hold the secondary copy of the drive linking data. */ - char *p1; /* Used to access individual sectors of data within new_data1. */ - char *p2; /* Used to access individual sectors of data within new_data2. */ - int memsize = linknumsectors * OS2_BYTES_PER_SECTOR; - u32 i, seq1, seq2; - - /* Allocate Memory for the buffers to hold the drive linking data. */ - LOG_EVERYTHING("Drive Linking Feature entry found.\n"); - new_data1 = kmalloc(memsize, GFP_KERNEL); - if (!new_data1) { - LOG_SERIOUS("Could not allocate Primary Link data\n"); - return NULL; - } - new_data2 = kmalloc(memsize, GFP_KERNEL); - if (!new_data2) { - LOG_SERIOUS("Could not allocate Secondary Link data\n"); - kfree(new_data1); - return NULL; - } - - LOG_EVERYTHING("Primary Feature Data starts at RBA %i\n", linksector1); - LOG_EVERYTHING("Secondary Feature Data starts at RBA %i\n", - linksector2); - - /* Read the drive linking data into memory. */ - if (INIT_IO(link_partition, 0, linksector1, linknumsectors, new_data1)) { - LOG_SERIOUS("I/O error reading Primary Feature Data.\n"); - seq1 = 0; - p1 = NULL; - } else { - /* Set up access to the buffer. Extract the Master Sequence Number from the buffer. */ - p1 = new_data1; - seq1 = ((struct link_table_first_sector *) p1)->Sequence_Number; - } - - if (INIT_IO(link_partition, 0, linksector2, linknumsectors, new_data2)) { - LOG_SERIOUS("I/O error reading Secondary Feature Data.\n"); - seq2 = 0; - p2 = NULL; - } else { - /* Set up access to the second buffer. Extract its copy of the Master Sequence Number. */ - p2 = new_data2; - seq2 = ((struct link_table_sector *) p2)->Sequence_Number; - } - - /* Validate both copies of the drive linking data one sector at a time. */ - for (i = 0; i < linknumsectors; - i++, p1 += OS2_BYTES_PER_SECTOR, p2 += OS2_BYTES_PER_SECTOR) { - if ((seq1 > 0) - && validate_drivelinksector((struct link_table_sector *) p1, i, - seq1)) { - LOG_SERIOUS - ("The primary copy of the drive link data is invalid! Sector %i is not valid\n", - i); - seq1 = 0; - } - - if ((seq2 > 0) - && validate_drivelinksector((struct link_table_sector *) p2, i, - seq2)) { - LOG_SERIOUS - ("The secondary copy of the drive link data is invalid! Sector %i is not valid\n", - i); - seq2 = 0; - } - - } - - LOG_EVERYTHING("Primary Feature Data sequence # %i\n", seq1); - LOG_EVERYTHING("Secondary Feature Data sequence # %i\n", seq2); - - /* Choose which copy of the drive linking data to use. If both sequence numbers are 0, then both copies - of the drive linking data are bad. If both are equal and non-zero, then both copies are good and it - really doesn't matter which one you choose. Otherwise, choose the copy with the highest sequence number. */ - if (seq2 > seq1) { - kfree(new_data1); - return new_data2; - } else { - kfree(new_data2); - if (!seq1) { - kfree(new_data1); - new_data1 = NULL; - } - } - return new_data1; -} - -/* - * Function: new_os2_bbr_data - * - * Allocate space for OS/2 bad block relocation information. - * Read in and validate the information from disk. - * Note: assumes 512 byte sectors. - */ -static char * -new_os2_bbr_data(u32 bbrsector1, - u32 bbrsector2, - u32 bbrnumsectors, struct evms_logical_node *bbr_partition) -{ - char *new_data1; /* Buffer to hold the primary copy of the BBR data. */ - char *new_data2; /* Buffer to hold the secondary copy of the BBR data. */ - char *p1; /* Used to examine the individual sectors of BBR data within new_data1. */ - char *p2; /* Used to examine the individual sectors of BBR data within new_data2. */ - int memsize = bbrnumsectors * OS2_BYTES_PER_SECTOR; - u32 i, seq1, seq2; - - LOG_EVERYTHING("BBR Feature entry found.\n"); - - /* Allocate memory for the buffers. */ - new_data1 = kmalloc(memsize, GFP_KERNEL); - if (!new_data1) { - LOG_SERIOUS("Could not allocate Primary BBR data\n"); - return NULL; - } - new_data2 = kmalloc(memsize, GFP_KERNEL); - if (!new_data2) { - LOG_SERIOUS("Could not allocate Secondary BBR data\n"); - kfree(new_data1); - return NULL; - } - - LOG_EVERYTHING("Primary Feature Data starts at RBA %i\n", bbrsector1); - LOG_EVERYTHING("Secondary Feature Data starts at RBA %i\n", bbrsector2); - - /* Read in both copies of the BBR data. */ - if (INIT_IO(bbr_partition, 0, bbrsector1, bbrnumsectors, new_data1)) { - LOG_SERIOUS("I/O error reading Primary Feature Data.\n"); - seq1 = 0; - p1 = NULL; - } else { - /* Establish access to the first sector of the BBR data. Extract the Master Sequence Number - for this copy of the BBR data. */ - p1 = new_data1; - seq1 = ((LVM_BBR_Table_First_Sector *) p1)->Sequence_Number; - } - - if (INIT_IO(bbr_partition, 0, bbrsector2, bbrnumsectors, new_data2)) { - LOG_SERIOUS("I/O error reading Secondary Feature Data.\n"); - seq2 = 0; - p2 = NULL; - } else { - /* Establish access to the first sector of the second copy of the BBR data. Extract the - Master Sequence Number for this copy of the BBR data. */ - p2 = new_data2; - seq2 = ((LVM_BBR_Table_Sector *) p2)->Sequence_Number; - } - - /* Validate both copies of the BBR Data, one sector at a time. */ - for (i = 0; i < bbrnumsectors; - i++, p1 += OS2_BYTES_PER_SECTOR, p2 += OS2_BYTES_PER_SECTOR) { - if ((seq1 > 0) && validate_bbrtablesector(p1, i, seq1)) { - LOG_SERIOUS - ("The primary BBR data is invalid! Sector %i is not valid\n", - i); - seq1 = 0; - } - - if ((seq2 > 0) && validate_bbrtablesector(p2, i, seq2)) { - LOG_SERIOUS - ("The secondary BBR data is invalid! Sector %i is not valid\n", - i); - seq2 = 0; - } - - } - - LOG_EVERYTHING("Primary Feature Data sequence # %i\n", seq1); - LOG_EVERYTHING("Secondary Feature Data sequence # %i\n", seq2); - - /* Choose which copy of the BBR Data to use based upon the sequence number. If both sequence numbers - are 0, then there is no valid BBR data. If both are non-zero and equal, then it really doesn't - matter which copy is used. Otherwise, choose the copy with the highest sequence number. */ - if (seq2 > seq1) { - kfree(new_data1); - return new_data2; - } else { - kfree(new_data2); - if (!seq1) { - kfree(new_data1); - new_data1 = NULL; - } - } - return new_data1; -} - -/* - * Function: new_os2volume - * - * Allocate space for a new OS/2 logical volume. - * Initialize the appropriate fields. - */ -static struct evms_logical_node * -new_os2volume(u32 volumeserial, char *volume_name) -{ - struct evms_logical_node *new_node; - os2_volume_runtime_entry_t *cur_volume; - - if (evms_cs_allocate_logical_node(&new_node)) { - LOG_SERIOUS("Could not allocate new volume\n"); - return NULL; - } - new_node->private = - kmalloc(sizeof (os2_volume_runtime_entry_t), GFP_KERNEL); - if (!new_node->private) { - LOG_SERIOUS("Could not allocate volume metadata\n"); - evms_cs_deallocate_logical_node(new_node); - return NULL; - } - memset(new_node->private, 0, sizeof (os2_volume_runtime_entry_t)); - new_node->plugin = &plugin_header; - new_node->system_id = LVM_PARTITION_INDICATOR; - sprintf(new_node->name, "os2/%s", volume_name); - cur_volume = (os2_volume_runtime_entry_t *) new_node->private; - cur_volume->Volume_Serial_Number = volumeserial; - cur_volume->Export_Needed = 1; - - if (os2lvm_nodes == NULL) - os2lvm_nodes = new_node; - - // This is the first node discovered. Start the BBR thread. - if (!BBR_Worker_Thread) { - BBR_Worker_Thread = - evms_cs_register_thread(BBR_Worker, NULL, BBR_Worker_Name); - if (!BBR_Worker_Thread) { - kfree(new_node->private); - evms_cs_deallocate_logical_node(new_node); - os2lvm_nodes = NULL; - return NULL; - } - } else { - cur_volume = - (os2_volume_runtime_entry_t *) os2lvm_nodes->private; - while (cur_volume->next_os2lvm_node) - cur_volume = - (os2_volume_runtime_entry_t *) cur_volume-> - next_os2lvm_node->private; - cur_volume->next_os2lvm_node = new_node; - } - - MOD_INC_USE_COUNT; - - return new_node; -} - -/* - * Function: delete_os2lvm_volume - * - * This function deletes the in-memory representation of an OS/2 - * logical volume. - */ -static int -delete_os2lvm_volume(struct evms_logical_node *logical_node) -{ - struct os2_dl_entry *curdrvlink = - ((os2_volume_runtime_entry_t *) logical_node->private)->drive_link, - *nextdrvlink; - os2_volume_runtime_entry_t *cur_volume, *next_volume; - - while (curdrvlink) { - nextdrvlink = curdrvlink->next; - delete_os2_drive_link(curdrvlink, 1); - curdrvlink = nextdrvlink; - } - - cur_volume = (os2_volume_runtime_entry_t *) os2lvm_nodes->private; - if (os2lvm_nodes == logical_node) - os2lvm_nodes = cur_volume->next_os2lvm_node; - else { - while (cur_volume->next_os2lvm_node) { - next_volume = - (os2_volume_runtime_entry_t *) cur_volume-> - next_os2lvm_node->private; - if (cur_volume->next_os2lvm_node == logical_node) { - cur_volume->next_os2lvm_node = - next_volume->next_os2lvm_node; - break; - } - } - } - - if (os2lvm_nodes == NULL) { - // Just deleted the last os2 node. Stop the BBR thread. - if (BBR_Worker_Thread) { - evms_cs_unregister_thread(BBR_Worker_Thread); - BBR_Worker_Thread = NULL; - } - } - - kfree(logical_node->private); - evms_cs_deallocate_logical_node(logical_node); - - MOD_DEC_USE_COUNT; - - return 0; -} - -/* - * Function: delete_os2_drive_link - * - * This function deletes the drive link runtime structure and any - * other structures it points to. - */ -static int -delete_os2_drive_link(struct os2_dl_entry * drive_link, - int delete_link_partition) -{ - if (drive_link->link_data) - kfree(drive_link->link_data); - if (drive_link->bbr_data) - kfree(drive_link->bbr_data); - if (delete_link_partition) - DELETE(drive_link->link_partition); - kfree(drive_link); - - return 0; -} - -// Consistency Checking Functions - -/* - * Function: validate_signaturesector - * - * This function checks the OS/2 LVM Signature Sector - */ -static int -validate_signaturesector(struct evms_logical_node *evms_partition, - LVM_Signature_Sector * signature_sector, - u32 sectorsize) -{ - u32 crc_hold, crc_new; - - /* In order for a signature sector to be considered valid, its signature and CRC must - be correct. Also, OS/2 stores the starting LBA of the partition and the size of - the partition that this signature sector corresponds to. These should be checked - as well. However, since the starting LBA of the partition that this belongs to is - not available to us as part of an struct evms_logical_node, we can only check the size - of the partition against what is stored in the signature sector. */ - - /* The signature used is in two parts. Test the first part. */ - if (signature_sector->LVM_Signature1 != OS2LVM_PRIMARY_SIGNATURE) { - LOG_EVERYTHING("Primary LVM Signature failed.\n"); - return 1; - } - - /* Test the second part of the signature. */ - if (signature_sector->LVM_Signature2 != OS2LVM_SECONDARY_SIGNATURE) { - LOG_EVERYTHING("Secondary LVM Signature failed.\n"); - return 1; - } - - /* Calculate the CRC and compare it against the stored CRC. */ - crc_hold = signature_sector->Signature_Sector_CRC; - signature_sector->Signature_Sector_CRC = 0; - crc_new = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, (void *) signature_sector, - sectorsize); - if (crc_hold != crc_new) { - LOG_EVERYTHING("Signature sector crc failed.\n"); - LOG_EVERYTHING("sector_crc == %x , calc_crc == %x \n", crc_hold, - crc_new); - return 1; - } - // The partition size must == that found in the Signature Sector - if (evms_partition->total_vsectors != - signature_sector->Partition_Sector_Count) { - LOG_EXTRA("Partition size is not valid\n"); - return 1; - } - - return 0; -} - -/* - * Function: validate_drivelinksector - * - * This function checks the OS/2 LVM Drivelink Feature Sector - */ -static int -validate_drivelinksector(void *Sector_To_Validate, - int Sector_Index, u32 Master_Sequence_Number) -{ - u32 crc_hold, crc_new; - struct link_table_first_sector *First_Sector = - (struct link_table_first_sector *) Sector_To_Validate; - struct link_table_sector *Link_Sector = - (struct link_table_sector *) Sector_To_Validate; - - /* The OS/2 drive linking data covers several sectors. The format of the first sector is slightly - different from the following sectors because it contains additional information about how many - drive links are actually in use. The following sectors just contain portions of the drive link - table. Each sector of OS/2 drive linking data contains a signature, crc, and sequence number - which must be validated. */ - - if (Sector_Index == 0) { - - /* Link Table Master Signature Check */ - if (LINK_TABLE_MASTER_SIGNATURE != - First_Sector->Link_Table_Signature) { - LOG_EVERYTHING - ("Link Table Master Signature Test failed.\n"); - return 1; - } - - /* We will NOT check the sequence number here as the first sector of drive link data is the - source of the Master_Sequence_Number which was passed in to us. */ - - /* Set up for the CRC Check */ - crc_hold = First_Sector->Link_Table_CRC; - First_Sector->Link_Table_CRC = 0; - } else { - /* Link Table Internal Signature Check */ - if (LINK_TABLE_SIGNATURE != Link_Sector->Link_Table_Signature) { - LOG_EVERYTHING - ("Link Table Internal Signature Test failed.\n"); - return 1; - } - - /* Check the sequence number. */ - if (Master_Sequence_Number != Link_Sector->Sequence_Number) { - LOG_EVERYTHING - ("Link Table Internal Sequence Number Test failed.\n"); - return 1; - } - - /* Set up for the CRC Check */ - crc_hold = Link_Sector->Link_Table_CRC; - Link_Sector->Link_Table_CRC = 0; - } - - crc_new = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, Sector_To_Validate, - OS2_BYTES_PER_SECTOR); - if (crc_hold != crc_new) { - LOG_EVERYTHING("Link Table crc failed.\n"); - LOG_EVERYTHING("sector_crc == %x , calc_crc == %x \n", crc_hold, - crc_new); - return 1; - } - - return 0; -} - -/* - * Function: validate_bbrtablesector - * - * This function checks the OS/2 LVM Bad Block Relocation Feature Sector - */ -static int -validate_bbrtablesector(void *Sector_To_Validate, - int Sector_Index, u32 Master_Sequence_Number) -{ - u32 crc_hold, crc_new; - LVM_BBR_Table_First_Sector *First_Sector = - (LVM_BBR_Table_First_Sector *) Sector_To_Validate; - LVM_BBR_Table_Sector *BBR_Sector = - (LVM_BBR_Table_Sector *) Sector_To_Validate; - - /* The OS/2 bad block relocation (BBR) data covers several sectors. The format of the first sector - is different from the following sectors because it contains additional information about how many - relocations are actually in use and the size and location of the block of replacement sectors. - The following sectors just contain portions of the BBR remap table. Each sector of OS/2 BBR data - contains a signature, crc, and sequence number which must be validated. */ - - if (Sector_Index == 0) { - - /* BBR Table Master Signature Check */ - if (BBR_TABLE_MASTER_SIGNATURE != First_Sector->Signature) { - LOG_EVERYTHING - ("BBR Table Master Signature Test failed.\n"); - return 1; - } - - /* We will NOT check the sequence number here as the first sector of BBR data is the - source of the Master_Sequence_Number which was passed in to us. */ - - /* Set up for the CRC Check */ - crc_hold = First_Sector->CRC; - First_Sector->CRC = 0; - - } else { - /* BBR Table Internal Signature Check */ - if (BBR_TABLE_SIGNATURE != BBR_Sector->Signature) { - LOG_EVERYTHING - ("BBR Table Internal Signature Test failed.\n"); - return 1; - } - - /* Check the sequence number. */ - if (Master_Sequence_Number != BBR_Sector->Sequence_Number) { - LOG_EVERYTHING - ("BBR Table Internal Sequence Number Test failed.\n"); - return 1; - } - - /* Set up for the CRC Check */ - crc_hold = BBR_Sector->CRC; - BBR_Sector->CRC = 0; - } - - crc_new = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, Sector_To_Validate, - OS2_BYTES_PER_SECTOR); - if (crc_hold != crc_new) { - LOG_EVERYTHING("BBRTable crc failed.\n"); - LOG_EVERYTHING("sector_crc == %x , calc_crc == %x \n", crc_hold, - crc_new); - return 1; - } - - return 0; -} - -/* - * Function: check_for_os2_bbr_relocations - * - * This function checks the OS/2 LVM Bad Block Relocation Tables - * for any active relocation sectors. The bbr table is reformatted in memory - * to make searches faster. - * Return values: 0 == no active relocations, 1 == contains active relocations - */ -static u32 -check_for_os2_bbr_relocations(char *bbr_data_ptr) -{ - LVM_BBR_Feature *feature_data = (LVM_BBR_Feature *) bbr_data_ptr; - - if (feature_data->control.Table_Entries_In_Use) { - LOG_EVERYTHING("There are %d active relocations.\n", - feature_data->control.Table_Entries_In_Use); - return 1; - } - - return 0; -} - -/* - * Function: check_os2_volumes - * - * This function performs a consistency check on all existing OS/2 - * Logical Volumes. The list of constituent partitions ( links ) - * is checked and ordered according to the Link Table. If any link - * is missing or inconsistent, the entire volume will be deleted. - */ -static int -check_os2_volumes(struct evms_logical_node **node_list) -{ - os2_volume_runtime_entry_t *cur_volume; - os2_volume_runtime_entry_t *previous_volume; - struct evms_logical_node *cur_node; - struct evms_logical_node *previous_node = NULL; - struct os2_dl_entry *link_list, *link_hold; - struct link_table_first_sector *psector1; - int i, rc = 0; - u32 numlinks, countlinks, linkser; - u32 Master_Sequence_Number; /* Used to check whether or not all of the copies of Drive Linking data match. */ - u64 partition_offset; - char *sect_ptr; - - LOG_ENTRY_EXIT("Checking OS/2 Logical Volumes\n"); - - cur_node = os2lvm_nodes; - - while (cur_node) { - cur_volume = (os2_volume_runtime_entry_t *) cur_node->private; - link_list = NULL; - if (!cur_volume->complete) { /* need to verify this one */ - cur_volume->complete = 1; - LOG_EVERYTHING("Checking volume %s\n", cur_node->name); - - // Reset fields for sort operation - cur_volume->size_in_sectors = 0; - numlinks = cur_volume->drive_link_count; - cur_volume->drive_link_count = 0; - cur_node->total_vsectors = 0; - link_list = cur_volume->drive_link; - cur_volume->drive_link = NULL; - - // Access the link data to order the drive links - psector1 = - (struct link_table_first_sector *) link_list-> - link_data; - Master_Sequence_Number = psector1->Sequence_Number; - - if (numlinks != psector1->Links_In_Use) { - LOG_SERIOUS - ("Link Count mismatch vol=%i, table=%i\n", - numlinks, psector1->Links_In_Use); - cur_volume->complete = 0; - countlinks = 0; - } else { - if (numlinks > LINKS_IN_FIRST_SECTOR) { - countlinks = LINKS_IN_FIRST_SECTOR; - numlinks -= LINKS_IN_FIRST_SECTOR; - } else { - countlinks = numlinks; - numlinks = 0; - } - - } - - partition_offset = 0; - for (i = 0; - (i < countlinks) && (cur_volume->complete == 1); - i++) { - linkser = - psector1->Link_Table[i]. - partition_serial; - if ((link_hold = - find_link_data(&link_list, linkser))) { - // Add this partition to its parent Volume - add_os2link(link_hold, cur_node); - LOG_EVERYTHING - ("Link start_RBA == "PFU64" , sector_count == "PFU64"\n", - partition_offset, - link_hold->sector_count); - link_hold->start_sector = - partition_offset; - partition_offset += - link_hold->sector_count; - } else { - LOG_SERIOUS - ("Link Table entry %i metadata missing\n", - i); - cur_volume->complete = 0; - break; - } - } - - sect_ptr = (char *) psector1; - - while (numlinks && (cur_volume->complete == 1)) { - if (numlinks > LINKS_IN_NEXT_SECTOR) { - countlinks = LINKS_IN_NEXT_SECTOR; - numlinks -= LINKS_IN_NEXT_SECTOR; - } else { - countlinks = numlinks; - numlinks = 0; - } - sect_ptr += OS2_BYTES_PER_SECTOR; - if (Master_Sequence_Number != - ((struct link_table_sector *) sect_ptr)-> - Sequence_Number) { - cur_volume->complete = 0; - LOG_SERIOUS - ("Bad Sequence Number for Drive Linking Metadata!\n"); - } else { - for (i = 0; i < countlinks; i++) { - linkser = - ((struct link_table_sector *) - sect_ptr)->Link_Table[i]. - partition_serial; - if ((link_hold = - find_link_data(&link_list, - linkser))) { - // Add this partition to its parent Volume - add_os2link(link_hold, - cur_node); - LOG_EVERYTHING - ("Link start_RBA == "PFU64" , sector_count == "PFU64"\n", - partition_offset, - link_hold-> - sector_count); - link_hold-> - start_sector = - partition_offset; - partition_offset += - link_hold-> - sector_count; - } else { - LOG_SERIOUS - ("Link Table entry %i metadata missing\n", - i); - cur_volume->complete = - 0; - break; - } - } - } - } - } - - /* If the volume is complete we can export it for use. */ - if (cur_volume->complete && (link_list == NULL)) { - - // Link new volume into the node list - if (cur_volume->Export_Needed && - (!evms_cs_add_logical_node_to_list - (node_list, cur_node)) - ) { - rc++; - cur_volume->Export_Needed = 0; - } - - previous_node = cur_node; - cur_node = cur_volume->next_os2lvm_node; - } else { - /* Remove the volume from os2lvm_nodes list and delete it. */ - if (previous_node != NULL) { - - previous_volume = - (os2_volume_runtime_entry_t *) - previous_node->private; - previous_volume->next_os2lvm_node = - cur_volume->next_os2lvm_node; - cur_volume->next_os2lvm_node = NULL; - - delete_os2lvm_volume(cur_node); - - cur_node = previous_volume->next_os2lvm_node; - } else { - previous_node = cur_volume->next_os2lvm_node; - delete_os2lvm_volume(cur_node); - cur_node = previous_node; - previous_node = NULL; - os2lvm_nodes = cur_node; - } - - /* If any items remain in link_list, delete those as well. */ - while (link_list) { - link_hold = link_list->next; - delete_os2_drive_link(link_list, 1); - link_list = link_hold; - } - - } - - } - - LOG_ENTRY_EXIT("Finished Checking OS/2 Logical Volumes\n"); - - return rc; -} - -/* BBR_Transfer_IO - * - * Transfer the responsibility for completing the specified IO from - * the thread that requested it to the BBR Worker Thread - */ -static void -BBR_Transfer_IO(struct transfer_record * Transfer_Record) -{ - unsigned long flags; - int Wake_Worker_Thread = 0; /* Assume that the worker is already awake. */ - - spin_lock_irqsave(&BBR_Queue_Lock, flags); - - /* The BBR IO List is a singly linked list. BBR_IO_List_Head points - to the first item in the list, and BBR_IO_List_Tail points to the - last item in the list. */ - Transfer_Record->next = NULL; - if (!BBR_IO_List_Tail) { /* Empty list */ - BBR_IO_List_Head = Transfer_Record; - Wake_Worker_Thread = 1; /* Wake up the worker thread. */ - } else /* Items already in the list. */ - BBR_IO_List_Tail->next = Transfer_Record; - - BBR_IO_List_Tail = Transfer_Record; - - spin_unlock_irqrestore(&BBR_Queue_Lock, flags); - if (Wake_Worker_Thread) - evms_cs_wakeup_thread(BBR_Worker_Thread); - - return; -} - -/* OS2_DL_Callback - * - * This is the callback function used when an I/O request has to be broken - * into two parts because it crosses a drive link boundary. - * - */ -static void -OS2_DL_Callback(struct buffer_head *bh, int uptodate) -{ - - struct tracking_record *Tracking_Record; - struct buffer_head *Original; - - Tracking_Record = bh->b_private; - - /* Is this a read or a write? */ - if (Tracking_Record->link1_transfer_rec || - Tracking_Record->link2_transfer_rec) { - /* We have a write here. Was it successful? */ - if (!uptodate) { - /* Have we tried BBR yet? */ - if ((bh == Tracking_Record->link1_bh) && - (!Tracking_Record->link1_bbr_attempted)) { - /* Attempt BBR. */ - BBR_Transfer_IO(Tracking_Record-> - link1_transfer_rec); - Tracking_Record->link1_bbr_attempted = 1; - return; - } else if ((bh == Tracking_Record->link2_bh) && - (!Tracking_Record->link2_bbr_attempted)) { - /* Attempt BBR. */ - BBR_Transfer_IO(Tracking_Record-> - link2_transfer_rec); - Tracking_Record->link2_bbr_attempted = 1; - return; - } - - } - - } - - Tracking_Record->io_in_progress -= 1; - if (Tracking_Record->io_in_progress) { - Tracking_Record->up_to_date = uptodate; - } - Original = Tracking_Record->org_bh; - - if (!Tracking_Record->io_in_progress) { - uptodate &= Tracking_Record->up_to_date; - /* If this is a write, then Transfer Records will have been set up for both Link1 and Link2. - If the transfer records were used because of BBR, then the BBR worker thread will have - disposed of the transfer records. If the transfer records were not used, then we must - dispose of them here to prevent memory leaks. */ - if (Tracking_Record->link1_transfer_rec && - (!Tracking_Record->link1_bbr_attempted)) { - evms_cs_deallocate_to_pool(BBR_Transfer_Pool, - Tracking_Record-> - link1_transfer_rec); - } - if (Tracking_Record->link2_transfer_rec && - (!Tracking_Record->link2_bbr_attempted)) { - evms_cs_deallocate_to_pool(BBR_Transfer_Pool, - Tracking_Record-> - link2_transfer_rec); - } - evms_cs_deallocate_to_pool(evms_bh_pool, - Tracking_Record->link1_bh); - evms_cs_deallocate_to_pool(evms_bh_pool, - Tracking_Record->link2_bh); - evms_cs_deallocate_to_pool(DL_Tracking_Pool, Tracking_Record); - Original->b_end_io(Original, uptodate); - } - - return; -} - -/* OS2_BBR_Write_Callback - * - * This is the callback for normal write requests. Check for an error - * during the I/O, and send to the worker thread for processing if necessary. - */ -static void -OS2_BBR_Write_Callback(struct transfer_record * Transfer_Record, - struct buffer_head *bh, int uptodate, int *redrive) -{ - if (!uptodate) { - BBR_Transfer_IO(Transfer_Record); - *redrive = TRUE; - } else { - evms_cs_deallocate_to_pool(BBR_Transfer_Pool, Transfer_Record); - } - - return; -} - -/* Worker thread to handle: - - I/O to drive/partitions/objects where bad blocks are known to exist - I/O to drive/partition/object where a new bad block has been discovered and the I/O must be redriven. - -*/ -static void -BBR_Worker(void *Not_Used) -{ - unsigned long flags; - struct transfer_record *Current_IO; - int complete; - - for (;;) { - // Process bbr_io_list, one entry at a time. - spin_lock_irqsave(&BBR_Queue_Lock, flags); - - /* Is there any work for us? */ - if (!BBR_IO_List_Head) { - spin_unlock_irqrestore(&BBR_Queue_Lock, flags); - break; /* List empty - nothing to do. */ - } - - /* Get the IO to perform. */ - Current_IO = BBR_IO_List_Head; - BBR_IO_List_Head = Current_IO->next; - if (!BBR_IO_List_Head) - BBR_IO_List_Tail = BBR_IO_List_Head; - - spin_unlock_irqrestore(&BBR_Queue_Lock, flags); - - /* Now lets process the I/O request. */ - complete = do_os2_bbr_io(Current_IO->Partition_Data, - Current_IO->Write_Flag, - Current_IO->bh->b_rsector, - Current_IO->bh-> - b_size >> EVMS_VSECTOR_SIZE_SHIFT, - Current_IO->bh->b_data); - - /* We need to do the callback. */ - Current_IO->bh->b_end_io(Current_IO->bh, (complete == 0)); - - /* Now cleanup */ - evms_cs_deallocate_to_pool(BBR_Transfer_Pool, Current_IO); - } - - return; /* Go to sleep. */ - -} - -/* - * Sector_Is_Remapped - * - * This function returns 1 if the specified sector has been remapped, 0 if it has not - * - * If the sector has been remapped, then the new sector is returned in Replacement_Sector - * - */ -static int -Sector_Is_Remapped(struct os2_dl_entry * io_dlentry, - u64 Source_Sector, u64 * Replacement_Sector) -{ - LVM_BBR_Feature *Feature_Data = - (LVM_BBR_Feature *) io_dlentry->bbr_data; - unsigned int Sector_Index; /* The BBR Table is spread across several sectors. This tracks which sector we are looking at. */ - unsigned int BBR_Table_Index; /* This tracks the actual entry in the BBR Table that we are examining. */ - unsigned int BBR_Table_Entries_In_Use = - Feature_Data->control.Table_Entries_In_Use; - struct bbr_table_entry * table_entry; - unsigned int guard1; - - /* Default value is no remap. */ - *Replacement_Sector = Source_Sector; - - do { - guard1 = io_dlentry->guard1; /* Lamport's Theorem */ - - for (BBR_Table_Index = 0; - BBR_Table_Index < BBR_Table_Entries_In_Use; - BBR_Table_Index++) { - Sector_Index = - BBR_Table_Index / BBR_TABLE_ENTRIES_PER_SECTOR; - table_entry = - &(Feature_Data->remap[Sector_Index]. - BBR_Table[BBR_Table_Index - - (Sector_Index * - BBR_TABLE_ENTRIES_PER_SECTOR)]); - if (table_entry->BadSector == (u32)Source_Sector) { - *Replacement_Sector = - (u64)table_entry->ReplacementSector; - break; - } - } - - } while (guard1 != io_dlentry->guard2); /* Lamport's Theorem */ - - if (*Replacement_Sector != Source_Sector) - return 1; - else - return 0; -} - -/* - * Invalidate_Mapping - * - * This function either frees a replacement sector to be reused, or it - * marks the replacement sector as bad. - * - */ -static void -Invalidate_Mapping(struct os2_dl_entry * dlentry, - u64 Source_Sector, int Replacement_Sector_Is_Bad) -{ - LVM_BBR_Feature *Feature_Data = (LVM_BBR_Feature *) dlentry->bbr_data; - unsigned int Sector_Index; /* The BBR Table is spread across several sectors. This tracks which sector we are looking at. */ - unsigned int BBR_Table_Index; /* This tracks the actual entry in the BBR Table that we are examining. */ - unsigned int BBR_Table_Entries_In_Use = - Feature_Data->control.Table_Entries_In_Use; - struct bbr_table_entry * table_entry = NULL; - - /* Lock for the BBR Table. */ - down(&(dlentry->bbr_table_lock)); - - /* Find the entry to invalidate. */ - for (BBR_Table_Index = 0; BBR_Table_Index < BBR_Table_Entries_In_Use; - BBR_Table_Index++) { - Sector_Index = BBR_Table_Index / BBR_TABLE_ENTRIES_PER_SECTOR; - table_entry = - &(Feature_Data->remap[Sector_Index]. - BBR_Table[BBR_Table_Index - - (Sector_Index * BBR_TABLE_ENTRIES_PER_SECTOR)]); - if (table_entry->BadSector == Source_Sector) { - break; - } - } - - /* Now that we have found the entry, we must invalidate it. */ - if (Replacement_Sector_Is_Bad) { - table_entry->BadSector = (u32) - 1; - } - /* OS/2 supported a method for clearing out bad block remappings if the filesystem on the volume supported - the tracking of bad blocks. We don't support that under Linux, so there is no else case here. */ - - /* Unlock the BBR Table */ - up(&(dlentry->bbr_table_lock)); - - return; -} - -/* - * Create_New_struct bbr_table_entry - * - * Finds bad blocks within the range specified, allocates replacement sectors, - * writes the data to the replacement sectors, and updates the BBR metadata on - * disk to reflect the new mapping. Returns 1 if successful, 0 otherwise. - * - */ -static int -Create_New_BBR_Table_Entry(struct os2_dl_entry * dlentry, - u64 starting_lsn, unsigned int count, void *buffer) -{ - u64 lsn; - struct bbr_table_entry *Table_Entry; - unsigned int Sector_Index; - unsigned int Table_Index; - int rc; - int rc2; - u32 New_Sequence_Number; - LVM_BBR_Feature *BBR_Data = (LVM_BBR_Feature *) dlentry->bbr_data; - - for (lsn = starting_lsn; lsn < (starting_lsn + count); lsn++) { - rc = INIT_IO(dlentry->link_partition, 1, lsn, 1, buffer); - while (rc) { - - /* Lock for the BBR Table. */ - down(&(dlentry->bbr_table_lock)); - - /* Increment the second guard value. This will cause those reading the BBR Table to spin. */ - dlentry->guard2++; - - /* Ensure that the bbr active flag is set. */ - dlentry->bbr_is_active = 1; - - /* Allocate a replacement sector */ - if (BBR_Data->control.Table_Entries_In_Use < - BBR_Data->control.Table_Size) { - Sector_Index = - BBR_Data->control.Table_Entries_In_Use / - BBR_TABLE_ENTRIES_PER_SECTOR; - Table_Index = - BBR_Data->control.Table_Entries_In_Use % - BBR_TABLE_ENTRIES_PER_SECTOR; - BBR_Data->control.Table_Entries_In_Use = - BBR_Data->control.Table_Entries_In_Use + 1; - Table_Entry = - (struct bbr_table_entry *) & (BBR_Data-> - remap[Sector_Index]. - BBR_Table - [Table_Index]); - Table_Entry->BadSector = lsn; - } else { - /* There are no more replacement sectors available! Time to bail ... */ - up(&(dlentry->bbr_table_lock)); - return 0; - } - - /* Now that we have a replacement sector, increment the first guard value. This will free any - threads reading the BBR Table. */ - dlentry->guard1++; - - /* Release the lock now that we have a replacement sector. */ - up(&(dlentry->bbr_table_lock)); - - /* Test the replacement sector. */ - rc = INIT_IO(dlentry->link_partition, 1, - Table_Entry->ReplacementSector, 1, buffer); - if (rc) { - /* The replacement sector was bad. Lets mark it bad in the table and try again. */ - Table_Entry->BadSector = (u32) - 1; - } - - } /* End of processing for the current sector. */ - - } /* end of loop to test each sector in the I/O and remap any bad ones found. */ - - /* Need to write the modified BBR Table back to disk. This includes updating the sequence numbers and CRCs. */ - - /* Lock for the BBR Table. */ - down(&(dlentry->bbr_table_lock)); - - /* Increment the sequence numbers. */ - New_Sequence_Number = BBR_Data->control.Sequence_Number + 1; - BBR_Data->control.Sequence_Number = New_Sequence_Number; - for (Sector_Index = 0; - Sector_Index < BBR_Data->control.Sectors_Per_Table; - Sector_Index++) { - BBR_Data->remap[Sector_Index].Sequence_Number = - New_Sequence_Number; - } - - /* Calculate the new CRC values. */ - BBR_Data->control.CRC = 0; - BBR_Data->control.CRC = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, &(BBR_Data->control), - OS2_BYTES_PER_SECTOR); - for (Sector_Index = 0; - Sector_Index < BBR_Data->control.Sectors_Per_Table; - Sector_Index++) { - BBR_Data->remap[Sector_Index].CRC = 0; - BBR_Data->remap[Sector_Index].CRC = - evms_cs_calculate_crc(EVMS_INITIAL_CRC, - &(BBR_Data->remap[Sector_Index]), - OS2_BYTES_PER_SECTOR); - } - - /* Now we must write the table back to the partition from whence it came. */ - - /* Write the first copy. */ - rc = INIT_IO(dlentry->link_partition, 1, dlentry->bbr_lsn1, - dlentry->bbr_feature_size, BBR_Data); - - /* Write the second copy. */ - rc2 = - INIT_IO(dlentry->link_partition, 1, dlentry->bbr_lsn2, - dlentry->bbr_feature_size, BBR_Data); - - /* If both copies failed to reach the disk, then fail the I/O. */ - if (rc && rc2) { - rc = 0; - } else - rc = 1; - - /* Unlock the BBR Table */ - up(&(dlentry->bbr_table_lock)); - - /* Indicate success. */ - return rc; -} - -/* - * Clone_Bufferhead - * - * Prepares a usable copy of an existing bufferhead. - * - */ -static void -Clone_Bufferhead(struct buffer_head *Source, struct buffer_head *Child) -{ - Child->b_next = NULL; - Child->b_blocknr = Source->b_blocknr; - Child->b_size = Source->b_size; - Child->b_list = BUF_LOCKED; - Child->b_dev = Source->b_dev; - atomic_set(&Child->b_count, 0); - atomic_set(&Child->b_count, atomic_read(&Source->b_count)); - Child->b_rdev = Source->b_rdev; - Child->b_state = Source->b_state; - Child->b_flushtime = 0; - Child->b_next_free = NULL; - Child->b_prev_free = NULL; - Child->b_this_page = (struct buffer_head *) 1; - Child->b_reqnext = NULL; - Child->b_pprev = NULL; - Child->b_data = Source->b_data; - Child->b_page = Source->b_page; - Child->b_end_io = Source->b_end_io; - Child->b_private = Source->b_private; - Child->b_rsector = Source->b_rsector; - clear_buffer_attached(Child); - return; -} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/s390_part.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/s390_part.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/s390_part.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/s390_part.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1447 +0,0 @@ -/* -*- linux-c -*- */ -/* - * - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - */ -/* - * linux/drivers/evms/s390_part.c - * - * EVMS S/390 partition manager - * - * Partial code extracted from - * - * linux/fs/partitions/ibm.c - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* prefix used in logging messages */ -#define LOG_PREFIX "s390_part: " - -/* Private instance data structure for node we produced */ -struct local_instance_data { - struct evms_logical_node *source_disk; - u64 start_sect; /* starting LBA */ - u64 nr_sects; /* number of sectors */ - unsigned char type; /* partition type or filesystem format indicator, can be set to 0 */ -}; - -static int exported_nodes; /* total # of exported segments - * produced during this discovery. - */ - -/* Prototypes */ -static int s390_partition_discover(struct evms_logical_node **); -static int s390_partition_delete(struct evms_logical_node *); -static void s390_partition_read(struct evms_logical_node *, - struct buffer_head *); -static void s390_partition_write(struct evms_logical_node *, - struct buffer_head *); -static int s390_partition_ioctl(struct evms_logical_node *, - struct inode *, - struct file *, unsigned int, unsigned long); -static int s390_partition_init_io(struct evms_logical_node *, - int, u64, u64, void *); - -static struct evms_plugin_fops fops = { - .discover = s390_partition_discover, - .delete = s390_partition_delete, - .read = s390_partition_read, - .write = s390_partition_write, - .init_io = s390_partition_init_io, - .ioctl = s390_partition_ioctl -}; - -#define EVMS_S390_PARTITION_MANAGER_ID 2 - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_SEGMENT_MANAGER, - EVMS_S390_PARTITION_MANAGER_ID), - .version = { - .major = 1, - .minor = 1, - .patchlevel = 2}, - .required_services_version = { - .major = 0, - .minor = 5, - .patchlevel = 0}, - .fops = &fops -}; - -/***************************************************/ -/* List Support - Typedefs, Variables, & Functions */ -/***************************************************/ - -/* Typedefs */ - -/* structure to keep status on - * each disk. - */ -#define S390_DISK_OK 0 -#define S390_DISK_FAILED 1 -#define S390_FAILED_SKIP_COUNT 1024 -struct disk_object { - int flags; - atomic_t skipped_ios; - atomic_t pending_ios; - atomic_t total_ios; - atomic_t failed_ios; - struct evms_logical_node *disk; -}; - -/* structure to keep status - * on each device. - */ -struct device_object { - unsigned char label[8]; - int total_paths; - struct evms_list_node *disk_object_list; - struct evms_list_node *segment_list; -}; - -/* structure used to track in-flight IOs, - * and to handle failover scenarios. - */ -struct s390_io { - struct device_object *devo; - struct disk_object *dsko; - struct evms_logical_node *segment; - int rw_flag; - int paths_tried; - struct buffer_head *bh; - struct s390_io *next; -}; -static spinlock_t s390_redrive_list_lock = SPIN_LOCK_UNLOCKED; -static struct s390_io *s390_redrive_list = NULL; -static struct evms_thread *s390_io_redrive_thread; -static struct evms_pool_mgmt *s390_io_track_pool = NULL; - -/* Variables */ - -static struct evms_list_node *my_device_object_list; - -static struct evms_list_node ** -lookup_device_object(struct evms_logical_node *disk) -{ - struct evms_list_node **devoln; - - devoln = &my_device_object_list; - while (*devoln) { - struct evms_list_node **dskoln; - struct device_object *devo; - devo = (struct device_object *) (*devoln)->item; - dskoln = &devo->disk_object_list; - while (*dskoln) { - struct disk_object *dsko; - dsko = (struct disk_object *) (*dskoln)->item; - if (dsko->disk == disk) { - return (devoln); - } - dskoln = &(*dskoln)->next; - } - devoln = &(*devoln)->next; - } - return (devoln); -} - -static struct evms_list_node ** -lookup_label(unsigned char *label, struct evms_list_node **devoln) -{ - if (!devoln) { - devoln = &my_device_object_list; - } else { - devoln = &(*devoln)->next; - } - while (*devoln) { - struct device_object *devo; - struct disk_object *dsko; - devo = (struct device_object *) (*devoln)->item; - dsko = (struct disk_object *) devo->disk_object_list->item; - LOG_DEBUG("comparing labels: new(%s), %s(%s)\n", - label, dsko->disk->name, devo->label); - if (!strncmp(devo->label, label, 6)) { - LOG_DEBUG("matching label found!\n"); - break; - } - devoln = &(*devoln)->next; - } - return (devoln); -} - -static struct evms_logical_node * -find_segment_on_disk(struct evms_logical_node *disk, - u64 start_sect, u64 nr_sects) -{ - struct evms_logical_node *rc = NULL; - struct evms_list_node **devoln; - - /* find disk object */ - devoln = lookup_device_object(disk); - if (*devoln) { - /* disk object found in list */ - /* attempt to find segment */ - struct evms_list_node **sln; - struct device_object *devo; - - devo = (struct device_object *) (*devoln)->item; - sln = &devo->segment_list; - while (*sln) { - struct evms_logical_node *segment; - struct local_instance_data *lid; - - segment = (struct evms_logical_node *) (*sln)->item; - lid = segment->private; - if (lid->start_sect == start_sect) { - if (lid->nr_sects == nr_sects) { - rc = segment; - break; - } - } - sln = &(*sln)->next; - } - } - return (rc); -} - -static int -add_segment_to_disk(struct evms_logical_node *disk, - unsigned char *label, struct evms_logical_node *segment) -{ - int rc = 0; - struct evms_list_node **devoln; - struct device_object *devo; - - devoln = lookup_device_object(disk); - if (*devoln == NULL) { - struct disk_object *dsko = NULL; - /* device object not in list, add device object */ - devo = kmalloc(sizeof (*devo), GFP_KERNEL); - if (devo) { - memset(devo, 0, sizeof (*devo)); - strncpy(devo->label, label, 6); - rc = evms_cs_add_item_to_list(devoln, devo); - } else { - rc = -ENOMEM; - } - - /* create a disk object */ - if (!rc) { - dsko = kmalloc(sizeof (*dsko), GFP_KERNEL); - if (!dsko) { - rc = -ENOMEM; - } - } - if (!rc) { - memset(dsko, 0, sizeof (*dsko)); - /* add disk to disk object */ - dsko->disk = disk; - /* add disk object to disk object list - * in device object */ - rc = evms_cs_add_item_to_list(&devo->disk_object_list, - dsko); - } - if (!rc) { - devo->total_paths++; - } else { - /* on error clean up allocations */ - if (dsko) { - kfree(dsko); - } - if (*devoln) { - evms_cs_remove_item_from_list(devoln, devo); - } - if (devo) - kfree(devo); - } - } else { - devo = (struct device_object *) (*devoln)->item; - } - if (!rc) { - /* attempt to add segment */ - rc = evms_cs_add_item_to_list(&devo->segment_list, segment); - } - return (rc); -} - -static int -remove_segment_from_disk(struct evms_logical_node *disk, - struct evms_logical_node *segment, - struct evms_list_node **empty_disk_object_list) -{ - int rc = -1; - struct evms_list_node **devoln; - - *empty_disk_object_list = NULL; - devoln = lookup_device_object(disk); - if (*devoln) { - /* device object found in list */ - /* attempt to remove segment */ - struct device_object *devo; - devo = (struct device_object *) (*devoln)->item; - rc = evms_cs_remove_item_from_list(&devo->segment_list, - segment); - if (!rc) { - if (devo->segment_list == NULL) { - /* return disk object list to caller */ - *empty_disk_object_list = - devo->disk_object_list; - /* remove device object from list */ - rc = evms_cs_remove_item_from_list(devoln, - devo); - /* free device object */ - kfree(devo); - } - } - } - return (rc); -} - -/* function: s390_load_balance - * - * this function is used to route an IO to the appropriate - * paths of a multipath device. - * - * appropriate paths are determine used load balancing - * techniques. load balancing is accomplished by monitoring - * pending or in-flight IOs to each path. when a new IO - * request is received, all paths are examined, and the path - * with the fewest IOs pending is selected to receive the - * new request. - * - * this routine also utilizes some failed path recovery - * logic. - * - * if a failed path has been skipped for a given number - * (timeout value) of IO requests. it is then tried again, - * and if the path has become functional again, it returned - * to the active state and it becomes available for load - * balancing. - * - * if a new IO arrives and we find no currently active paths, - * each failed path will be attempted one time in the hopes - * that it may have become active from the time between when - * it was marked failed and now. only when all paths have - * been tried and found non-active, is the IO marked with - * an error and returned. - * - * this function works in concert with s390_end_io_callback - * function and the s390iod(aemon), to redrive failed IO - * requests. - * - */ -static void -s390_load_balance(struct s390_io **piot, struct evms_logical_node *disk) -{ - struct evms_list_node **dskoln; - struct disk_object *dsko, *selected_dsko = NULL; - int dskidx, path = 0; - struct s390_io *iot; - - /* allocate and initialize an IO tracking structure - * if one was not passed in. - */ - if (!*piot) { - struct evms_list_node **devoln; - /* allocate IO Track struct */ - *piot = evms_cs_allocate_from_pool(s390_io_track_pool, - EVMS_BLOCKABLE); - memset(*piot, 0, sizeof (*iot)); - /* find the device object */ - devoln = lookup_device_object(disk); - (*piot)->devo = (*devoln)->item; - } - iot = *piot; - - /* find next disk object based on current load */ - - /* check for failed paths that have timed-out */ - dskidx = 1; - dskoln = &iot->devo->disk_object_list; - while (*dskoln) { - dsko = (struct disk_object *) (*dskoln)->item; - do { - /* skip paths tried earlier */ - if (iot->paths_tried & dskidx) { - continue; - } - /* skip active disks */ - if (dsko->flags == S390_DISK_OK) { - continue; - } - /* skip disks that haven't timed-out yet */ - if (atomic_read(&dsko->skipped_ios) - < S390_FAILED_SKIP_COUNT) { - continue; - } - selected_dsko = dsko; - path = dskidx; - break; - } while (0); - dskoln = &(*dskoln)->next; - dskidx <<= 1; - } - - /* if we have no timed-out paths, then check for the - * path with lowest pending io count. if that path - * happens to be a failed path and there is active - * paths, increment the skipped io count, mark this - * path as having been selected, then go back and run - * the loop again, looking for the next best choice. - * continue this process until the best active has - * been selected, or we end up with the best failed - * path. - */ - if (!selected_dsko) { - int paths_selected, have_actives; - paths_selected = 0; - s390_repeat_active_search: - path = 0; - have_actives = FALSE; - dskidx = 1; - dskoln = &iot->devo->disk_object_list; - while (*dskoln) { - dsko = (struct disk_object *) (*dskoln)->item; - do { - /* skip paths tried earlier */ - if (iot->paths_tried & dskidx) { - continue; - } - /* skip previously selected disks */ - if (paths_selected & dskidx) { - continue; - } - /* remember if we have active disks */ - if (dsko->flags == S390_DISK_OK) { - have_actives = TRUE; - } - /* look for disk with smallest - * pending IO count. - */ - if (selected_dsko) { - if (atomic_read(&dsko->pending_ios) - >= - (atomic_read - (&selected_dsko->pending_ios))) { - continue; - } - } - selected_dsko = dsko; - path = dskidx; - } while (0); - dskoln = &(*dskoln)->next; - dskidx <<= 1; - } - /* if we have unselected active paths - * and the currently selected path is - * failed, increment its skipped io count, - * and then go back to find an active path. - * - * this loop is structured this way so that - * we can accurately determine and track when - * a path has been skipped. - */ - if (have_actives && selected_dsko) { - if (selected_dsko->flags & S390_DISK_FAILED) { - atomic_inc(&selected_dsko->skipped_ios); - paths_selected |= path; - selected_dsko = NULL; - goto s390_repeat_active_search; - } - } - } - - /* if we have a selected path, perform the necessary - * bookkeeping on it. - */ - if (selected_dsko) { - atomic_set(&selected_dsko->skipped_ios, 0); - atomic_inc(&selected_dsko->pending_ios); - atomic_inc(&selected_dsko->total_ios); - iot->paths_tried |= path; - } - /* store the selected path (disk object) in the - * IO tracking structure, for examination by the - * caller. - */ - iot->dsko = selected_dsko; -} - -static void -s390_end_io_callback(void *private, - struct buffer_head *bh, int uptodate, int *done) -{ - struct s390_io *iot; - ulong flags; - - iot = private; - - /* update the disk object's status */ -// spin_lock_irqsave(iot->devo->device_object_lock, flags); - atomic_dec(&iot->dsko->pending_ios); - iot->dsko->flags = !uptodate; -// spin_unlock_irqrestore(iot->devo->device_object_lock, flags); - - if (!uptodate) { - atomic_inc(&iot->dsko->failed_ios); - /* encountered error */ - - /* is this a multipath device? */ - if (iot->devo->total_paths > 1) { - /* yes, its a multipath device */ - - /* determine alternate path */ - s390_load_balance(&iot, NULL); - if (iot->dsko) { - /* queue up redrive request */ - spin_lock_irqsave(&s390_redrive_list_lock, - flags); - iot->next = s390_redrive_list; - s390_redrive_list = iot; - spin_unlock_irqrestore(&s390_redrive_list_lock, - flags); - /* wake up redrive daemon */ - evms_cs_wakeup_thread(s390_io_redrive_thread); - - /* prevent the end_io to caller of EVMS */ - *done = TRUE; - } - } - } - if (*done == FALSE) { - evms_cs_deallocate_to_pool(s390_io_track_pool, iot); - } -} - -/**************************************************** -* Function: s390iod -* -* This is a kernel thread that handles read/write of mirrorss -* This shouldn't ever run on a non-mirrored LV read/write -* -* -*****************************************************/ -static void -s390iod(void *data) -{ - struct s390_io *iot; - unsigned long flags; - int rc; - - while (1) { - spin_lock_irqsave(&s390_redrive_list_lock, flags); - if (s390_redrive_list == NULL) { - spin_unlock_irqrestore(&s390_redrive_list_lock, flags); - break; - } - iot = s390_redrive_list; - s390_redrive_list = iot->next; - iot->next = NULL; - spin_unlock_irqrestore(&s390_redrive_list_lock, flags); - - /* register for callback */ - rc = evms_cs_register_for_end_io_notification(iot, iot->bh, - s390_end_io_callback); - if (rc) { - LOG_ERROR - ("error(%d): unable to register for end io callback!\n", - rc); - } else { - /* redrive IO */ - if (!iot->rw_flag) { - R_IO(iot->dsko->disk, iot->bh); - } else { - W_IO(iot->dsko->disk, iot->bh); - } - } - } -} - -/* - * Function: add_segment - */ -static int -s390_process_segment(struct evms_logical_node **discover_list, - struct evms_logical_node *node, - unsigned char *label, - u64 start_sect, - u64 nr_sects, unsigned char type, int part_num) -{ - struct local_instance_data *InstData = NULL; - struct evms_logical_node *segment; - int rc = 0; - - segment = find_segment_on_disk(node, start_sect, nr_sects); - if (segment) { - LOG_DETAILS("exporting segment '%s'.\n", segment->name); - } else { - InstData = kmalloc(sizeof (*InstData), GFP_KERNEL); - if (InstData) { - memset(InstData, 0, sizeof (*InstData)); - InstData->source_disk = node; - InstData->start_sect = start_sect; - InstData->nr_sects = nr_sects; - InstData->type = type; - rc = evms_cs_allocate_logical_node(&segment); - } else { - rc = -ENOMEM; - } - - if (!rc) { - segment->plugin = &plugin_header; - segment->system_id = (unsigned int) type; - segment->total_vsectors = nr_sects; - segment->block_size = node->block_size; - segment->hardsector_size = node->hardsector_size; - segment->private = InstData; - segment->flags = node->flags; - strcpy(segment->name, node->name); - sprintf(segment->name + strlen(segment->name), "%d", - part_num); - LOG_DETAILS("creating segment '%s'.\n", segment->name); - rc = add_segment_to_disk(node, label, segment); - if (rc) { - LOG_ERROR - ("%s: error(%d) adding segment '%s'!\n", - __FUNCTION__, rc, segment->name); - rc = 0; - } else { - MOD_INC_USE_COUNT; - } - } - if (rc) { - if (InstData) - kfree(InstData); - if (segment) - evms_cs_deallocate_logical_node(segment); - } - } - if (!rc) { - evms_cs_add_logical_node_to_list(discover_list, segment); - exported_nodes++; - } - return rc; -} - -typedef enum { - ibm_partition_lnx1 = 0, - ibm_partition_vol1 = 1, - ibm_partition_cms1 = 2, - ibm_partition_none = 3 -} ibm_partition_t; - -static char *part_names[] = { - [ibm_partition_lnx1] = "LNX1", - [ibm_partition_vol1] = "VOL1", - [ibm_partition_cms1] = "CMS1", - [ibm_partition_none] = "(nonl)" -}; - -static ibm_partition_t -get_partition_type(char *type) -{ - int i; - for (i = 0; i < 3; i++) { - if (!strncmp(type, part_names[i], 4)) - break; - } - return i; -} - -/* - * compute the block number from a - * cyl-cyl-head-head structure - */ -static inline int -cchh2blk(cchh_t * ptr, struct hd_geometry *geo) -{ - return ptr->cc * geo->heads * geo->sectors + ptr->hh * geo->sectors; -} - -/* - * compute the block number from a - * cyl-cyl-head-head-block structure - */ -static inline int -cchhb2blk(cchhb_t * ptr, struct hd_geometry *geo) -{ - int block = 0; - - block = ptr->cc * geo->heads * geo->sectors + ptr->hh * geo->sectors; - if (ptr->b) { - block += ptr->b - 1; - } - - return block; -} - -static void -print_mem(void *buffer, int length) -{ - int i, done; - unsigned char *bufptr; - - bufptr = (unsigned char *) buffer; - i = done = 0; - while (!done) { - if ((i % 16) == 0) - printk(KERN_INFO "\n0x%p->", buffer + i); - printk(KERN_INFO "%02x ", bufptr[i]); - if (++i >= length) - done++; - } - printk(KERN_INFO "\n"); -} - -static int -s390_probe_multipath(struct evms_logical_node *disk, - unsigned char *label, - u64 label_lba, int label_offset, unsigned char *org_buf) -{ - int rc = FALSE; - struct evms_list_node **devoln; - unsigned char *sector_buf = NULL; - - LOG_ENTRY_EXIT("%s: Entry\n", __FUNCTION__); - /* check if this disk is already known. - * if it is already in our device list - * then we don't need to check for - * multipath associations. - */ - devoln = lookup_device_object(disk); - /* is this disk in our list? */ - if (*devoln) { - struct device_object *devo; - struct disk_object *dsko; - /* yes, disk already known */ - - /* we need to determine if this - * is our first path to this - * device. - */ - devo = (struct device_object *) (*devoln)->item; - /* if this is the first path to this - * device, return FALSE so the main - * routine will process its segments. - * if this is not the first path, - * return TRUE so the main routine - * will not process its segments. - */ - dsko = (struct disk_object *) devo->disk_object_list->item; - if (dsko->disk != disk) { - rc = TRUE; - } - /* only print multipath log msgs if its - * active on this device. - */ - if (devo->total_paths > 1) { - LOG_DEBUG - ("skipping probe of known multipath device '%s'.\n", - disk->name); - } - LOG_ENTRY_EXIT("%s: Exit RC(%d)\n", __FUNCTION__, rc); - return (rc); - } - - /* search device object list for a matching label */ - devoln = NULL; - while (*(devoln = lookup_label(label, devoln))) { - struct device_object *devo; - struct disk_object *dsko; - unsigned char org_label[6]; -#define S390_TEST_LABEL "~!@#$" - - /* yes, found matching label */ - if (!sector_buf) { - /* allocate buffer for incoming label sector */ - sector_buf = kmalloc(disk->hardsector_size, GFP_KERNEL); - if (!sector_buf) { - rc = -ENOMEM; - break; - } - } - - /* save original label */ - memcpy(org_label, org_buf + label_offset, 6); - /* alter label to test pattern */ - strcpy(org_buf + label_offset, S390_TEST_LABEL); - /* write test pattern to this disk */ - LOG_DEBUG("writing test label to '%s'.\n", disk->name); - rc = INIT_IO(disk, WRITE, label_lba, 1, org_buf); - if (rc) { - LOG_ERROR("error(%d) reading sector("PFU64") from '%s'.\n", - rc, label_lba, disk->name); - break; - } - - /* read label from device object with matching label */ - devo = (struct device_object *) (*devoln)->item; - dsko = (struct disk_object *) devo->disk_object_list->item; - LOG_DEBUG("reading label from '%s'.\n", dsko->disk->name); - rc = INIT_IO(dsko->disk, READ, label_lba, 1, sector_buf); - if (rc) { - LOG_ERROR("error(%d) writing sector("PFU64") to '%s'.\n", - rc, label_lba, dsko->disk->name); - } - - /* restore original label */ - memcpy(org_buf + label_offset, org_label, 6); - LOG_DEBUG("restoring original label to '%s'.\n", disk->name); - rc = INIT_IO(disk, WRITE, label_lba, 1, org_buf); - if (rc) { - LOG_ERROR("error(%d) reading sector("PFU64") from '%s'.\n", - rc, label_lba, disk->name); - break; - } - - LOG_DEBUG("checking label: %s(%6s), reference(%6s).\n", - dsko->disk->name, - sector_buf + label_offset, S390_TEST_LABEL); - if (!strcmp(sector_buf + label_offset, S390_TEST_LABEL)) { - LOG_DETAILS("assigning '%s' as first path to device.\n", - dsko->disk->name); - LOG_DETAILS("assigning '%s' as next path to device.\n", - disk->name); - /* store this disk in the disk object's - * disk list. - */ - /* create a disk object */ - dsko = NULL; - if (!rc) { - dsko = kmalloc(sizeof (*dsko), GFP_KERNEL); - if (!dsko) { - rc = -ENOMEM; - } - } - if (!rc) { - memset(dsko, 0, sizeof (*dsko)); - /* add disk to disk object */ - dsko->disk = disk; - /* add disk object to disk object list - * in device object */ - rc = evms_cs_add_item_to_list(&devo-> - disk_object_list, - dsko); - } - if (!rc) { - devo->total_paths++; - } else { - if (dsko) { - kfree(dsko); - } - break; - } - - /* indicate we found a multipath device */ - rc = TRUE; - break; - } - } - if (sector_buf) { - kfree(sector_buf); - } - - LOG_ENTRY_EXIT("%s: Exit RC(%d)\n", __FUNCTION__, rc); - return (rc); -} - -static int -s390_probe_for_segments(struct evms_logical_node **discover_list, - struct evms_logical_node *disk) -{ - char type[5] = { 0, }, name[7] = { - 0,}; - int rc, vsects_per_hardsect = 0; - unsigned int blk; - u64 io_start, label_lba = 3; - dasd_information_t *info = NULL; - struct hd_geometry *geo = NULL; - unchar *data = NULL; - - /* allocate space for DASD ioctl packet - */ - info = kmalloc(sizeof (dasd_information_t), GFP_KERNEL); - if (info) { - memset(info, 0, sizeof (dasd_information_t)); - LOG_DEBUG("probing '%s' for 390 DASD info...\n", disk->name); - /* issue DASD info ioctl - */ - rc = evms_cs_kernel_ioctl(disk, BIODASDINFO, - (unsigned long) info); - if (rc) { - LOG_DEBUG("error(%d) from BIODASDINFO ioctl.\n", rc); - LOG_DEBUG("assuming '%s' is not a valid 390 device!\n", - disk->name); - } - } else { - rc = -ENOMEM; - } - - if (!rc) { - /* if we successfully completed the previous - * get DASD info ioctl, we will assume that - * the device is a valid 390 disk. - * - * remove it from the discover list. - */ - rc = evms_cs_remove_logical_node_from_list(discover_list, disk); - if (rc) { - LOG_ERROR - ("error(%d) removing disk(%s) from discover list.\n", - rc, disk->name); - } - } - if (!rc) { - /* allocate space for the geometry packet - */ - geo = kmalloc(sizeof (struct hd_geometry), GFP_KERNEL); - if (!geo) { - rc = -ENOMEM; - } - } - if (!rc) { - memset(geo, 0, sizeof (struct hd_geometry)); - /* issue the Get GEO ioctl - */ - rc = evms_cs_kernel_ioctl(disk, HDIO_GETGEO, - (unsigned long) geo); - if (rc) { - LOG_ERROR("error(%d) from HDIO_GETGEO ioctl.\n", rc); - } - } - if (!rc) { - /* retrieve the vsects_per_hardsect (hardsector size) - */ - vsects_per_hardsect = disk->hardsector_size; - vsects_per_hardsect >>= EVMS_VSECTOR_SIZE_SHIFT; - data = kmalloc(EVMS_VSECTOR_SIZE, GFP_KERNEL); - if (!data) { - rc = -ENOMEM; - } - } - if (!rc) { - /* go read the 1st block on the disk - */ - label_lba = info->label_block * vsects_per_hardsect; - io_start = label_lba; - rc = INIT_IO(disk, READ, io_start, 1, data); - if (rc) { - LOG_ERROR("error(%d) reading sector("PFU64") from '%s'.\n", - rc, io_start, disk->name); - } else { -// print_mem(data, EVMS_VSECTOR_SIZE); - } - } - if (!rc) { - int offset, size, psize, counter = 0, label_offset; - int vstart = 0, vend = 0; - int vtoc_record_count, vtoc_index; - format1_label_t f1; - format4_label_t *f4; - volume_label_t vlabel; - ibm_partition_t partition_type; - - /* determine the format type - */ - - strncpy(type, data, 4); - if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { - label_offset = 8; - } else { - label_offset = 4; - } - strncpy(name, data + label_offset, 6); - memcpy(&vlabel, data, sizeof (volume_label_t)); - - EBCASC(type, 4); - EBCASC(name, 6); - partition_type = get_partition_type(type); - LOG_DETAILS("disk: raw type(%s), type(%s), name(%s)\n", - type, part_names[partition_type], name); - - rc = s390_probe_multipath(disk, name, label_lba, label_offset, - data); - if (!rc) { - switch (partition_type) { - case ibm_partition_cms1: - if (*((long *) data + 13) != 0) { - /* disk is reserved minidisk */ - long *label = (long *) data; - vsects_per_hardsect = - label[3] >> EVMS_VSECTOR_SIZE_SHIFT; - offset = label[13]; - size = - (label[7] - - 1) * vsects_per_hardsect; - LOG_DEBUG("(MDSK)"); - } else { - offset = info->label_block + 1; - size = disk->total_vsectors; - } - offset *= vsects_per_hardsect; - /* adjust for 0 thru label block offset - */ - size -= offset; - rc = s390_process_segment(discover_list, - disk, - name, - offset, size, 0, 1); - break; - case ibm_partition_lnx1: - case ibm_partition_none: - offset = info->label_block + 1; - offset *= vsects_per_hardsect; - size = disk->total_vsectors; - /* adjust for 0 thru label block offset - */ - size -= offset; - rc = s390_process_segment(discover_list, - disk, - name, - offset, size, 0, 1); - break; - case ibm_partition_vol1: - /* set max dscb record count == single track till we see the vtoc descriptor */ - vtoc_record_count = geo->sectors; - /* set current index into vtoc */ - vtoc_index = 0; - /* get block number and read then first dscb */ - blk = cchhb2blk(&vlabel.vtoc, geo); - io_start = blk * vsects_per_hardsect; - rc = INIT_IO(disk, READ, io_start, 1, data); - if (rc) { - LOG_ERROR - ("error(%d) reading sector("PFU64") from '%s'.\n", - rc, io_start, disk->name); - break; - } else { - // print_mem(data, EVMS_VSECTOR_SIZE); - } - memcpy(&f1, data, sizeof (format1_label_t)); - - // read vtoc records ... terminate when : - // (1) we hit first NULL record - // (2) we get an error processing a vtoc record - // (3) we run out of vtoc records to process - while (f1.DS1FMTID != 0x00 && rc == 0 - && vtoc_index < vtoc_record_count) { - if (f1.DS1FMTID == 0xf4) { // vtoc descriptor - f4 = (format4_label_t *) data; - vstart = - cchh2blk(&f4->DS4VTOCE. - llimit, geo); - vend = - cchh2blk(&f4->DS4VTOCE. - ulimit, geo); - vtoc_record_count = - (vend - vstart) + - geo->sectors; - } else if (f1.DS1FMTID == 0xf1) { // dataset descriptor - - offset = - cchh2blk(&f1.DS1EXT1.llimit, - geo); - psize = - cchh2blk(&f1.DS1EXT1.ulimit, - geo) - offset + - geo->sectors; - - counter++; - rc = s390_process_segment - (discover_list, disk, name, - offset * - vsects_per_hardsect, - psize * - vsects_per_hardsect, 0, - counter); - } - if (!rc) { // get next dscb - ++vtoc_index; - ++blk; - io_start = - blk * vsects_per_hardsect; - rc = INIT_IO(disk, READ, - io_start, 1, data); - if (rc) { - LOG_ERROR - ("error(%d) reading sector("PFU64") from '%s'.\n", - rc, io_start, - disk->name); - break; - } else { - // print_mem(data, EVMS_VSECTOR_SIZE); - } - memcpy(&f1, data, - sizeof - (format1_label_t)); - } - } - break; - default: - rc = s390_process_segment(discover_list, - disk, name, - 0, 0, 0, 1); - break; - } - } - } - if (info) { - kfree(info); - } - if (geo) { - kfree(geo); - } - if (data) - kfree(data); - - return (rc); -} - -/* - * Function: s390_partition_discover - * - */ -static int -s390_partition_discover(struct evms_logical_node **discover_list) -{ - int rc = 0; - struct evms_logical_node *node, *next_node; - - MOD_INC_USE_COUNT; - LOG_ENTRY_EXIT("%s: ENTRY\n", __FUNCTION__); - - /* initialize global variable */ - exported_nodes = 0; - - /* examine each node on the discover list */ - next_node = *discover_list; - while (next_node) { - node = next_node; - next_node = node->next; - if (GetPluginType(node->plugin->id) != EVMS_DEVICE_MANAGER) - /* only process disk nodes - */ - continue; - if (node->iflags & EVMS_TOP_SEGMENT) - continue; - s390_probe_for_segments(discover_list, node); - } - - LOG_ENTRY_EXIT("%s: EXIT(exported nodes:%d, error code:%d)\n", - __FUNCTION__, exported_nodes, rc); - if (exported_nodes) - rc = exported_nodes; - MOD_DEC_USE_COUNT; - return (rc); -} - -/* - * Function: s390_partition_delete - * - */ -static int -s390_partition_delete(struct evms_logical_node *segment) -{ - int rc = 0; - struct local_instance_data *LID; - - LOG_DETAILS("deleting segment '%s'.\n", segment->name); - - if (!segment) { - rc = -ENODEV; - } else { - struct evms_list_node *empty_disk_object_list = NULL; - LID = segment->private; - if (LID) { - /* remove the segment from the - * disk's segment list - */ - rc = remove_segment_from_disk(LID->source_disk, - segment, - &empty_disk_object_list); - /* free the local instance data */ - kfree(LID); - } - /* free the segment node */ - evms_cs_deallocate_logical_node(segment); - MOD_DEC_USE_COUNT; - /* if the last segment on the disk was - * deleted, delete the disk node(s) too - */ - while (empty_disk_object_list) { - struct disk_object *dsko; - dsko = - (struct disk_object *) empty_disk_object_list->item; - rc = evms_cs_remove_item_from_list - (&empty_disk_object_list, dsko); - if (!rc) { - rc = DELETE(dsko->disk); - if (rc) { - LOG_ERROR - ("error(%d): attempting to delete '%s'.\n", - rc, dsko->disk->name); - rc = 0; - } - } - kfree(dsko); - } - } - return (rc); -} - -/* - * function: s390_partition_io_error - * - * this function was primarily created because the function - * buffer_IO_error is inline and kgdb doesn't allow breakpoints - * to be set on inline functions. Since this was an error path - * and not mainline, I decided to add a trace statement to help - * report on the failing condition. - * - */ -static void -s390_partition_io_error(int rc, - struct evms_logical_node *node, - int io_flag, struct buffer_head *bh) -{ - switch (rc) { - case 1: - LOG_SERIOUS - ("attempt to %s beyond partition boundary("PFU64") on (%s), rsector(%ld).\n", - (io_flag) ? "WRITE" : "READ", node->total_vsectors - 1, - node->name, bh->b_rsector); - break; - case 2: - LOG_ERROR - ("%s error(no active paths) on '%s' to drive the I/O.\n", - (io_flag) ? "WRITE" : "READ", node->name); - break; - } - - bh->b_end_io(bh, 0); -} - -/* - * Function: s390_partition_read - * - */ -static void -s390_partition_read(struct evms_logical_node *partition, struct buffer_head *bh) -{ - struct local_instance_data *LID = partition->private; - struct s390_io *iot = NULL; - int rc = 1; - - if (bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) <= - partition->total_vsectors) { - bh->b_rsector += LID->start_sect; - - s390_load_balance(&iot, LID->source_disk); - if (iot->dsko) { - iot->segment = partition; - iot->bh = bh; - iot->rw_flag = READ; - /* register the callback */ - evms_cs_register_for_end_io_notification(iot, bh, - s390_end_io_callback); - /* drive the IO */ - R_IO(iot->dsko->disk, bh); - return; - } else { - rc = 2; - } - } - s390_partition_io_error(rc, partition, READ, bh); -} - -/* - * Function: s390_partition_write - * - */ -static void -s390_partition_write(struct evms_logical_node *partition, - struct buffer_head *bh) -{ - struct local_instance_data *LID = partition->private; - struct s390_io *iot = NULL; - int rc = 1; - - if (bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) <= - partition->total_vsectors) { - bh->b_rsector += LID->start_sect; - - s390_load_balance(&iot, LID->source_disk); - if (iot->dsko) { - iot->segment = partition; - iot->bh = bh; - iot->rw_flag = WRITE; - /* register the callback */ - evms_cs_register_for_end_io_notification(iot, bh, - s390_end_io_callback); - /* drive the IO */ - W_IO(iot->dsko->disk, bh); - return; - } else { - rc = 2; - } - } - s390_partition_io_error(rc, partition, WRITE, bh); -} - -/* - * Function: s390_partition_init_io - * - */ -static int -s390_partition_init_io(struct evms_logical_node *partition, int io_flag, /* 0=read, 1=write */ - u64 sect_nr, /* disk LBA */ - u64 num_sects, /* # of sectors */ - void *buf_addr) -{ /* buffer address */ - int rc; - struct local_instance_data *LID = partition->private; - struct s390_io *iot = NULL; - - if ((sect_nr + num_sects) <= partition->total_vsectors) { - do { - s390_load_balance(&iot, LID->source_disk); - if (!iot->dsko) { - rc = -EIO; - break; - } - rc = INIT_IO(iot->dsko->disk, io_flag, - sect_nr + LID->start_sect, num_sects, - buf_addr); - /* do disk object IO bookkeeping */ - atomic_dec(&iot->dsko->pending_ios); - if (rc == -EIO) { - atomic_inc(&iot->dsko->failed_ios); - iot->dsko->flags = S390_DISK_FAILED; - } else { - iot->dsko->flags = S390_DISK_OK; - } - } while (rc == -EIO); - evms_cs_deallocate_to_pool(s390_io_track_pool, iot); - } else { - LOG_SERIOUS - ("init_io: attempt to %s beyond partition(%s) boundary("PFU64") at sector("PFU64") for count("PFU64").\n", - (io_flag) ? "WRITE" : "READ", partition->name, - (LID->nr_sects - 1), sect_nr, num_sects); - rc = -EINVAL; - } - - return (rc); -} - -/* - * Function: s390_partition_ioctl - * - */ -static int -s390_partition_ioctl(struct evms_logical_node *partition, - struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - struct local_instance_data *LID; - struct hd_geometry hd_geo; - int rc; - - rc = 0; - LID = partition->private; - if (!inode) - return -EINVAL; - switch (cmd) { - case HDIO_GETGEO: - { - rc = IOCTL(LID->source_disk, inode, file, cmd, arg); - if (rc) - break; - if (copy_from_user - (&hd_geo, (void *) arg, - sizeof (struct hd_geometry))) - rc = -EFAULT; - if (rc) - break; - hd_geo.start = LID->start_sect; - if (copy_to_user - ((void *) arg, &hd_geo, - sizeof (struct hd_geometry))) - rc = -EFAULT; - } - break; - case EVMS_GET_BMAP: - { - struct evms_get_bmap_pkt *bmap = - (struct evms_get_bmap_pkt *) arg; - bmap->rsector += LID->start_sect; - /* intentionally fall thru to - * default ioctl down to device - * manager. - */ - } - default: - rc = IOCTL(LID->source_disk, inode, file, cmd, arg); - } - return rc; -} - -/* - * Function: s390_part_init - * - */ -static int __init -s390_part_init(void) -{ - const char *name = "evms_s390iod"; - - /* create s390 IODaemon thread */ - s390_io_redrive_thread = evms_cs_register_thread(s390iod, NULL, name); - /* create pool of IO tracking structures */ - s390_io_track_pool = - evms_cs_create_pool(sizeof (struct s390_io), "EVMS_s390_IO", NULL, - NULL); - - return evms_cs_register_plugin(&plugin_header); /* register with EVMS */ -} - -static void __exit -s390_part_exit(void) -{ - evms_cs_destroy_pool(s390_io_track_pool); - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(s390_part_init); -module_exit(s390_part_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/evms/snapshot.c linux-2.4.20-wolk4.7-fullkernel/drivers/evms/snapshot.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/evms/snapshot.c 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/evms/snapshot.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,2798 +0,0 @@ -/* -*- linux-c -*- */ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/drivers/evms/snapshot.c - * - * EVMS SnapShot Feature. - * - * This feature provides the ability to Snapshot ANY existing EVMS volume - * (including compatibility) to a new EVMS volume that is created when the - * SnapShot is enabled. This feature will appear in the call stack for both - * the original and the snapshot volume. - */ - -#define LOG_PREFIX "snapshot: " - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct proc_dir_entry * snap_proc = NULL; -static unsigned int snapshot_count = 0; /* Number of active snapshots and originals. */ - -/* Memory pools. */ -static kmem_cache_t * snap_page_slab = NULL; -static mempool_t * snap_page_pool = NULL; -static kmem_cache_t * snap_buffer_slab = NULL; -static mempool_t * snap_buffer_pool = NULL; -static kmem_cache_t * snap_async_org_io_slab = NULL; -static mempool_t * snap_async_org_io_pool = NULL; -static kmem_cache_t * snap_async_snap_io_slab = NULL; -static mempool_t * snap_async_snap_io_pool = NULL; -static kmem_cache_t * snap_hash_entry_slab = NULL; -static mempool_t * snap_hash_entry_pool = NULL; - -#ifdef SNAPSHOT_DEBUG -static struct async_org_io * debug_async_org_io_list = NULL; -static spinlock_t debug_async_org_io_list_lock = SPIN_LOCK_UNLOCKED; -#endif - -/* API prototypes */ -static int snap_discover_volumes(struct evms_logical_node ** evms_node_list); -static int snap_delete_volume(struct evms_logical_node * node); -static void snap_read(struct evms_logical_node * node, - struct buffer_head * bh); -static void snap_write(struct evms_logical_node * node, - struct buffer_head * bh); -static int snap_init_io(struct evms_logical_node * node, int rw, - u64 sect_nr, u64 num_sects, void * buf_addr); -static int snap_ioctl(struct evms_logical_node * node, - struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); - -/* Other functions that require prototypes. */ -static int add_snapshot(struct evms_logical_node * node, - struct snapshot_metadata * metadata, - struct evms_logical_node ** evms_node_list); -static int snap_proc_read(char * page, char ** start, off_t off, - int count, int * eof, void * data); -static void snapshot_do_rollback(void * volume); -static void snap_async_io_thread(void * volume); -void snap_read_chunk_cb(struct buffer_head * bh, int uptodate); -void snap_write_chunk_cb(struct buffer_head * bh, int uptodate); -void snap_cow_table_cb(struct buffer_head * bh, int uptodate); - -/* Snapshot plugin's function table and header. */ -static struct evms_plugin_fops function_table = { - .discover = snap_discover_volumes, - .delete = snap_delete_volume, - .read = snap_read, - .write = snap_write, - .init_io = snap_init_io, - .ioctl = snap_ioctl -}; - -static struct evms_plugin_header plugin_header = { - .id = SetPluginID(IBM_OEM_ID, - EVMS_ASSOCIATIVE_FEATURE, - EVMS_SNAPSHOT_FEATURE_ID), - .version = { - .major = EVMS_SNAPSHOT_VERSION_MAJOR, - .minor = EVMS_SNAPSHOT_VERSION_MINOR, - .patchlevel = EVMS_SNAPSHOT_VERSION_PATCHLEVEL - }, - .required_services_version = { - .major = EVMS_COMMON_SERVICES_MAJOR, - .minor = EVMS_COMMON_SERVICES_MINOR, - .patchlevel = EVMS_COMMON_SERVICES_PATCHLEVEL - }, - .fops = &function_table -}; - -/** - * convert_metadata - Perform endian conversion on a metadata sector. - * @metadata: snapshot metadata sector - **/ -static void convert_metadata(struct snapshot_metadata * metadata) -{ - metadata->signature = le32_to_cpup(&metadata->signature); - metadata->CRC = le32_to_cpup(&metadata->CRC); - metadata->version.major = le32_to_cpup(&metadata->version.major); - metadata->version.minor = le32_to_cpup(&metadata->version.minor); - metadata->version.patchlevel = le32_to_cpup(&metadata->version.patchlevel); - metadata->flags = le32_to_cpup(&metadata->flags); - metadata->original_size = le64_to_cpup(&metadata->original_size); - metadata->lba_of_COW_table = le64_to_cpup(&metadata->lba_of_COW_table); - metadata->lba_of_first_chunk = le64_to_cpup(&metadata->lba_of_first_chunk); - metadata->chunk_size = le32_to_cpup(&metadata->chunk_size); - metadata->total_chunks = le32_to_cpup(&metadata->total_chunks); -} - -static void *slab_pool_alloc(int gfp_mask, void * data) -{ - return kmem_cache_alloc(data, gfp_mask); -} - -static void slab_pool_free(void * ptr, void * data) -{ - kmem_cache_free(data, ptr); -} - -/** - * allocate_snapshot_hash_entry - * @volume: Snapshot volume to get a new entry for. - * @org_chunk: Number of original chunk. - * @snap_chunk: Number of remap chunk. - * @chunk_state: see SNAP_CHUNK_* - * - * Get a snapshot_hash_entry from the pool and initialize. Accessing the - * free_hash_list is safe, since we only call this function while holding - * the snap_semaphore. - */ -static struct snapshot_hash_entry * -allocate_snapshot_hash_entry(struct snapshot_volume * volume, - u64 org_chunk, - u64 snap_chunk, - u32 chunk_state) -{ - struct snapshot_hash_entry * hash_entry; - - hash_entry = volume->free_hash_list; - if (hash_entry) { - volume->free_hash_list = hash_entry->next; - hash_entry->org_chunk = org_chunk; - hash_entry->snap_chunk = snap_chunk; - hash_entry->chunk_state = chunk_state; - hash_entry->snap_io = NULL; - hash_entry->next = NULL; - hash_entry->prev = NULL; - spin_lock_init(&hash_entry->chunk_state_lock); - } else { - /* Should never happen, since hash entries are max - * allocated at discovery time. - */ - BUG(); - } - - return hash_entry; -} - -/** - * insert_snapshot_hash_entry - * - * Insert a new entry into a snapshot hash chain, immediately following the - * specified entry. This function should not be used to add an entry into an - * empty list, or as the first entry in an existing list. For that case, use - * insert_snapshot_map_entry_at_head(). - */ -static int insert_snapshot_hash_entry(struct snapshot_hash_entry * entry, - struct snapshot_hash_entry * base) -{ - entry->next = base->next; - entry->prev = base; - base->next = entry; - if ( entry->next ) { - entry->next->prev = entry; - } - return 0; -} - -/** - * insert_snapshot_hash_entry_at_head - * - * Insert a new entry into a snapshot chain as the first entry in the chain. - */ -static int insert_snapshot_hash_entry_at_head(struct snapshot_hash_entry * entry, - struct snapshot_hash_entry ** head) -{ - entry->next = *head; - entry->prev = NULL; - *head = entry; - if ( entry->next ) { - entry->next->prev = entry; - } - return 0; -} - -/** - * set_snapshot_flags - * @snap_node: - * @set_flag: Flags to turn "on" in the metadata sector. - * @unset_flag: Flags to turn "off" in the metadata sector. - * - * Set the flags field in the metadata and write the metadata sector to - * the snapshot volume. The node passed in to this function should be the - * "lower" of the snapshot nodes, meaning the one consumed by the snapshot - * plugin, not the one exported from the plugin. - * - * Appropriate values for the two flag parameters are: - * EVMS_SNAPSHOT_DISABLED - * EVMS_SNAPSHOT_FULL - * EVMS_SNAPSHOT_ROLLBACK - * EVMS_SNAPSHOT_ROLLBACK_COMP - */ -static int set_snapshot_flags(struct evms_logical_node * snap_node, - u32 set_flag, - u32 unset_flag) -{ - unsigned char data[EVMS_VSECTOR_SIZE] = {0}; - struct snapshot_metadata * metadata = (struct snapshot_metadata*)data; - - /* Read the metadata sector */ - if ( INIT_IO(snap_node, 0, snap_node->total_vsectors-3, 1, data) ) { - return -EIO; - } - - /* Set the appropriate flags. Do endian conversion on the fly. */ - metadata->flags |= cpu_to_le32p(&set_flag); - metadata->flags &= ~(cpu_to_le32p(&unset_flag)); - metadata->CRC = 0; - metadata->CRC = cpu_to_le32(evms_cs_calculate_crc(EVMS_INITIAL_CRC, - metadata, - sizeof(struct snapshot_metadata))); - - /* Write the metadata sector back to the volume. */ - if ( INIT_IO(snap_node, 1, snap_node->total_vsectors-3, 1, data) ) { - return -EIO; - } - - return 0; -} - -/** - * disable_snapshot - */ -static void disable_snapshot(struct snapshot_volume * snap_volume, - int update_metadata) -{ - LOG_ERROR("Disabling snapshot volume '%s'.\n", - snap_volume->exported_node->name); - snap_volume->flags |= EVMS_SNAPSHOT_DISABLED; - if ( update_metadata ) { - set_snapshot_flags(snap_volume->logical_node, - EVMS_SNAPSHOT_DISABLED, 0); - } else { - snap_volume->flags |= EVMS_SNAPSHOT_DISABLED_PENDING; - evms_cs_wakeup_thread(snap_volume->snapshot_org->async_io_thread); - } -} - -/** - * snap_discover_volumes - * - * Inspect the global node list, looking for volumes with a valid - * snapshot metadata sector. - */ -static int snap_discover_volumes(struct evms_logical_node ** evms_node_list) -{ - struct evms_logical_node * node, * next_node; - struct snapshot_metadata * metadata = NULL; - int org_crc, final_crc, rc = 0; - - MOD_INC_USE_COUNT; - - /* A buffer for reading the metadata. */ - metadata = kmalloc(EVMS_VSECTOR_SIZE, GFP_KERNEL); - if (!metadata) { - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - - /* Check every node on the discovery list. */ - for ( node = *evms_node_list; node && !rc; node = next_node ) { - next_node = node->next; - - /* This node must not be one we put back on the list already, - * and must have a feature header with snapshot's ID. - */ - if ( node->plugin->id == plugin_header.id || - ! node->feature_header || - node->feature_header->feature_id != plugin_header.id ) { - continue; - } - - /* Read third-to-last sector for the snapshot metadata. */ - rc = INIT_IO(node, 0, node->total_vsectors-3, 1, metadata); - if (rc) { - LOG_ERROR("IO error reading sector "PFU64" on '%s'.\n", - node->total_vsectors-3, node->name); - rc = -EVMS_FEATURE_FATAL_ERROR; - evms_cs_remove_logical_node_from_list(evms_node_list, - node); - DELETE(node); - continue; - } - - /* Check for a valid snapshot signature. */ - if ( le32_to_cpup(&metadata->signature) != - EVMS_SNAPSHOT_SIGNATURE ) { - continue; - } - evms_cs_remove_logical_node_from_list(evms_node_list, node); - - /* Check for a valid CRC. */ - org_crc = le32_to_cpup(&metadata->CRC); - metadata->CRC = 0; - final_crc = evms_cs_calculate_crc(EVMS_INITIAL_CRC, metadata, - sizeof(struct snapshot_metadata)); - if ( final_crc != org_crc ) { - LOG_ERROR("CRC error in feature data on '%s'.\n", - node->name); - rc = -EVMS_FEATURE_FATAL_ERROR; - DELETE(node); - continue; - } - - /* Check for correct metadata version. */ - convert_metadata(metadata); - if ( metadata->version.major > plugin_header.version.major ) { - LOG_ERROR("ERROR: unsuppoprted metadata version on '%s'.\n", - node->name); - rc = -EVMS_FEATURE_FATAL_ERROR; - DELETE(node); - continue; - } - - rc = add_snapshot(node, metadata, evms_node_list); - } - - kfree(metadata); - MOD_DEC_USE_COUNT; - return rc; -} - -/** - * check_quiesce - * - * Make sure an original volume and all of its snapshots are quiesced. - */ -static int check_quiesce(struct snapshot_volume * org_volume) -{ - struct snapshot_volume * next_vol; - - for ( next_vol = org_volume; - next_vol; - next_vol = next_vol->snapshot_next ) { - if ( ! (next_vol->flags & EVMS_SNAPSHOT_QUIESCED) ) { - LOG_ERROR("Can't delete snapshot, volume '%s' not quiesced.\n", - next_vol->logical_node->name); - return -EBUSY; - } - } - return 0; -} - -/** - * remove_snapshot_from_chain - * - * Remove the specified snapshot volume from its original's chain of snapshots. - */ -static int remove_snapshot_from_chain(struct snapshot_volume * snap_volume) -{ - struct snapshot_volume ** p_volume; - - if ( snap_volume->snapshot_org ) { - down_write(&snap_volume->snapshot_org->snap_semaphore); - for ( p_volume = &snap_volume->snapshot_org->snapshot_next; - *p_volume; - p_volume = &(*p_volume)->snapshot_next ) { - if ( *p_volume == snap_volume ) { - *p_volume = (*p_volume)->snapshot_next; - break; - } - } - up_write(&snap_volume->snapshot_org->snap_semaphore); - } - snap_volume->snapshot_org = NULL; - snap_volume->snapshot_next = NULL; - return 0; -} - -/** - * delete_snapshot_hash_chain - * - * Delete all items in a single chain in the hash table. - */ -static int delete_snapshot_hash_chain(struct snapshot_hash_entry * head) -{ - struct snapshot_hash_entry * next; - - while (head) { - next = head->next; - mempool_free(head, snap_hash_entry_pool); - head = next; - } - return 0; -} - -/** - * snapshot_delete_pools - * - * Delete all memory pools after all snapshots have been deleted. - * Also shutdown the daemon thread. - */ -static void snapshot_delete_pools(void) -{ - /* The pool of data pages. */ - if (snap_page_slab) { - if (snap_page_pool) { - mempool_destroy(snap_page_pool); - snap_page_pool = NULL; - } - kmem_cache_destroy(snap_page_slab); - snap_page_slab = NULL; - } - - /* The pool of snap_io_buffer's. */ - if (snap_buffer_slab) { - if (snap_buffer_pool) { - mempool_destroy(snap_buffer_pool); - snap_buffer_pool = NULL; - } - kmem_cache_destroy(snap_buffer_slab); - snap_buffer_slab = NULL; - } - - /* The pool of async_org_io's. */ - if (snap_async_org_io_slab) { - if (snap_async_org_io_pool) { - mempool_destroy(snap_async_org_io_pool); - snap_async_org_io_pool = NULL; - } - kmem_cache_destroy(snap_async_org_io_slab); - snap_async_org_io_slab = NULL; - } - - /* The pool of async_snap_io's. */ - if (snap_async_snap_io_slab) { - if (snap_async_snap_io_pool) { - mempool_destroy(snap_async_snap_io_pool); - snap_async_snap_io_pool = NULL; - } - kmem_cache_destroy(snap_async_snap_io_slab); - snap_async_snap_io_slab = NULL; - } - - /* The pool of hash table entries. */ - if (snap_hash_entry_slab) { - if (snap_hash_entry_pool) { - mempool_destroy(snap_hash_entry_pool); - snap_hash_entry_pool = NULL; - } - kmem_cache_destroy(snap_hash_entry_slab); - snap_hash_entry_slab = NULL; - } -} - -/** - * snapshot_create_pools - * - * Allocate all of the memory pools when the first snapshot is created. - * Also start up the daemon thread for processing async I/O's. - */ -static int snapshot_create_pools(void) -{ - /* Pool of data pages. */ - if (!snap_page_slab) { - snap_page_slab = kmem_cache_create("snap_page_slab", - PAGE_SIZE, 0, - SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (snap_page_slab) { - snap_page_pool = mempool_create(1, slab_pool_alloc, - slab_pool_free, - snap_page_slab); - } - } - - /* Pool of snap_io_buffer's. */ - if (!snap_buffer_slab) { - snap_buffer_slab = kmem_cache_create("snap_bh_slab", - sizeof(struct snap_io_buffer), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (snap_buffer_slab) { - snap_buffer_pool = mempool_create(1, slab_pool_alloc, - slab_pool_free, - snap_buffer_slab); - } - } - - /* Pool of async_org_io's. */ - if (!snap_async_org_io_slab) { - snap_async_org_io_slab = kmem_cache_create("async_org_io_slab", - sizeof(struct async_org_io), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (snap_async_org_io_slab) { - snap_async_org_io_pool = mempool_create(1, slab_pool_alloc, - slab_pool_free, - snap_async_org_io_slab); - } - } - - /* Pool of async_snap_io's. */ - if (!snap_async_snap_io_slab) { - snap_async_snap_io_slab = kmem_cache_create("async_snap_io_slab", - sizeof(struct async_snap_io), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (snap_async_snap_io_slab) { - snap_async_snap_io_pool = mempool_create(1, slab_pool_alloc, - slab_pool_free, - snap_async_snap_io_slab); - } - } - - /* Pool of hash table entries. */ - if (!snap_hash_entry_slab) { - snap_hash_entry_slab = kmem_cache_create("snap_hash_slab", - sizeof(struct snapshot_hash_entry), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (snap_hash_entry_slab) { - snap_hash_entry_pool = mempool_create(1, slab_pool_alloc, - slab_pool_free, - snap_hash_entry_slab); - } - } - - if ( ! snap_page_slab || ! snap_page_pool || - ! snap_buffer_slab || ! snap_buffer_pool || - ! snap_async_org_io_slab || ! snap_async_org_io_pool || - ! snap_async_snap_io_slab || ! snap_async_snap_io_pool || - ! snap_hash_entry_slab || ! snap_hash_entry_pool ) { - LOG_CRITICAL("No memory available to create snapshot pools.\n"); - snapshot_delete_pools(); - return -ENOMEM; - } - - return 0; -} - -/** - * snap_delete_volume - * - * Delete the in-memory representation of a volume. The specified node - * can actually be either a snapshot or an original. Deleting a snapshot - * causes it to be removed from its original's chain of snapshots. - * - * For async snapshots, we will need to flush the COW table and mark the - * snapshot clean in the metadata. - */ -static int snap_delete_volume(struct evms_logical_node * node) -{ - struct snapshot_volume * volume = node->private; - struct snapshot_volume * org_volume = volume->snapshot_org; - struct snapshot_volume * next_vol; - int i, rc = 0; - - /* Don't delete a snapshot that's rolling back. */ - if ( volume->flags & EVMS_SNAPSHOT_ROLLBACK && - ! (volume->flags & EVMS_SNAPSHOT_DISABLED) ) { - LOG_ERROR("Can't delete '%s' during snapshot rollback.", - node->name); - return -EBUSY; - } - - /* Delete the instance data. */ - if (volume) { - if ( volume->flags & EVMS_SNAPSHOT ) { - /* This node is a snapshot. Check that this snapshot and - * its original have been quiesced. For async snapshots, - * make sure there are no outstanding remaps in - * progress. Then remove it from the original's chain of - * snapshots. - */ - if ( ! (volume->flags & EVMS_SNAPSHOT_QUIESCED) ) { - LOG_ERROR("Can't delete snapshot, snapshot volume '%s' not quiesced.\n", - volume->logical_node->name); - return -EBUSY; - } - if ( org_volume && - ! (org_volume->flags & EVMS_SNAPSHOT_QUIESCED) ) { - LOG_ERROR("Can't delete snapshot, original volume '%s' not quiesced.\n", - org_volume->logical_node->name); - return -EBUSY; - } - - remove_snapshot_from_chain(volume); - - /* If we just deleted the only/last snapshot for this - * original, the original will not be modified. It is - * the engine's responsibility to delete the original - * and rediscover in order to clear it of its snapshot - * information. Even if that doesn't happen, the state - * of the kernel will still be safe. I/O's coming into - * this plugin for the original will just be passed - * down without any other action or modification. - */ - - /* Unregister the proc-fs entry for this node. */ - if (snap_proc) { - remove_proc_entry(node->volume_info->volume_name, - snap_proc); - } - } else { - /* This is an original. It's the engine's responsibility - * to delete all snapshots before deleting an original. - * Otherwise, a snapshot could be left pointing to an - * original that no longer exists. Thus, we just need to - * make sure there are no snapshots in the chain. - */ - rc = check_quiesce(volume); - if (rc) { - return rc; - } - - /* Shut down the async I/O thread. */ - if (volume->async_io_thread) { - evms_cs_unregister_thread(volume->async_io_thread); - } - - /* Loop through all snapshots left on this original, - * and NULL out their org pointer, in case they don't - * get deleted. - */ - for ( next_vol = volume->snapshot_next; next_vol; - next_vol = next_vol->snapshot_next ) { - next_vol->snapshot_org = NULL; - } - } - - /* Free up all memory used by the instance data, including - * the underlying node, the hash table, and the data buffer. - */ - if (volume->logical_node) { - rc = DELETE(volume->logical_node); - if (rc) { - return rc; - } - } - if (volume->snapshot_map) { - /* Delete all of the hash chains, - * then the actual table. - */ - for ( i = 0; i < volume->hash_table_size; i++ ) { - delete_snapshot_hash_chain(volume->snapshot_map[i]); - } - delete_snapshot_hash_chain(volume->free_hash_list); - vfree(volume->snapshot_map); - } - if (volume->chunk_data_buffer) { - kfree(volume->chunk_data_buffer); - } - if (volume->rollback_thread) { - evms_cs_unregister_thread(volume->rollback_thread); - } - - kfree(volume); - } - - evms_cs_deallocate_logical_node(node); - snapshot_count--; - - /* If there are no more snapshot objects, free up the memory pools. */ - if ( snapshot_count == 0 ) { - snapshot_delete_pools(); - } - - MOD_DEC_USE_COUNT; - - return 0; -} - -/** - * search_snapshot_hash_chain - * - * Search the hash chain that is anchored at the specified head pointer. If the - * chunk number is found, a pointer to that entry in the chain is set, and a 1 - * is returned. If the chunk is not found, a pointer to the previous entry is - * set and 0 is returned. If the return pointer is NULL, this means either the - * list is empty, or the specified sector should become the first list item. - */ -static int search_snapshot_hash_chain(u64 chunk, - struct snapshot_hash_entry * head, - struct snapshot_hash_entry ** result) -{ - struct snapshot_hash_entry * curr = head; - struct snapshot_hash_entry * prev = head; - while ( curr && curr->org_chunk < chunk ) { - prev = curr; - curr = curr->next; - } - if (!curr) { - /* Either an empty chain or went off the end of the chain. */ - *result = prev; - return 0; - } else if ( curr->org_chunk != chunk ) { - *result = curr->prev; - return 0; - } else { - *result = curr; - return 1; - } -} - -/** - * snapshot_remap_chunk - * - * Perform a sector remap on a snapshot volume. This should be called from the - * I/O read path, It first determines the base sector of the chunk containing - * the specified sector, and saves the remainder. Then it performs a search - * through the snapshot map for the specified volume. If a match is found, the - * sector number is changed to the new value. If no match is found, the value - * is left the same, meaning the read should proceed down the original volume. - */ -static int snapshot_remap_chunk(struct snapshot_volume * snap_volume, - struct buffer_head * bh) -{ - struct snapshot_hash_entry * result; - u64 chunk, sector = bh->b_rsector; - unsigned long remainder, hash_value; - unsigned long flags, queued = FALSE; - - remainder = sector & (u64)(snap_volume->chunk_size - 1); - chunk = sector >> snap_volume->chunk_shift; - hash_value = ((unsigned long)chunk) % snap_volume->hash_table_size; - - if ( search_snapshot_hash_chain(chunk, - snap_volume->snapshot_map[hash_value], - &result) ) { - bh->b_rsector = (result->snap_chunk << snap_volume->chunk_shift) - + remainder; - if ( result->chunk_state != SNAP_CHUNK_COPIED ) { - /* If this chunk is in the middle of being copied, - * place this request on the pending list. - */ - spin_lock_irqsave(&result->chunk_state_lock, flags); - if ( result->chunk_state != SNAP_CHUNK_COPIED ) { - bh->b_reqnext = result->snap_io->pending_reads; - result->snap_io->pending_reads = bh; - if (!result->snap_io->dev) { - result->snap_io->dev = bh->b_rdev; - } - evms_cs_volume_request_in_progress(result->snap_io->dev, - +1, NULL); - queued = TRUE; - } - spin_unlock_irqrestore(&result->chunk_state_lock, flags); - } - - if (queued) { - return -1; - } else { - return 1; - } - } - return 0; -} - -/** - * snap_read - */ -static void snap_read(struct evms_logical_node * node, - struct buffer_head * bh) -{ - struct snapshot_volume * volume = node->private; - u64 alignment; - int rc; - - /* Size check. */ - if ( bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) > - node->total_vsectors ) { - bh->b_end_io(bh, 0); - return; - } - - /* Can't read if rollback is in progress. */ - if ( volume->flags & EVMS_SNAPSHOT_ROLLBACK ) { - LOG_ERROR("Cannot read from snapshot '%s' during rollback.\n", - volume->logical_node->name); - bh->b_end_io(bh, 0); - return; - } - - /* On a read to the original, we can just pass it through completely - * untouched. Only reads to the snapshot can be remapped. - */ - if ( volume->flags & EVMS_SNAPSHOT_ORG ) { - R_IO(volume->logical_node, bh); - return; - } - - /* Lock the snapshot before processing the request. */ - down_read(&volume->snap_semaphore); - - /* Make sure the snapshot is not full/disabled, and that - * the original is present. - */ - if ( (volume->flags & (EVMS_SNAPSHOT_DISABLED|EVMS_SNAPSHOT_FULL)) || - (! volume->snapshot_org) ) { - bh->b_end_io(bh, 0); - up_read(&volume->snap_semaphore); - return; - } - - /* Check for unaligned I/O. This is mostly to prevent XFS from - * sending a request that spans a chunk. - */ - alignment = bh->b_rsector; - alignment <<= EVMS_VSECTOR_SIZE_SHIFT; - if ( unlikely(alignment & (bh->b_size - 1)) ) { - LOG_ERROR("Unaligned request [rsector(%lx), size(%x)] rejected on snapshot %s.\n", - bh->b_rsector, bh->b_size, node->name); - bh->b_end_io(bh, 0); - up_read(&volume->snap_semaphore); - return; - } - - /* Check if this sector has been remapped. */ - rc = snapshot_remap_chunk(volume, bh); - if ( rc > 0 ) { - /* Sector was remapped. Send IO to the snapshot. */ - up_read(&volume->snap_semaphore); - R_IO(volume->logical_node, bh); - } else if ( rc < 0 ) { - /* Sector was remapped but queued to be driven later. */ - up_read(&volume->snap_semaphore); - } else { - /* Has not been remapped. Send IO to the original. */ - R_IO(volume->snapshot_org->logical_node, bh); - up_read(&volume->snap_semaphore); - } -} - - -/********** Asynchronous Snapshot I/O Code **********/ - - -/** - * snap_deallocate_buffer - */ -static void snap_deallocate_buffer(struct snap_io_buffer * buf, - int deallocate_page) -{ - if (buf) { - if (deallocate_page) { - mempool_free(buf->bh->b_data, snap_page_pool); - } - mempool_free(buf, snap_buffer_pool); - } -} - -/** - * snap_allocate_buffer - * - * Allocate a snap_io_buffer and a data page from the respective memory - * pools. Initialize as appropriate. - */ -static struct snap_io_buffer * snap_allocate_buffer(int allocate_page) -{ - struct snap_io_buffer * buf; - struct buffer_head * bh; - - /* Grab a snap_io_buffer from the pool. */ - buf = mempool_alloc(snap_buffer_pool, GFP_NOIO); - if (!buf) { - return NULL; - } - memset(buf, 0, sizeof(struct snap_io_buffer)); - bh = buf->bh = &buf->_bh; - - /* Grab a data page from the pool. */ - if (allocate_page) { - bh->b_data = mempool_alloc(snap_page_pool, GFP_NOIO); - if (!bh->b_data) { - snap_deallocate_buffer(buf, FALSE); - return NULL; - } - bh->b_page = virt_to_page(bh->b_data); - } - - /* Initialize the rest of the buffer. */ - bh->b_size = PAGE_SIZE; - bh->b_list = BUF_LOCKED; - atomic_set(&bh->b_count, 1); - bh->b_this_page = (struct buffer_head *)1; - bh->b_private = buf; - set_bit(BH_Dirty, &bh->b_state); - set_bit(BH_Lock, &bh->b_state); - set_bit(BH_Req, &bh->b_state); - set_bit(BH_Mapped, &bh->b_state); - set_bit(BH_Uptodate, &bh->b_state); - init_waitqueue_head(&bh->b_wait); - INIT_LIST_HEAD(&buf->chunk_write_list); - - return buf; -} - -/** - * snap_deallocate_buffer_list - * - * Free each buffer in the specified list. - */ -static void snap_deallocate_buffer_list(struct snap_io_buffer * buf_list, - int deallocate_pages) -{ - struct snap_io_buffer * buf, * buf_next; - - for ( buf = buf_list; buf; buf = buf_next ) { - buf_next = buf->buffer_next; - snap_deallocate_buffer(buf, deallocate_pages); - } -} - -/** - * snap_allocate_buffer_list - * - * Allocate a list of snap_io_buffer's which will be used to copy a chunk - * from the original to the snapshot. - */ -static struct snap_io_buffer * -snap_allocate_buffer_list(unsigned int count, - u64 starting_lba, - void (*callback)(struct buffer_head *, int), - int allocate_pages) -{ - struct snap_io_buffer * buf, * head = NULL; - struct snap_io_buffer ** tail = &head; - unsigned int i; - - for ( i = 0; i < count; i++ ) { - /* Get a buffer from the pool. */ - buf = snap_allocate_buffer(allocate_pages); - if (!buf) { - snap_deallocate_buffer_list(head, allocate_pages); - return NULL; - } - - /* Set the callback function and the sector value. */ - buf->bh->b_end_io = callback; - buf->bh->b_rsector = starting_lba + i * - (PAGE_SIZE >> EVMS_VSECTOR_SIZE_SHIFT); - - /* Add this buffer to the list to return. */ - *tail = buf; - tail = &buf->buffer_next; - } - - return head; -} - -/** - * deallocate_async_snap_io - */ -static void deallocate_async_snap_io(struct async_snap_io * async_snap_io) -{ - DEBUG_CHECK_SNAP_IO(async_snap_io); - - snap_deallocate_buffer(async_snap_io->cow_table_buffer, TRUE); - snap_deallocate_buffer_list(async_snap_io->copy_buffers, FALSE); - mempool_free(async_snap_io, snap_async_snap_io_pool); -} - -/** - * allocate_async_snap_io - * @snap_volume: The snapshot volume this chunk belongs to. - * @hash_entry: The entry in the hash table representing this chunk. - * @async_org_io: The parent async I/O structure. - * @snap_chunk_lba: The starting LBA on the snapshot for this chunk. - * @buffer_count: The number of buffers needed to copy this chunk. - * - * Allocate an async_snap_io structure from the pool and initialize. - * Create a list of buffer heads to use for the copy. - */ -static struct async_snap_io * -allocate_async_snap_io(struct snapshot_volume * snap_volume, - struct snapshot_hash_entry * hash_entry, - struct async_org_io * async_org_io, - u64 snap_chunk_lba, - unsigned int buffer_count) -{ - struct async_snap_io * async_snap_io; - - async_snap_io = mempool_alloc(snap_async_snap_io_pool, GFP_NOIO); - if (async_snap_io) { - memset(async_snap_io, 0, sizeof(struct async_snap_io)); - async_snap_io->snap_volume = snap_volume; - async_snap_io->hash_table_entry = hash_entry; - async_snap_io->org_io = async_org_io; - INIT_LIST_HEAD(&async_snap_io->snap_pending_io_list); - INIT_LIST_HEAD(&async_snap_io->cow_write_list); - atomic_set(&async_snap_io->write_count, buffer_count); - - async_snap_io->cow_table_buffer = snap_allocate_buffer(TRUE); - if (async_snap_io->cow_table_buffer) { - /* The buffer for the COW table needs to be adjusted. */ - struct snap_io_buffer * buf = async_snap_io->cow_table_buffer; - buf->bh->b_size = EVMS_VSECTOR_SIZE; - buf->bh->b_end_io = snap_cow_table_cb; - buf->buffer_private = async_snap_io; - - async_snap_io->copy_buffers = - snap_allocate_buffer_list(buffer_count, - snap_chunk_lba, - snap_write_chunk_cb, - FALSE); - if (!async_snap_io->copy_buffers) { - deallocate_async_snap_io(async_snap_io); - async_snap_io = NULL; - } - } else { - deallocate_async_snap_io(async_snap_io); - async_snap_io = NULL; - } - } - return async_snap_io; -} - -/** - * deallocate_async_org_io - */ -static void deallocate_async_org_io(struct async_org_io * async_org_io) -{ - DEBUG_REMOVE_ORG_IO_FROM_LIST(async_org_io); - - snap_deallocate_buffer_list(async_org_io->copy_buffers, TRUE); - mempool_free(async_org_io, snap_async_org_io_pool); -} - -/** - * allocate_async_org_io - * - * Allocate an async_org_io structure from the pool and initialize. - * Create a list of buffer heads to use for the copy. - */ -static struct async_org_io * -allocate_async_org_io(struct snapshot_volume * org_volume, - u64 org_chunk_lba, - unsigned int buffer_count) -{ - struct async_org_io * async_org_io; - - async_org_io = mempool_alloc(snap_async_org_io_pool, GFP_NOIO); - if (async_org_io) { - DEBUG_ADD_ORG_IO_TO_LIST(async_org_io); - - memset(async_org_io, 0, sizeof(struct async_org_io)); - async_org_io->org_volume = org_volume; - spin_lock_init(&async_org_io->pending_writes_lock); - INIT_LIST_HEAD(&async_org_io->org_pending_io_list); - atomic_set(&async_org_io->copy_count, 0); - atomic_set(&async_org_io->ref_count, 1); - - async_org_io->copy_buffers = - snap_allocate_buffer_list(buffer_count, - org_chunk_lba, - snap_read_chunk_cb, - TRUE); - if (!async_org_io->copy_buffers) { - deallocate_async_org_io(async_org_io); - async_org_io = NULL; - } - } - return async_org_io; -} - -/** - * deallocate_async_io - * - * This function deletes the entire async I/O structure, including the - * async_org_io, all async_snap_io's, and all buffer heads and pages. - */ -static void deallocate_async_io(struct async_org_io * async_org_io) -{ - struct async_snap_io * async_snap_io, * next_snap_io; - - for ( async_snap_io = async_org_io->snap_io_list; - async_snap_io; - async_snap_io = next_snap_io ) { - next_snap_io = async_snap_io->snap_io_list_next; - deallocate_async_snap_io(async_snap_io); - } - deallocate_async_org_io(async_org_io); -} - -/** - * process_org_pending_io_list - * - * Grab the first item from the org_pending_io_list and send all - * waiting write requests to the original. - */ -static void process_org_pending_io_list(struct snapshot_volume * org_volume, - int * done) -{ - struct async_org_io * async_org_io; - struct buffer_head * bh; - unsigned long flags; - - spin_lock_irqsave(&org_volume->org_pending_io_list_lock, flags); - if ( list_empty(&org_volume->org_pending_io_list) ) { - spin_unlock_irqrestore(&org_volume->org_pending_io_list_lock, - flags); - *done = TRUE; - } else { - async_org_io = ORG_PENDING_IO_ENTRY(org_volume->org_pending_io_list.next); - list_del(&async_org_io->org_pending_io_list); - spin_unlock_irqrestore(&org_volume->org_pending_io_list_lock, - flags); - - for ( bh = async_org_io->pending_writes; bh; - bh = async_org_io->pending_writes ) { - async_org_io->pending_writes = bh->b_reqnext; - bh->b_reqnext = NULL; - W_IO(async_org_io->org_volume->logical_node, bh); - evms_cs_volume_request_in_progress(async_org_io->dev, - -1, NULL); - } - - if ( atomic_dec_and_test(&async_org_io->ref_count) ) { - deallocate_async_io(async_org_io); - } - *done = FALSE; - } -} - - -/** - * process_snap_pending_io_list - * - * Grab the first item from the snap_pending_io_list and send - * all waiting read and write requests to the snapshot. - */ -static void process_snap_pending_io_list(struct snapshot_volume * org_volume, - int * done) -{ - struct async_snap_io * async_snap_io; - struct buffer_head * bh; - unsigned long flags; - - spin_lock_irqsave(&org_volume->snap_pending_io_list_lock, flags); - if ( list_empty(&org_volume->snap_pending_io_list) ) { - spin_unlock_irqrestore(&org_volume->snap_pending_io_list_lock, - flags); - } else { - async_snap_io = SNAP_PENDING_IO_ENTRY(org_volume->snap_pending_io_list.next); - list_del(&async_snap_io->snap_pending_io_list); - spin_unlock_irqrestore(&org_volume->snap_pending_io_list_lock, - flags); - - /* Reads */ - for ( bh = async_snap_io->pending_reads; bh; - bh = async_snap_io->pending_reads ) { - async_snap_io->pending_reads = bh->b_reqnext; - bh->b_reqnext = NULL; - R_IO(async_snap_io->snap_volume->logical_node, bh); - evms_cs_volume_request_in_progress(async_snap_io->dev, - -1, NULL); - } - /* Writes */ - for ( bh = async_snap_io->pending_writes; bh; - bh = async_snap_io->pending_writes ) { - async_snap_io->pending_writes = bh->b_reqnext; - bh->b_reqnext = NULL; - W_IO(async_snap_io->snap_volume->logical_node, bh); - evms_cs_volume_request_in_progress(async_snap_io->dev, - -1, NULL); - } - - if ( atomic_dec_and_test(&async_snap_io->org_io->ref_count) ) { - deallocate_async_io(async_snap_io->org_io); - } - *done = FALSE; - } -} - -/** - * process_chunk_write_list - * - * Grab the first item from the chunk_write_list and send down - * writes to each snapshot of this original. - */ -static void process_chunk_write_list(struct snapshot_volume * org_volume, - int * done) -{ - struct snap_io_buffer * buf, * snap_buf; - struct async_snap_io * async_snap_io; - unsigned long flags; - - spin_lock_irqsave(&org_volume->chunk_write_list_lock, flags); - if ( list_empty(&org_volume->chunk_write_list) ) { - spin_unlock_irqrestore(&org_volume->chunk_write_list_lock, - flags); - } else { - buf = CHUNK_WRITE_ENTRY(org_volume->chunk_write_list.next); - list_del(&buf->chunk_write_list); - spin_unlock_irqrestore(&org_volume->chunk_write_list_lock, - flags); - - for ( snap_buf = buf->copy_next; snap_buf; - snap_buf = snap_buf->copy_next ) { - async_snap_io = snap_buf->buffer_private; - W_IO(async_snap_io->snap_volume->logical_node, - snap_buf->bh); - } - *done = FALSE; - } -} - -/** - * write_cow_table - * - * On S/390 machines, the hardsector size is usually 4k, and the driver won't - * accept I/O requests that are less than 4k in size. Thus, the COW table - * cannot be written as a single sector. We must first read in the entire - * 4k hardsector, overlay the 512 byte COW table, and then write out the entire - * 4k again. - * - * On machines with hardsector size of 512, the COW table write will be - * processed just as it was before. - * - * If an error occurs in this function, we will send down the buffer as as - * read instead of a write. This will ensure that the callback function still - * runs and cleans up the async_io structures and releases all pending I/Os. - */ -static inline void write_cow_table(struct snapshot_volume * snap, - struct buffer_head * bh) -{ - if ( snap->logical_node->hardsector_size > bh->b_size ) { - u64 offset; - u8 * buffer; - unsigned short b_size = bh->b_size; - int rc; - - offset = bh->b_rsector & ((snap->logical_node->hardsector_size >> - EVMS_VSECTOR_SIZE_SHIFT) - 1); - bh->b_rsector -= offset; - bh->b_size = snap->logical_node->hardsector_size; - - /* Need a buffer to temporarily hold the COW table sector. */ - buffer = kmalloc(b_size, GFP_NOIO); - if (!buffer) { - disable_snapshot(snap, TRUE); - R_IO(snap->logical_node, bh); - return; - } - memcpy(buffer, bh->b_data, b_size); - - /* Read in the entire hardsector from disk. */ - rc = INIT_IO(snap->logical_node, READ, bh->b_rsector, - snap->logical_node->hardsector_size >> - EVMS_VSECTOR_SIZE_SHIFT, - bh->b_data); - if (rc) { - disable_snapshot(snap, TRUE); - R_IO(snap->logical_node, bh); - return; - } - - /* Copy the COW table back into the buffer. */ - memcpy(bh->b_data + (offset << EVMS_VSECTOR_SIZE_SHIFT), - buffer, b_size); - } - - W_IO(snap->logical_node, bh); -} - -/** - * process_cow_table_write_lists - */ -static void process_cow_table_write_lists(struct snapshot_volume * org_volume, - int * done) -{ - struct snapshot_volume * snap_volume; - struct async_snap_io * async_snap_io, * async_snap_io2; - struct list_head * lh; - unsigned long flags; - - /* Check the chunk_write_list for each snapshot on this original. */ - down_read(&org_volume->snap_semaphore); - for ( snap_volume = org_volume->snapshot_next; - snap_volume; - snap_volume = snap_volume->snapshot_next ) { - - /* While we are here, see if the DISABLED bit needs to - * be written to disk. - */ - if ( snap_volume->flags & EVMS_SNAPSHOT_DISABLED && - snap_volume->flags & EVMS_SNAPSHOT_DISABLED_PENDING ) { - disable_snapshot(snap_volume, TRUE); - snap_volume->flags &= ~EVMS_SNAPSHOT_DISABLED_PENDING; - } - - spin_lock_irqsave(&snap_volume->cow_table_write_list_lock, - flags); - - if ( list_empty(&snap_volume->cow_table_write_list) ) { - spin_unlock_irqrestore(&snap_volume->cow_table_write_list_lock, - flags); - continue; - } - - /* Check for an in-flight COW-table-write. */ - async_snap_io = COW_WRITE_ENTRY(snap_volume->cow_table_write_list.next); - if ( atomic_read(&async_snap_io->write_count) != 0 ) { - spin_unlock_irqrestore(&snap_volume->cow_table_write_list_lock, - flags); - continue; - } - - /* See if there are any COW-table-writes that can be skipped. */ - list_for_each(lh, &snap_volume->cow_table_write_list) { - /* No need to check the first list element, since - * we've already examined it. - */ - if ( lh->prev != &snap_volume->cow_table_write_list ) { - async_snap_io = COW_WRITE_ENTRY(lh); - async_snap_io2 = COW_WRITE_ENTRY(lh->prev); - if ( atomic_read(&async_snap_io->write_count) != 0 ) { - async_snap_io = async_snap_io2; - break; - } - if ( async_snap_io->cow_table_buffer->bh->b_rsector != - async_snap_io2->cow_table_buffer->bh->b_rsector ) { - async_snap_io = async_snap_io2; - break; - } - } - } - - /* We have the buffer to send down. Now mark all - * previous COW-table buffers as in-flight. - */ - list_for_each(lh, &snap_volume->cow_table_write_list) { - async_snap_io2 = COW_WRITE_ENTRY(lh); - atomic_dec(&async_snap_io2->write_count); - if ( async_snap_io2 == async_snap_io ) { - break; - } - else { - DEBUG_INC_COW_TABLE_OVERLAPS(snap_volume); - } - } - - spin_unlock_irqrestore(&snap_volume->cow_table_write_list_lock, flags); - - /* Write the COW table. */ - DEBUG_INC_COW_TABLE_WRITES(snap_volume); - write_cow_table(snap_volume, async_snap_io->cow_table_buffer->bh); - - *done = FALSE; - } - up_read(&org_volume->snap_semaphore); -} - -/** - * snap_async_io_thread - * - * This is the async I/O thread function. It processes requests from four - * lists, which are embedded in the original volume structure passed to the - * thread. - * - * The first list, org_pending_io_list, contains async_org_io's, each of which - * contain a list of write requests to the original volume that are waiting on - * the completion of a chunk copy. - * - * The second list, snap_pending_io_list, contains async_snap_io's, each of - * which contain a list of read requests and a list of write requests to the - * snapshot volume that are waiting on the completion of a chunk copy. - * - * The third list, chunk_write_list, contains buffers that were used to read - * part of a chunk from the original volume. Those buffers are linked to other - * buffers which are used to write the same part of that chunk to the snapshot. - * - * The fourth list is actually the list of snapshots for this original. Each - * snapshot then has a list of COW-table buffers that have to be written. The - * processing of this list is optimized to eliminate unnecessary, overlapping - * writes of the COW table. - * - * The loop will continue as long as there is an item on at least one of - * the four lists. When they are all empty, the loop exits and the thread - * goes back to sleep. - */ -static void snap_async_io_thread(void * volume) -{ - struct snapshot_volume * org_volume = volume; - int done = FALSE; - - while (!done) { - process_org_pending_io_list(org_volume, &done); - - process_snap_pending_io_list(org_volume, &done); - - process_chunk_write_list(org_volume, &done); - - process_cow_table_write_lists(org_volume, &done); - } - - run_task_queue(&tq_disk); -} - -/** - * schedule_org_pending_io - * - * Place the async_org_io on the thread's processing list. - */ -static void schedule_org_pending_io(struct async_org_io * async_org_io) -{ - struct snapshot_volume * org_volume = async_org_io->org_volume; - unsigned long flags; - - spin_lock_irqsave(&org_volume->org_pending_io_list_lock, flags); - list_add_tail(&async_org_io->org_pending_io_list, - &org_volume->org_pending_io_list); - spin_unlock_irqrestore(&org_volume->org_pending_io_list_lock, flags); - evms_cs_wakeup_thread(org_volume->async_io_thread); -} - -/** - * schedule_snap_pending_io - * - * Place the async_snap_io on the thread's processing list. - */ -static void schedule_snap_pending_io(struct async_snap_io * async_snap_io) -{ - struct snapshot_volume * org_volume = async_snap_io->org_io->org_volume; - unsigned long flags; - - spin_lock_irqsave(&org_volume->snap_pending_io_list_lock, flags); - list_add_tail(&async_snap_io->snap_pending_io_list, - &org_volume->snap_pending_io_list); - spin_unlock_irqrestore(&org_volume->snap_pending_io_list_lock, flags); - evms_cs_wakeup_thread(org_volume->async_io_thread); -} - -/** - * schedule_chunk_write - * - * Place the buffer on the chunk_write_list for the thread to process. This - * list uses the chunk_write_list field in the snap_io_buffer. - */ -static void schedule_chunk_write(struct snap_io_buffer * buf) -{ - struct async_org_io * org_io = buf->buffer_private; - struct snapshot_volume * org_volume = org_io->org_volume; - unsigned long flags; - - spin_lock_irqsave(&org_volume->chunk_write_list_lock, flags); - list_add_tail(&buf->chunk_write_list, &org_volume->chunk_write_list); - spin_unlock_irqrestore(&org_volume->chunk_write_list_lock, flags); - evms_cs_wakeup_thread(org_volume->async_io_thread); -} - -/** - * schedule_cow_table_write - * - * Place the async_snap_io on the thread's processing list. - */ -static void schedule_cow_table_write(struct async_snap_io * async_snap_io) -{ - struct snapshot_volume * snap_volume = async_snap_io->snap_volume; - unsigned long flags; - - spin_lock_irqsave(&snap_volume->cow_table_write_list_lock, flags); - list_add_tail(&async_snap_io->cow_write_list, - &snap_volume->cow_table_write_list); - spin_unlock_irqrestore(&snap_volume->cow_table_write_list_lock, flags); -} - -/** - * snap_read_chunk_cb - * - * This is the callback function for reading chunks from the original. - * When each read completes, we have to decrement the read_count in the - * async_org_io. If this count reaches zero, we can decrement the - * chunk_lock's in all of the hash entries, and send the original write - * request down. Finally, send this buffer head over to the thread to - * send the writes down to the snapshots. - */ -void snap_read_chunk_cb(struct buffer_head * bh, - int uptodate) -{ - struct snap_io_buffer * buf = bh->b_private; - - if (!uptodate) { - /* Error reading the chunk. Disable all snapshots on this org. */ - struct async_org_io * async_org_io = buf->buffer_private; - struct snapshot_volume * snap_volume; - LOG_ERROR("Error reading chunk from original '%s'.\n", - async_org_io->org_volume->exported_node->name); - for ( snap_volume = async_org_io->org_volume->snapshot_next; - snap_volume; - snap_volume = snap_volume->snapshot_next ) { - disable_snapshot(snap_volume, FALSE); - } - } - - schedule_chunk_write(buf); -} - -/** - * snap_write_chunk_cb - * - * This is the callback function for writing chunks to the snapshot. When - * each write completes, decrement the write_count in the async_snap_io. - * If this count reaches zero, decrement the chunk_lock in the hash entry, - * and decrement the remap_count in the async_org_io. If the remap_count - * reaches zero, then everybody is done, and we can free up the entire - * async_io structure. - */ -void snap_write_chunk_cb(struct buffer_head * bh, - int uptodate) -{ - struct snap_io_buffer * buf = bh->b_private; - struct async_snap_io * async_snap_io = buf->buffer_private; - - if (!uptodate) { - /* Error writing chunk. Disable this snapshot. */ - LOG_ERROR("Error writing chunk to snapshot '%s'.\n", - async_snap_io->snap_volume->exported_node->name); - disable_snapshot(async_snap_io->snap_volume, FALSE); - } - - atomic_dec(&async_snap_io->write_count); - evms_cs_wakeup_thread(async_snap_io->org_io->org_volume->async_io_thread); -} - -/** - * snap_cow_table_cb - * - * This is the callback function for writing out the COW table. - */ -void snap_cow_table_cb(struct buffer_head * bh, - int uptodate) -{ - struct snap_io_buffer * buf = bh->b_private; - struct async_snap_io * async_snap_io = buf->buffer_private; - struct async_snap_io * async_snap_io2; - struct async_org_io * async_org_io; - struct snapshot_volume * snap_volume = async_snap_io->snap_volume; - struct list_head * lh, * tmp; - unsigned long flags, flags2; - - if (!uptodate) { - /* Error writing the COW table sector. Disable the snapshot. */ - struct snapshot_volume * snap_volume = buf->buffer_private; - LOG_ERROR("Error writing COW table to snapshot '%s'.\n", - snap_volume->exported_node->name); - disable_snapshot(snap_volume, FALSE); - } - - spin_lock_irqsave(&snap_volume->cow_table_write_list_lock, flags); - - list_for_each_safe(lh, tmp, &snap_volume->cow_table_write_list) { - list_del(lh); - async_snap_io2 = COW_WRITE_ENTRY(lh); - async_org_io = async_snap_io2->org_io; - - /* Mark the chunk as copied in the hash table. */ - spin_lock_irqsave(&async_snap_io2->hash_table_entry->chunk_state_lock, - flags2); - async_snap_io2->hash_table_entry->chunk_state = SNAP_CHUNK_COPIED; - async_snap_io2->hash_table_entry->snap_io = NULL; - spin_unlock_irqrestore(&async_snap_io2->hash_table_entry->chunk_state_lock, - flags2); - - /* Release any pending I/Os waiting on this chunk. */ - schedule_snap_pending_io(async_snap_io2); - if ( atomic_dec_and_test(&async_org_io->copy_count) ) { - schedule_org_pending_io(async_org_io); - } - - if ( async_snap_io2 == async_snap_io ) { - break; - } - } - - spin_unlock_irqrestore(&snap_volume->cow_table_write_list_lock, flags); -} - -/** - * snap_queue_original_request - * - * An existing remap was found for the chunk for this write request. - * If the chunk has been fully copied, then the request can go through - * normally. If the chunk is still being processed, this request must - * be queued up to be driven after the chunk has been copied. - */ -static void snap_queue_original_request(struct snapshot_volume * snap_volume, - struct buffer_head * org_bh, - struct snapshot_hash_entry * target_entry, - u64 remainder, - int * queued_org_bh, - int write_to_snapshot) -{ - struct async_org_io * org_io; - unsigned long flags, flags2; - - if (write_to_snapshot) { - org_bh->b_rsector = (target_entry->snap_chunk << - snap_volume->chunk_shift) + - remainder; - } - - if ( ! *queued_org_bh && - target_entry->chunk_state != SNAP_CHUNK_COPIED ) { - spin_lock_irqsave(&target_entry->chunk_state_lock, flags); - if (write_to_snapshot) { - /* A write to the snapshot. */ - if ( target_entry->chunk_state != SNAP_CHUNK_COPIED ) { - org_bh->b_reqnext = - target_entry->snap_io->pending_writes; - target_entry->snap_io->pending_writes = org_bh; - if (!target_entry->snap_io->dev) { - target_entry->snap_io->dev = - org_bh->b_rdev; - } - evms_cs_volume_request_in_progress(target_entry->snap_io->dev, - +1, NULL); - *queued_org_bh = TRUE; - } - } else { - /* A write to the original. */ - if ( target_entry->chunk_state != SNAP_CHUNK_COPIED ) { - org_io = target_entry->snap_io->org_io; - spin_lock_irqsave(&org_io->pending_writes_lock, - flags2); - org_bh->b_reqnext = org_io->pending_writes; - org_io->pending_writes = org_bh; - if (!org_io->dev) { - org_io->dev = org_bh->b_rdev; - } - spin_unlock_irqrestore(&org_io->pending_writes_lock, - flags2); - evms_cs_volume_request_in_progress(org_io->dev, - +1, NULL); - *queued_org_bh = TRUE; - } - } - spin_unlock_irqrestore(&target_entry->chunk_state_lock, flags); - } -} - -/** - * snapshot_copy_1 - * - * Check this snapshot node to see if the given sector/chunk has been - * remapped yet. If it hasn't, create a new hash table entry, update the - * in-memory COW table, write the COW table to disk if it is full, and - * then start the process of copying the chunk from the original to the - * snapshot. - */ -static int snapshot_copy_1(struct snapshot_volume * snap_volume, - struct buffer_head * org_bh, - struct async_org_io ** async_org_io, - int * queued_org_bh, - int write_to_snapshot) -{ - struct snapshot_volume * org_volume = snap_volume->snapshot_org; - struct snapshot_hash_entry * target_entry, * new_map_entry; - struct snap_io_buffer * cow_buf, *buf1, *buf2; - struct async_snap_io * async_snap_io; - u64 org_sector = org_bh->b_rsector; - u64 org_chunk_lba, snap_chunk_lba; - u64 alignment; - u64 chunk, remainder; - unsigned long hash_value, buffer_count, sectors_in_chunk; - - /* Grab the read-lock when checking for an existing remap. */ - down_read(&snap_volume->snap_semaphore); - - /* Make sure the snapshot has not been disabled. */ - if ( snap_volume->flags & (EVMS_SNAPSHOT_DISABLED|EVMS_SNAPSHOT_FULL) || - ! org_volume ) { - up_read(&snap_volume->snap_semaphore); - return -ENOSPC; - } - - /* Check for unaligned I/O. This is mostly to prevent XFS from - * sending a request that spans a chunk. - */ - alignment = org_sector << EVMS_VSECTOR_SIZE_SHIFT; - if ( unlikely(alignment & (org_bh->b_size - 1)) ) { - LOG_ERROR("Unaligned request [rsector(%lx), size(%x)] rejected on snapshot %s.\n", - org_bh->b_rsector, org_bh->b_size, - snap_volume->logical_node->name); - if (!write_to_snapshot) { - disable_snapshot(snap_volume, TRUE); - } - up_read(&snap_volume->snap_semaphore); - return -EINVAL; - } - - /* Search the hash table to see if this sector has already been - * remapped on this snapshot. - */ - chunk = org_sector >> snap_volume->chunk_shift; - remainder = org_sector & (u64)(snap_volume->chunk_size - 1); - hash_value = (unsigned long)chunk % snap_volume->hash_table_size; - - if ( search_snapshot_hash_chain(chunk, - snap_volume->snapshot_map[hash_value], - &target_entry) ) { - /* Chunk is already remapped. If the remap is still in progress, - * queue up this request to be handled later. If the remap is - * complete, we can just keep going. - */ - up_read(&snap_volume->snap_semaphore); - snap_queue_original_request(snap_volume, org_bh, - target_entry, remainder, - queued_org_bh, write_to_snapshot); - return 0; - } - - /* Convert to a write-lock and check again for a remap. - * (Same search and check as just before). - */ - up_read(&snap_volume->snap_semaphore); - down_write(&snap_volume->snap_semaphore); - if ( search_snapshot_hash_chain(chunk, - snap_volume->snapshot_map[hash_value], - &target_entry) ) { - /* Chunk is already remapped. If the remap is still in progress, - * queue up this request to be handled later. If the remap is - * complete, we can just keep going. - */ - up_write(&snap_volume->snap_semaphore); - snap_queue_original_request(snap_volume, org_bh, - target_entry, remainder, - queued_org_bh, write_to_snapshot); - return 0; - } - - /* Is there enough room left on this snapshot to remap this chunk? */ - if ( snap_volume->next_free_chunk >= snap_volume->num_chunks ) { - /* Once the snapshot becomes full, further writes to the - * original can't be remapped, and thus this snapshot - * will become "corrupted". - */ - snap_volume->flags |= EVMS_SNAPSHOT_FULL; - set_snapshot_flags(snap_volume->logical_node, - EVMS_SNAPSHOT_FULL, EVMS_SNAPSHOT_DISABLED); - up_write(&snap_volume->snap_semaphore); - return -ENOSPC; - } - - /* Create and initialize a new hash table entry for the new remap. - * The value SNAP_CHUNK_COPYING indicates that this chunk still has to - * be read from the original and written to the snapshot. - */ - new_map_entry = allocate_snapshot_hash_entry(snap_volume, - chunk, - snap_volume->next_free_chunk, - SNAP_CHUNK_COPYING); - if (!new_map_entry) { - /* Can't get memory for map entry. Disable this snapshot. */ - LOG_ERROR("Memory error allocating hash table entry for snapshot '%s'.\n", - snap_volume->exported_node->name); - disable_snapshot(snap_volume, TRUE); - up_write(&snap_volume->snap_semaphore); - return -ENOMEM; - } - - /* Add the entry to the hash table. */ - if (target_entry) { - insert_snapshot_hash_entry(new_map_entry, target_entry); - } else { - insert_snapshot_hash_entry_at_head(new_map_entry, - &(snap_volume->snapshot_map[hash_value])); - } - - /* Calculate the number of buffers that will be needed to copy this - * chunk, and the starting LBAs for both the org and the snap. - */ - org_chunk_lba = chunk * org_volume->chunk_size; - snap_chunk_lba = snap_volume->next_free_chunk * org_volume->chunk_size; - snap_volume->next_free_chunk++; - sectors_in_chunk = min(((u64)org_volume->chunk_size), - org_volume->logical_node->total_vsectors - - org_chunk_lba); - buffer_count = (sectors_in_chunk + - (PAGE_SIZE >> EVMS_VSECTOR_SIZE_SHIFT) - 1) / - (PAGE_SIZE >> EVMS_VSECTOR_SIZE_SHIFT); - - /* Create the parent async_org_io structure if it hasn't been done yet. */ - if (!*async_org_io) { - *async_org_io = allocate_async_org_io(org_volume, - org_chunk_lba, - buffer_count); - if (!*async_org_io) { - // BUGBUG: Disable the snapshot? - BUG(); - } - - /* If we are only reading a partial chunk from the original, - * may need to readjust the size in the last buffer. - */ - if ( (sectors_in_chunk < org_volume->chunk_size) && - (sectors_in_chunk & - ((PAGE_SIZE >> EVMS_VSECTOR_SIZE_SHIFT) - 1)) ) { - for ( buf1 = (*async_org_io)->copy_buffers; - buf1->buffer_next; - buf1 = buf1->buffer_next ) { - ; - } - buf1->bh->b_size = (sectors_in_chunk << - EVMS_VSECTOR_SIZE_SHIFT) & - (PAGE_SIZE - 1); - } - } - - /* Create an async_snap_io structure for this snapshot and attach to - * the org io structure. - */ - async_snap_io = allocate_async_snap_io(snap_volume, new_map_entry, - *async_org_io, snap_chunk_lba, - buffer_count); - if (!async_snap_io) { - // BUGBUG: Disable the snapshot? - BUG(); - } - - /* Fill in the next entry in the COW table. Copy the COW table to the - * buffer to be written out later. - */ - snap_volume->cow_table[snap_volume->next_cow_entry] = cpu_to_le64p(&chunk); - snap_volume->next_cow_entry++; - cow_buf = async_snap_io->cow_table_buffer; - cow_buf->bh->b_rdev = org_bh->b_rdev; - cow_buf->bh->b_rsector = snap_volume->current_cow_sector; - memcpy(cow_buf->bh->b_data, snap_volume->cow_table, EVMS_VSECTOR_SIZE); - - /* If the COW table is full, reinitialize for the next sector. */ - if ( snap_volume->next_cow_entry >= (EVMS_VSECTOR_SIZE/sizeof(u64)) ) { - snap_volume->next_cow_entry = 0; - snap_volume->current_cow_sector++; - memset(snap_volume->cow_table, 0xff, EVMS_VSECTOR_SIZE); - } - - /* Attach the original buffer head, if it hasn't been queued - * already on a different copy. - */ - if (!*queued_org_bh) { - org_bh->b_reqnext = NULL; - if (write_to_snapshot) { - /* Write to the snapshot. Attach to the async_snap_io. */ - org_bh->b_rsector = (new_map_entry->snap_chunk << - snap_volume->chunk_shift) + - remainder; - async_snap_io->pending_writes = org_bh; - async_snap_io->dev = org_bh->b_rdev; - } else { - /* Write to the original. Attatch to the async_org_io. */ - (*async_org_io)->pending_writes = org_bh; - (*async_org_io)->dev = org_bh->b_rdev; - } - evms_cs_volume_request_in_progress(org_bh->b_rdev, +1, NULL); - *queued_org_bh = TRUE; - } - - /* Point the hash table entry at this async_snap_io. Then add this - * async_snap_io to the list in the async_org_io, as well as to the - * list in the snapshot volume. - */ - new_map_entry->snap_io = async_snap_io; - - async_snap_io->snap_io_list_next = (*async_org_io)->snap_io_list; - (*async_org_io)->snap_io_list = async_snap_io; - atomic_inc(&(*async_org_io)->copy_count); - atomic_inc(&(*async_org_io)->ref_count); - - schedule_cow_table_write(async_snap_io); - - /* Parallel walk through the copy_buffer's in the org and the snap, - * updating all necessary pointers and lists. - */ - for ( buf1 = (*async_org_io)->copy_buffers, - buf2 = async_snap_io->copy_buffers; - buf1 && buf2; - buf1 = buf1->buffer_next, buf2 = buf2->buffer_next ) { - buf2->copy_next = buf1->copy_next; - buf2->buffer_private = async_snap_io; - buf2->bh->b_rdev = org_bh->b_rdev; - buf2->bh->b_data = buf1->bh->b_data; - buf2->bh->b_page = buf1->bh->b_page; - - buf1->bh->b_rdev = org_bh->b_rdev; - buf1->copy_next = buf2; - buf1->buffer_private = *async_org_io; - } - - /* We're done modifying snapshot volume info, so we can release the - * lock. We can't start any reads until all snapshots for this original - * have been checked. Return and start the reads later. - */ - up_write(&snap_volume->snap_semaphore); - - return 0; -} - -/** - * snapshot_copy_data - */ -static void snapshot_copy_data(struct snapshot_volume * org_volume, - struct buffer_head * org_bh) -{ - struct snapshot_volume * snap_volume, * next_volume; - struct async_org_io * async_org_io = NULL; - struct snap_io_buffer * buf; - int queued_org_bh = FALSE; - - /* Check each snapshot on this original - * to see which one's need a remap. - */ - for ( snap_volume = org_volume->snapshot_next; - snap_volume; snap_volume = next_volume ) { - next_volume = snap_volume->snapshot_next; - snapshot_copy_1(snap_volume, org_bh, &async_org_io, - &queued_org_bh, FALSE); - } - - if (async_org_io) { - /* One or more snapshots need a remap. The async_io structures - * have been built. Now we just need to run through them and - * start all of the reads. - */ - for ( buf = async_org_io->copy_buffers; - buf; buf = buf->buffer_next ) { - R_IO(org_volume->logical_node, buf->bh); - } - } else if (!queued_org_bh) { - /* None of the snapshots needed a remap, and we didn't have to - * queue this request to be processed later due to a copy in - * progress. The write can be sent down normally. - */ - W_IO(org_volume->logical_node, org_bh); - } -} - -/** - * writeable_snapshot_copy_data - */ -static void writeable_snapshot_copy_data(struct snapshot_volume * snap_volume, - struct buffer_head * org_bh) -{ - struct snapshot_volume * org_volume = snap_volume->snapshot_org; - struct async_org_io * async_org_io = NULL; - struct snap_io_buffer * buf; - int rc, queued_org_bh = FALSE; - - rc = snapshot_copy_1(snap_volume, org_bh, &async_org_io, - &queued_org_bh, TRUE); - if ( rc < 0 ) { - org_bh->b_end_io(org_bh, 0); - return; - } - - if (async_org_io) { - /* Need to remap this chunk to the snapshot. The async_io - * structures have been built. Just need to run through them - * and start all of the reads. - */ - for ( buf = async_org_io->copy_buffers; buf; - buf = buf->buffer_next ) { - R_IO(org_volume->logical_node, buf->bh); - } - } else if (!queued_org_bh) { - /* No remap. The write can be sent down immediately. */ - W_IO(snap_volume->logical_node, org_bh); - } -} - -/** - * snap_write - */ -static void snap_write(struct evms_logical_node * node, - struct buffer_head * bh) -{ - struct snapshot_volume * volume = node->private; - - /* Size check. */ - if ( bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT) > - node->total_vsectors) { - bh->b_end_io(bh, 0); - return; - } - - /* Can't write if rollback is in progress. */ - if ( volume->flags & EVMS_SNAPSHOT_ROLLBACK ) { - LOG_ERROR("Cannot write to snapshot '%s' during rollback.\n", - volume->logical_node->name); - bh->b_end_io(bh, 0); - return; - } - - if ( volume->flags & EVMS_SNAPSHOT ) { - /* Snapshot. */ - if ( volume->flags & EVMS_SNAPSHOT_WRITEABLE ) { - writeable_snapshot_copy_data(volume, bh); - } else { - bh->b_end_io(bh, 0); - } - } else { - /* Original. */ - snapshot_copy_data(volume, bh); - } -} - -/** - * snap_ioctl - */ -static int snap_ioctl(struct evms_logical_node * logical_node, - struct inode * inode, - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct snapshot_volume * volume = logical_node->private; - struct evms_quiesce_vol_pkt * quiesce; - struct evms_plugin_ioctl_pkt pkt, * user_pkt; - int percent_full, rc = 0; - - switch (cmd) { - case EVMS_QUIESCE_VOLUME: - quiesce = (struct evms_quiesce_vol_pkt*)arg; - if (quiesce->command) { - /* Quiesce */ - volume->flags |= EVMS_SNAPSHOT_QUIESCED; - } else { - /* Un-quiesce */ - volume->flags &= ~EVMS_SNAPSHOT_QUIESCED; - } - break; - - case EVMS_GET_BMAP: - if ( volume->flags & EVMS_SNAPSHOT_ORG ) { - rc = IOCTL(volume->logical_node, inode, file, cmd, arg); - } else { - rc = -EINVAL; - } - break; - - case EVMS_PLUGIN_IOCTL: - user_pkt = (struct evms_plugin_ioctl_pkt *)arg; - - /* Copy user's parameters to kernel space. */ - if ( copy_from_user(&pkt, user_pkt, sizeof(pkt)) ) { - rc = -EFAULT; - break; - } - - if ( pkt.feature_id != logical_node->plugin->id ) { - /* This ioctl is not targetted at snapshotting, so - * broadcast the command to all children. - */ - rc = IOCTL(logical_node, inode, file, cmd, arg); - break; - } - - switch (pkt.feature_command) { - case SNAPSHOT_QUERY_PERCENT_FULL: - if ( volume->flags & EVMS_SNAPSHOT_FULL ) { - percent_full = -1; - } else if ( volume->flags & EVMS_SNAPSHOT_DISABLED ) { - percent_full = -2; - } else { - percent_full = (volume->next_free_chunk * 100) / - volume->num_chunks; - } - rc = copy_to_user(pkt.feature_ioctl_data, - &percent_full, - sizeof(percent_full)); - break; - - case SNAPSHOT_START_ROLLBACK: - if ( volume->flags & EVMS_SNAPSHOT_FULL ) { - rc = -ENOSPC; - } else if ( volume->flags & EVMS_SNAPSHOT_DISABLED ) { - rc = -EIO; - } else if ( ! (volume->flags & EVMS_SNAPSHOT) ) { - rc = -EINVAL; - } else { - set_snapshot_flags(volume->logical_node, - EVMS_SNAPSHOT_ROLLBACK, 0); - } - break; - - case SNAPSHOT_CHECK_STATE: - rc = copy_to_user(pkt.feature_ioctl_data, - &volume->flags, - sizeof(volume->flags)); - break; - - default: - rc = -EINVAL; - } - break; - - case EVMS_CHECK_MEDIA_CHANGE: - case EVMS_REVALIDATE_DISK: - case EVMS_GET_DISK_LIST: - case EVMS_CHECK_DEVICE_STATUS: - /* Broadcast these to all children. */ - if ( ! (volume->flags & EVMS_SNAPSHOT_ORG) ) { - volume = volume->snapshot_org; - } - while (volume) { - rc = IOCTL(volume->logical_node, inode, file, cmd, arg); - volume = volume->snapshot_next; - } - break; - - case EVMS_OPEN_VOLUME: - /* Disallow opens on rollback in progress. - * Otherwise fall through. - */ - if ( volume->flags & EVMS_SNAPSHOT_ROLLBACK) { - LOG_ERROR("Cannot open snapshot volume '%s' during rollback\n", - volume->logical_node->name); - rc = -EBUSY; - break; - } - - default: - rc = IOCTL(volume->logical_node, inode, file, cmd, arg); - - } - return rc; -} - -/** - * snap_init_io - */ -static int snap_init_io(struct evms_logical_node * node, - int rw, - u64 sect_nr, - u64 num_sects, - void * buf_addr) -{ - struct snapshot_volume * volume = node->private; - - /* No init io access to snapshot, and no writes allowed to original - * since they would not be snapshotted. - */ - if ( rw || (volume->flags & EVMS_SNAPSHOT) ) { - return -EINVAL; - } - return INIT_IO(volume->logical_node, rw, - sect_nr, num_sects, buf_addr); -} - -/** - * add_cow_entry_to_snapshot_map - * - * This function takes a cow table entry (from the on-disk data), and - * converts it into an appropriate entry for the snapshot map, and - * inserts it into the appropriate map for the specified volume. - */ -static int add_cow_entry_to_snapshot_map(u64 org_chunk, - u64 snap_chunk, - struct snapshot_volume * volume) -{ - struct snapshot_hash_entry * new_entry, * target_entry; - unsigned long hash_value; - - new_entry = allocate_snapshot_hash_entry(volume, org_chunk, - snap_chunk, SNAP_CHUNK_COPIED); - if (!new_entry) { - return -ENOMEM; - } - - hash_value = (long)org_chunk % volume->hash_table_size; - if ( search_snapshot_hash_chain(org_chunk, - volume->snapshot_map[hash_value], - &target_entry) ) { - /* A duplicate mapping was found. This should never happen. */ - } else { - if (target_entry) { - insert_snapshot_hash_entry(new_entry, target_entry); - } else { - insert_snapshot_hash_entry_at_head(new_entry, - &(volume->snapshot_map[hash_value])); - } - } - return 0; -} - -/** - * build_snapshot_maps - * - * Construct the initial hash table state based on - * existing COW tables on the disk. - */ -static int build_snapshot_maps(struct snapshot_volume * volume) -{ - int rc = 0; - int done = FALSE; - while (!done) { - /* Read in one sector's worth of COW tables. */ - if ( INIT_IO(volume->logical_node, 0, - volume->current_cow_sector, 1, - volume->cow_table) ) { - return -EIO; - } - - /* Translate every valid COW table entry into - * a snapshot map entry. - */ - for ( volume->next_cow_entry = 0; - volume->next_cow_entry < (EVMS_VSECTOR_SIZE/sizeof(u64)) && - volume->cow_table[volume->next_cow_entry] != 0xffffffffffffffff; - volume->next_cow_entry++, volume->next_free_chunk++ ) { - rc = add_cow_entry_to_snapshot_map(le64_to_cpup(&volume->cow_table[volume->next_cow_entry]), - volume->next_free_chunk, - volume); - if (rc) { - return(rc); - } - } - - /* Move on to the next sector if necessary. */ - if ( volume->next_cow_entry == - (EVMS_VSECTOR_SIZE/sizeof(u64)) ) { - volume->current_cow_sector++; - } else { - done = TRUE; - } - } - return 0; -} - -/** - * initialize_snapshot_node - */ -static int initialize_snapshot_node(struct evms_logical_node * snap_node, - struct evms_logical_node * new_snap_node, - struct evms_logical_node * org_node, - struct snapshot_metadata * metadata) -{ - struct snapshot_volume * snap_volume; - struct snapshot_hash_entry * new_entry; - int i, rc = 0; - - /* Instance data for the snapshot. */ - snap_volume = kmalloc(sizeof(struct snapshot_volume), GFP_KERNEL); - if (!snap_volume) { - set_snapshot_flags(snap_node, EVMS_SNAPSHOT_DISABLED, 0); - snap_delete_volume(new_snap_node); - DELETE(snap_node); - return -ENOMEM; - } - memset(snap_volume, 0, sizeof(struct snapshot_volume)); - - /* Initialize the snapshot node. */ - new_snap_node->total_vsectors = org_node->total_vsectors; - new_snap_node->plugin = &plugin_header; - new_snap_node->private = snap_volume; - new_snap_node->flags = snap_node->flags | - (org_node->flags & (EVMS_DEVICE_REMOVABLE | EVMS_VOLUME_PARTIAL)) | - ((metadata->flags & EVMS_SNAPSHOT_WRITEABLE) ? 0 : EVMS_VOLUME_READ_ONLY); - new_snap_node->hardsector_size = snap_node->hardsector_size; - new_snap_node->block_size = snap_node->block_size; - new_snap_node->system_id = EVMS_SNAPSHOT_SIGNATURE; - new_snap_node->volume_info = snap_node->volume_info; - /* Get the new node's name from the consumed node's feature header. */ - strcpy(new_snap_node->name, snap_node->feature_header->object_name); - - /* Initialize the private data. */ - snap_volume->logical_node = snap_node; - snap_volume->exported_node = new_snap_node; - init_rwsem(&snap_volume->snap_semaphore); - snap_volume->chunk_size = metadata->chunk_size; - snap_volume->chunk_shift = evms_cs_log2((u64)metadata->chunk_size); - snap_volume->num_chunks = metadata->total_chunks; - snap_volume->current_cow_sector = metadata->lba_of_COW_table; - snap_volume->hash_table_size = metadata->total_chunks / MAX_HASH_CHAIN_ENTRIES + 1; - snap_volume->flags = EVMS_SNAPSHOT | - (metadata->flags & EVMS_SNAPSHOT_WRITEABLE) | - (metadata->flags & EVMS_SNAPSHOT_ASYNC); - INIT_LIST_HEAD(&snap_volume->cow_table_write_list); - spin_lock_init(&snap_volume->cow_table_write_list_lock); - -#ifdef SNAPSHOT_DEBUG - atomic_set(&snap_volume->cow_table_writes, 0); - atomic_set(&snap_volume->cow_table_overlaps, 0); -#endif - - if ( metadata->flags & EVMS_SNAPSHOT_ROLLBACK ) { - - /* Buffer for reading rollback data. */ - snap_volume->chunk_data_buffer = kmalloc(SNAPSHOT_CHUNK_BUFFER_SIZE << - EVMS_VSECTOR_SIZE_SHIFT, - GFP_KERNEL); - if (!snap_volume->chunk_data_buffer) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return -ENOMEM; - } - - /* Create the rollback thread. */ - snap_volume->rollback_thread = - evms_cs_register_thread(snapshot_do_rollback, - snap_volume, - "evms_snapshot_rollback"); - if (!snap_volume->rollback_thread){ - LOG_SERIOUS("Could not start rollback thread for snapshot '%s'.\n", - snap_node->name); - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return -ENOMEM; - } - } else { - /* Snapshot hash table. */ - snap_volume->snapshot_map = vmalloc(snap_volume->hash_table_size * - sizeof(struct snapshot_hash_entry*)); - if (!snap_volume->snapshot_map) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return -ENOMEM; - } - memset(snap_volume->snapshot_map, 0, - snap_volume->hash_table_size * - sizeof(struct snapshot_hash_entry*)); - - /* Pre-allocate all of the hash entries we will need and - * store them in the free list in the volume. - */ - for ( i = 0; i < snap_volume->num_chunks; i++ ) { - new_entry = mempool_alloc(snap_hash_entry_pool, - GFP_KERNEL); - if (!new_entry) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return -ENOMEM; - } - new_entry->next = snap_volume->free_hash_list; - snap_volume->free_hash_list = new_entry; - } - - rc = build_snapshot_maps(snap_volume); - if (rc) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return rc; - } - } - - return 0; -} - -/** - * initialize_original_node - */ -static int initialize_original_node(struct evms_logical_node * snap_node, - struct evms_logical_node * new_snap_node, - struct evms_logical_node * org_node, - struct evms_logical_node * new_org_node) -{ - struct snapshot_volume * snap_volume = new_snap_node->private; - struct snapshot_volume * org_volume; - - /* Instance data for the original. */ - org_volume = kmalloc(sizeof(struct snapshot_volume), GFP_KERNEL); - if (!org_volume) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - snap_delete_volume(new_org_node); - return -ENOMEM; - } - memset(org_volume, 0, sizeof(struct snapshot_volume)); - - /* Initialize the new node. */ - new_org_node->total_vsectors = org_node->total_vsectors; - new_org_node->plugin = &plugin_header; - new_org_node->private = org_volume; - new_org_node->flags = org_node->flags | - (snap_node->flags & - (EVMS_DEVICE_REMOVABLE | EVMS_VOLUME_PARTIAL)); - new_org_node->hardsector_size = org_node->hardsector_size; - new_org_node->block_size = org_node->block_size; - new_org_node->system_id = EVMS_ORIGINAL_SIGNATURE; - new_org_node->volume_info = org_node->volume_info; - /* Must reuse the original node's name. */ - strcpy(new_org_node->name, org_node->name); - - /* Initialize the private data. */ - org_volume->logical_node = org_node; - org_volume->exported_node = new_org_node; - init_rwsem(&org_volume->snap_semaphore); - org_volume->chunk_size = snap_volume->chunk_size; - org_volume->chunk_shift = snap_volume->chunk_shift; - org_volume->flags = EVMS_SNAPSHOT_ORG | - (snap_volume->flags & EVMS_SNAPSHOT_ASYNC); - INIT_LIST_HEAD(&org_volume->chunk_write_list); - spin_lock_init(&org_volume->chunk_write_list_lock); - INIT_LIST_HEAD(&org_volume->org_pending_io_list); - spin_lock_init(&org_volume->org_pending_io_list_lock); - INIT_LIST_HEAD(&org_volume->snap_pending_io_list); - spin_lock_init(&org_volume->snap_pending_io_list_lock); - - /* Start the async I/O thread for this original. */ - org_volume->async_io_thread = - evms_cs_register_thread(snap_async_io_thread, org_volume, - "evms_async_snapshot"); - if (!org_volume->async_io_thread) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - snap_delete_volume(new_org_node); - return -ENOMEM; - } - - return 0; -} - -/** - * add_snapshot - * - * Initializes a snapshot instance and exports an evms_logical_node to - * the global list. - */ -static int add_snapshot(struct evms_logical_node * snap_node, - struct snapshot_metadata * metadata, - struct evms_logical_node ** evms_node_list) -{ - struct evms_logical_node * new_snap_node; - struct evms_logical_node * new_org_node; - struct evms_logical_node * org_node; - struct snapshot_volume * snap_volume; - struct snapshot_volume * org_volume; - struct snapshot_volume * tmp_volume; - int rc = 0; - - /* Make sure the snapshot is not full or disabled. */ - if ( metadata->flags & (EVMS_SNAPSHOT_DISABLED | EVMS_SNAPSHOT_FULL) ) { - LOG_WARNING("Error: Snapshot %s discovered as disabled/full.\n", - snap_node->name); - LOG_WARNING(" Deleting from further use.\n"); - DELETE(snap_node); - return -ENOSPC; - } - - /* Inspect the global list until a node is found with the name of - * this snapshot's original. There can only be one original for - * each snapshot. - */ - for ( org_node = *evms_node_list; - org_node && strncmp(EVMS_GET_NODE_NAME(org_node), - metadata->original_volume, - EVMS_VOLUME_NAME_SIZE); - org_node = org_node->next ) { - ; - } - if (!org_node) { - /* No original was found. Disable and delete the snapshot. */ - LOG_ERROR("Error: No original found for snapshot %s, looking for %s\n", - snap_node->name, metadata->original_volume); - set_snapshot_flags(snap_node, EVMS_SNAPSHOT_DISABLED, 0); - DELETE(snap_node); - return -ENODEV; - } - - LOG_DEBUG("Adding snapshot for '%s'\n", org_node->name); - - /* We found the original on the list. Verify the size to be sure the - * name didn't change for compatibility. For non-512-byte hardsector - * sizes, round down org node to a hardsector multiple to be the same - * as what was stored in the metadata. - */ - if ( (org_node->total_vsectors & - (~((org_node->hardsector_size/EVMS_VSECTOR_SIZE)-1))) != - metadata->original_size ) { - /* The snapshot no longer points at a valid original. - * Disable and delete the snapshot. - */ - LOG_ERROR("Error: Original volume size does not match for snapshot '%s'!\n", - snap_node->name); - LOG_ERROR(" volume=%s: org_size="PFU64", current size="PFU64"\n", - org_node->name, metadata->original_size, - org_node->total_vsectors); - set_snapshot_flags(snap_node, EVMS_SNAPSHOT_DISABLED, 0); - DELETE(snap_node); - return -ENODEV; - } - - /* New EVMS node for the snapshot. */ - if ( evms_cs_allocate_logical_node(&new_snap_node) ) { - set_snapshot_flags(snap_node, EVMS_SNAPSHOT_DISABLED, 0); - DELETE(snap_node); - return -ENOMEM; - } - - MOD_INC_USE_COUNT; - snapshot_count++; - - snapshot_create_pools(); - - rc = initialize_snapshot_node(snap_node, new_snap_node, - org_node, metadata); - if (rc) { - return rc; - } - snap_volume = new_snap_node->private; - - /* Check to see if the node we found is one we put back on the list due - * to another snapshot of the original, if so then don't allocate a new - * node and volume info, just get the old one. - */ - if ( org_node->plugin->id != plugin_header.id ) { - - /* New EVMS node for the original. */ - if ( evms_cs_allocate_logical_node(&new_org_node) ) { - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return -ENOMEM; - } - - MOD_INC_USE_COUNT; - snapshot_count++; - - rc = initialize_original_node(snap_node, new_snap_node, - org_node, new_org_node); - if (rc) { - return rc; - } - org_volume = new_org_node->private; - - /* Remove the original volume from the global list, then - * add the new version of the original to the global list. - */ - evms_cs_remove_logical_node_from_list(evms_node_list, org_node); - evms_cs_add_logical_node_to_list(evms_node_list, new_org_node); - } else { - /* There is already at least one snapshot for this original. */ - new_org_node = org_node; - org_volume = new_org_node->private; - org_node = org_volume->logical_node; - - /* Make sure this snapshot matches the current - * chunk size if we have async snapshots. - */ - if ( snap_volume->chunk_size != org_volume->chunk_size ) { - LOG_ERROR("Cannot add snapshot '%s' with chunk size %u to original '%s' with chunk size %u.\n", - new_snap_node->name, snap_volume->chunk_size, - new_org_node->name, org_volume->chunk_size); - disable_snapshot(snap_volume, TRUE); - snap_delete_volume(new_snap_node); - return -EINVAL; - } - - /* If the new snapshot is Removable or Partial, propogate - * the flags to the original and all other snapshots. - */ - for ( tmp_volume = org_volume; - tmp_volume; - tmp_volume = tmp_volume->snapshot_next) { - tmp_volume->exported_node->flags |= - (snap_node->flags & - (EVMS_DEVICE_REMOVABLE | EVMS_VOLUME_PARTIAL)); - } - } - - /* Create a proc-fs entry for this snapshot. */ - if (snap_proc) { - create_proc_read_entry(snap_node->feature_header->volume_name, - S_IFREG, snap_proc, - snap_proc_read, new_snap_node); - } - - /* Insert the new snapshot at the start of the original's chain. */ - down_write(&org_volume->snap_semaphore); - snap_volume->snapshot_next = org_volume->snapshot_next; - org_volume->snapshot_next = snap_volume; - snap_volume->snapshot_org = org_volume; - up_write(&org_volume->snap_semaphore); - - /* Place the new snapshot on the global list. */ - evms_cs_add_logical_node_to_list(evms_node_list, new_snap_node); - - if ( metadata->flags & EVMS_SNAPSHOT_ROLLBACK ) { - org_volume->flags |= EVMS_SNAPSHOT_ROLLBACK; - snap_volume->flags |= EVMS_SNAPSHOT_ROLLBACK; - evms_cs_wakeup_thread(snap_volume->rollback_thread); - } - - return 0; -} - -/** - * do_rollback - */ -void snapshot_do_rollback(void * volume) -{ - struct snapshot_volume * snap_volume = volume; - struct snapshot_volume * org_volume = snap_volume->snapshot_org; - u32 io_size = snap_volume->chunk_size; - u32 sectors = io_size; - int done = FALSE; - int i, iterations = 1; - - evms_cs_invalidate_volume(org_volume->exported_node); - evms_cs_invalidate_volume(snap_volume->exported_node); - - /* Safety to start at chunk 0. */ - snap_volume->next_free_chunk = 0; - while (!done) { - - if ( SNAPSHOT_CHUNK_BUFFER_SIZE < snap_volume->chunk_size ) { - iterations = snap_volume->chunk_size / - org_volume->chunk_size; - sectors = io_size = org_volume->chunk_size; - } - - /* Read in one sector's worth of COW tables. */ - if ( INIT_IO(snap_volume->logical_node, 0, - snap_volume->current_cow_sector, 1, - snap_volume->cow_table) ) { - LOG_ERROR("Error reading COW table from snapshot during rollback, aborting rollback\n"); - return; - } - - /* Translate every valid COW table entry into - * a snapshot map entry. - */ - for ( snap_volume->next_cow_entry = 0; - snap_volume->next_cow_entry < - (EVMS_VSECTOR_SIZE/sizeof(u64)) && - snap_volume->cow_table[snap_volume->next_cow_entry] != - 0xffffffffffffffff; - snap_volume->next_cow_entry++, - snap_volume->next_free_chunk++ ) { - for ( i = 0; i < iterations; i++ ) { - - /* Don't go off the end of the original. */ - if ( io_size > - org_volume->logical_node->total_vsectors - - (snap_volume->cow_table[snap_volume->next_cow_entry] * - snap_volume->chunk_size + i * io_size) ) { - sectors = org_volume->logical_node->total_vsectors - - (snap_volume->cow_table[snap_volume->next_cow_entry] * - snap_volume->chunk_size + i * io_size); - } - - /* Read the chunk from the snapshot volume. */ - if ( INIT_IO(snap_volume->logical_node, READ, - (snap_volume->next_free_chunk * - snap_volume->chunk_size + - i*io_size), - sectors, - snap_volume->chunk_data_buffer) ) { - LOG_ERROR("Error reading chunk %u from snapshot '%s'. Continuing.\n", - snap_volume->next_free_chunk, - snap_volume->logical_node->name); - } - - /* Write the chunk to the original volume. */ - if ( INIT_IO(org_volume->logical_node, WRITE, - snap_volume->cow_table[snap_volume->next_cow_entry] * - snap_volume->chunk_size + i*io_size, - sectors, - snap_volume->chunk_data_buffer) ) { - LOG_ERROR("Error writing chunk %u to original '%s' during rollback. Continuing.\n", - snap_volume->next_free_chunk, - org_volume->logical_node->name); - } - - if ( sectors < io_size ) { - break; - } - } - } - - /* Move on to the next COW table sector if necessary. */ - if ( snap_volume->next_cow_entry == - (EVMS_VSECTOR_SIZE/sizeof(u64)) ) { - snap_volume->current_cow_sector++; - } else { - done = TRUE; - snap_volume->flags |= EVMS_SNAPSHOT_DISABLED | - EVMS_SNAPSHOT_ROLLBACK_COMP; - snap_volume->flags &= ~EVMS_SNAPSHOT_ROLLBACK; - org_volume->flags &= ~EVMS_SNAPSHOT_ROLLBACK; - set_snapshot_flags(snap_volume->logical_node, - EVMS_SNAPSHOT_DISABLED | - EVMS_SNAPSHOT_ROLLBACK_COMP, - EVMS_SNAPSHOT_ROLLBACK); - LOG_DEFAULT("Rollback complete from snapshot %s\n", - snap_volume->exported_node->name); - } - } -} - -/** - * snap_proc_read - * - * Callback function for the proc-fs entry for each snapshot node. - * Print out pertinent information about this snapshot. The "data" - * parameter is a pointer to an EVMS logical node. - */ -static int snap_proc_read(char * page, char ** start, off_t off, - int count, int * eof, void * data) -{ - struct evms_logical_node * snap_node = data; - struct snapshot_volume * snap_volume = snap_node->private; - int sz = 0; - - PROCPRINT("Snapshot of : %s\n", (snap_volume->snapshot_org) ? EVMS_GET_NODE_NAME(snap_volume->snapshot_org->logical_node) : (u8 *)"Unknown"); - PROCPRINT("Size (KB) : %u\n", (snap_volume->num_chunks * snap_volume->chunk_size)/2); - PROCPRINT("Chunk Size (KB): %u\n", (snap_volume->chunk_size)/2); - PROCPRINT("Writeable : %s\n", (snap_volume->flags & EVMS_SNAPSHOT_WRITEABLE) ? "Yes" : "No"); - PROCPRINT("Usage : %u%%\n", (snap_volume->next_free_chunk * 100) / snap_volume->num_chunks); - PROCPRINT("Status : %s\n", (snap_volume->flags & EVMS_SNAPSHOT_FULL) ? "Full / Disabled" : (snap_volume->flags & EVMS_SNAPSHOT_DISABLED) ? "Disabled" : "Active"); -#ifdef SNAPSHOT_DEBUG - PROCPRINT("Next free chunk: %u\n", snap_volume->next_free_chunk); - PROCPRINT("COW Writes : %u\n", atomic_read(&snap_volume->cow_table_writes)); - PROCPRINT("COW Overlaps : %u\n", atomic_read(&snap_volume->cow_table_overlaps)); -#endif - -out: - *start = page + off; - sz -= off; - if (sz < 0) - sz = 0; - return sz > count ? count : sz; -} - -/** - * snapshot_init - */ -int __init snapshot_init(void) -{ - struct proc_dir_entry * pde; - - /* Register a directory in proc-fs. */ - pde = evms_cs_get_evms_proc_dir(); - if (pde) { - snap_proc = create_proc_entry("snapshot", S_IFDIR, pde); - } - - /* Register with EVMS. */ - return evms_cs_register_plugin(&plugin_header); -} - -/** - * snapshot_exit - */ -void __exit snapshot_exit(void) -{ - struct proc_dir_entry * pde; - - /* Unregister the directory in proc-fs. */ - pde = evms_cs_get_evms_proc_dir(); - if (pde) { - remove_proc_entry("snapshot", pde); - } - - evms_cs_unregister_plugin(&plugin_header); -} - -module_init(snapshot_init); -module_exit(snapshot_exit); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/Config.in linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/Config.in --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/Config.in 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/Config.in 2003-08-17 21:26:58.000000000 +0200 @@ -13,16 +13,11 @@ if [ "$CONFIG_I2C" != "n" ]; then dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT - dep_tristate ' Basic I2C on Parallel Port' CONFIG_I2C_PPORT $CONFIG_I2C_ALGOBIT - if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - dep_tristate 'SA1100 I2C Adapter' CONFIG_I2C_FRODO $CONFIG_I2C_ALGOBIT - fi fi dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF - dep_tristate ' PCF on EPP port' CONFIG_I2C_PCFEPP $CONFIG_I2C_ALGOPCF fi if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then @@ -37,10 +32,10 @@ if [ "$CONFIG_I2C" != "n" ]; then dep_tristate ' Embedded Planet RPX Lite/Classic suppoort' CONFIG_I2C_RPXLITE $CONFIG_I2C_ALGO8XX fi fi - if [ "$CONFIG_IBM_OCP" = "y" ]; then - dep_tristate 'IBM on-chip I2C Algorithm' CONFIG_I2C_IBM_OCP_ALGO $CONFIG_I2C - if [ "$CONFIG_I2C_IBM_OCP_ALGO" != "n" ]; then - dep_tristate ' IBM on-chip I2C Adapter' CONFIG_I2C_IBM_OCP_ADAP $CONFIG_I2C_IBM_OCP_ALGO + if [ "$CONFIG_405" = "y" ]; then + dep_tristate 'PPC 405 I2C Algorithm' CONFIG_I2C_PPC405_ALGO $CONFIG_I2C + if [ "$CONFIG_I2C_PPC405_ALGO" != "n" ]; then + dep_tristate ' PPC 405 I2C Adapter' CONFIG_I2C_PPC405_ADAP $CONFIG_I2C_PPC405_ALGO fi fi @@ -75,7 +70,7 @@ if [ "$CONFIG_I2C" != "n" ]; then # This is needed for automatic patch generation: sensors code ends here dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C - dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C $CONFIG_SYSCTL + dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C fi endmenu diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/Makefile 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/Makefile 2003-08-17 21:26:58.000000000 +0200 @@ -5,7 +5,7 @@ O_TARGET := i2c.o export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \ - i2c-algo-8xx.o i2c-proc.o i2c-algo-ibm_ocp.o + i2c-algo-ite.o i2c-proc.o obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o @@ -13,16 +13,12 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bi obj-$(CONFIG_I2C_PHILIPSPAR) += i2c-philips-par.o obj-$(CONFIG_I2C_ELV) += i2c-elv.o obj-$(CONFIG_I2C_VELLEMAN) += i2c-velleman.o -obj-$(CONFIG_I2C_PPORT) += i2c-pport.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o -obj-$(CONFIG_I2C_PCFEPP) += i2c-pcf-epp.o +obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o +obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o -obj-$(CONFIG_I2C_ALGO8XX) += i2c-algo-8xx.o -obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o -obj-$(CONFIG_I2C_IBM_OCP_ALGO) += i2c-algo-ibm_ocp.o -obj-$(CONFIG_I2C_IBM_OCP_ADAP) += i2c-adap-ibm_ocp.o -obj-$(CONFIG_I2C_FRODO) += i2c-frodo.o +obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o # This is needed for automatic patch generation: sensors code starts here obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/dmi_scan.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/dmi_scan.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/dmi_scan.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/dmi_scan.c 2003-08-17 21:26:58.000000000 +0200 @@ -11,12 +11,12 @@ #include #include #include -#include #include +#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" #include /* for 2.2 kernels */ @@ -177,8 +177,6 @@ static void __init dmi_save_ident(struct static void __init dmi_decode(struct dmi_header *dm) { - u8 *data = (u8 *)dm; - switch(dm->type) { case 0: @@ -230,21 +228,7 @@ void __init dmi_scan_mach(void) printk("dmi_scan.o: SM BIOS found\n"); } -#ifdef MODULE MODULE_DESCRIPTION("SM BIOS DMI Scanner"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif EXPORT_SYMBOL(dmi_ident); EXPORT_SYMBOL(dmi_scan_mach); -int init_module(void) -{ - return 0; -} - -int cleanup_module(void) -{ - return 0; -} - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-adap-ibm_ocp.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-adap-ibm_ocp.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-adap-ibm_ocp.c 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-adap-ibm_ocp.c 2003-08-17 21:26:58.000000000 +0200 @@ -57,19 +57,13 @@ #include #include #include -#include #include -#include -#include #include #include -#include +#include +#include #include -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - /* * This next section is configurable, and it is used to set the number * of i2c controllers in the system. The default number of instances is 1, @@ -146,13 +140,6 @@ static int iic_ibmocp_getclock(void *dat } -#if 0 -static void iic_ibmocp_sleep(unsigned long timeout) -{ - schedule_timeout( timeout * HZ); -} -#endif - // // Description: Put this process to sleep. We will wake up when the @@ -260,50 +247,11 @@ static void iic_ibmocp_release(void) // -// Description: Does nothing -// -static int iic_ibmocp_reg(struct i2c_client *client) -{ - return 0; -} - - -// -// Description: Does nothing -// -static int iic_ibmocp_unreg(struct i2c_client *client) -{ - return 0; -} - - -// -// Description: If this compiled as a module, then increment the count -// -static void iic_ibmocp_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - - -// -// Description: If this is a module, then decrement the count -// -static void iic_ibmocp_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -// // Description: Called when the module is loaded. This function starts the // cascade of calls up through the heirarchy of i2c modules (i.e. up to the // algorithm layer and into to the core layer) // -int __init iic_ibmocp_init(void) +static int __init iic_ibmocp_init(void) { int i; @@ -342,7 +290,7 @@ int __init iic_ibmocp_init(void) iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin; iic_ibmocp_data[i]->udelay = 80; iic_ibmocp_data[i]->mdelay = 80; - iic_ibmocp_data[i]->timeout = 100; + iic_ibmocp_data[i]->timeout = HZ; iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL); if(iic_ibmocp_ops[i] == NULL) { @@ -350,13 +298,10 @@ int __init iic_ibmocp_init(void) } memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter)); strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter"); + iic_ibmocp_ops[i]->owner = THIS_MODULE; iic_ibmocp_ops[i]->id = I2C_HW_OCP; iic_ibmocp_ops[i]->algo = NULL; iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i]; - iic_ibmocp_ops[i]->inc_use = iic_ibmocp_inc_use; - iic_ibmocp_ops[i]->dec_use = iic_ibmocp_dec_use; - iic_ibmocp_ops[i]->client_register = iic_ibmocp_reg; - iic_ibmocp_ops[i]->client_unregister = iic_ibmocp_unreg; init_waitqueue_head(&(iic_wait[i])); @@ -372,7 +317,7 @@ int __init iic_ibmocp_init(void) } -static void iic_ibmocp_exit(void) +static void __exit iic_ibmocp_exit(void) { int i; @@ -382,14 +327,14 @@ static void iic_ibmocp_exit(void) iic_ibmocp_release(); } -EXPORT_NO_SYMBOLS; - // // If modules is NOT defined when this file is compiled, then the MODULE_* // macros will resolve to nothing // MODULE_AUTHOR("MontaVista Software "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter"); +MODULE_LICENSE("GPL"); + MODULE_PARM(base, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(clock, "i"); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-adap-ite.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-adap-ite.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-adap-ite.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-adap-ite.c 2002-08-03 02:39:44.000000000 +0200 @@ -82,7 +82,7 @@ static void iic_ite_setiic(void *data, i unsigned long j = jiffies + 10; DEB3(printk(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff)); - DEB3({while (time_before(jiffies, j)) schedule();}) + DEB3({while (jiffies < j) schedule();}) outw(val,ctl); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-8xx.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-8xx.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-8xx.c 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-8xx.c 2003-08-17 21:26:58.000000000 +0200 @@ -24,31 +24,26 @@ // XXX todo // timeout sleep? -/* $Id: i2c-algo-8xx.c,v 1.8 2002/11/18 21:35:27 mds Exp $ */ +/* $Id: i2c-algo-8xx.c,v 1.9.2.2 2003/01/21 10:00:19 kmalkki Exp $ */ #include #include #include #include -#include #include -#include -#include #include #include - +#include +#include #include #include -#include -#include #define CPM_MAX_READ 513 /* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */ static wait_queue_head_t iic_wait; static ushort r_tbase, r_rbase; -int cpm_scan = 0; int cpm_debug = 0; static void @@ -73,10 +68,10 @@ cpm_iic_interrupt(void *dev_id, struct p } static void -cpm_iic_init(struct i2c_algo_8xx_data *cpm_adap) +cpm_iic_init(struct i2c_algo_8xx_data *cpm) { - volatile iic_t *iip = cpm_adap->iip; - volatile i2c8xx_t *i2c = cpm_adap->i2c; + volatile iic_t *iip = cpm->iip; + volatile i2c8xx_t *i2c = cpm->i2c; unsigned char brg; bd_t *bd = (bd_t *)__res; @@ -99,8 +94,8 @@ cpm_iic_init(struct i2c_algo_8xx_data *c /* Set up the IIC parameters in the parameter ram. */ - iip->iic_tbase = r_tbase = cpm_adap->dp_addr; - iip->iic_rbase = r_rbase = cpm_adap->dp_addr + sizeof(cbd_t)*2; + iip->iic_tbase = r_tbase = cpm->dp_addr; + iip->iic_rbase = r_rbase = cpm->dp_addr + sizeof(cbd_t)*2; iip->iic_tfcr = SMC_EB; iip->iic_rfcr = SMC_EB; @@ -111,8 +106,8 @@ cpm_iic_init(struct i2c_algo_8xx_data *c /* Initialize Tx/Rx parameters. */ - if (cpm_adap->reloc == 0) { - volatile cpm8xx_t *cp = cpm_adap->cp; + if (cpm->reloc == 0) { + volatile cpm8xx_t *cp = cpm->cp; cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; @@ -149,14 +144,14 @@ cpm_iic_init(struct i2c_algo_8xx_data *c printk ("%s[%d] Install ISR for IRQ %d\n", __func__,__LINE__, CPMVEC_I2C); } - (*cpm_adap->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c); + (*cpm->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c); } static int -cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap) +cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm) { - volatile i2c8xx_t *i2c = cpm_adap->i2c; + volatile i2c8xx_t *i2c = cpm->i2c; /* Shut down IIC. */ @@ -520,11 +515,11 @@ cpm_iic_tryaddress(struct i2c_algo_8xx_d return 1; } -static int cpm_xfer(struct i2c_adapter *i2c_adap, +static int cpm_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { - struct i2c_algo_8xx_data *adap = i2c_adap->algo_data; + struct i2c_algo_8xx_data *cpm = adap->algo_data; struct i2c_msg *pmsg; int i, ret; u_char addr; @@ -547,7 +542,7 @@ static int cpm_xfer(struct i2c_adapter * } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ - ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len); + ret = cpm_iic_read(cpm, addr, pmsg->buf, pmsg->len); if (cpm_debug) printk("i2c-algo-8xx.o: read %d bytes\n", ret); if (ret < pmsg->len ) { @@ -555,7 +550,7 @@ static int cpm_xfer(struct i2c_adapter * } } else { /* write bytes from buffer */ - ret = cpm_iic_write(adap, addr, pmsg->buf, pmsg->len); + ret = cpm_iic_write(cpm, addr, pmsg->buf, pmsg->len); if (cpm_debug) printk("i2c-algo-8xx.o: wrote %d\n", ret); if (ret < pmsg->len ) { @@ -566,12 +561,6 @@ static int cpm_xfer(struct i2c_adapter * return (num); } -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 cpm_func(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | @@ -581,14 +570,11 @@ static u32 cpm_func(struct i2c_adapter * /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm cpm_algo = { - "MPC8xx CPM algorithm", - I2C_ALGO_MPC8XX, - cpm_xfer, - NULL, - NULL, /* slave_xmit */ - NULL, /* slave_recv */ - algo_control, /* ioctl */ - cpm_func, /* functionality */ + .owner = THIS_MODULE, + .name = "MPC8xx CPM algorithm", + .id = I2C_ALGO_MPC8XX, + .master_xfer = cpm_xfer, + .functionality = cpm_func, }; /* @@ -597,7 +583,7 @@ static struct i2c_algorithm cpm_algo = { int i2c_8xx_add_bus(struct i2c_adapter *adap) { int i; - struct i2c_algo_8xx_data *cpm_adap = adap->algo_data; + struct i2c_algo_8xx_data *cpm = adap->algo_data; if (cpm_debug) printk("i2c-algo-8xx.o: hw routines for %s registered.\n", @@ -608,69 +594,23 @@ int i2c_8xx_add_bus(struct i2c_adapter * adap->id |= cpm_algo.id; adap->algo = &cpm_algo; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - i2c_add_adapter(adap); - cpm_iic_init(cpm_adap); - - /* scan bus */ - if (cpm_scan) { - printk(KERN_INFO " i2c-algo-8xx.o: scanning bus %s...\n", - adap->name); - for (i = 0; i < 128; i++) { - if (cpm_iic_tryaddress(cpm_adap, i)) { - printk("(%02x)",i<<1); - } - } - printk("\n"); - } - return 0; + cpm_iic_init(cpm); } int i2c_8xx_del_bus(struct i2c_adapter *adap) { - int res; - struct i2c_algo_8xx_data *cpm_adap = adap->algo_data; - - cpm_iic_shutdown(cpm_adap); + struct i2c_algo_8xx_data *cpm = adap->algo_data; - if ((res = i2c_del_adapter(adap)) < 0) - return res; + cpm_iic_shutdown(cpm); - printk("i2c-algo-8xx.o: adapter unregistered: %s\n",adap->name); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; + return i2c_del_adapter(adap); } EXPORT_SYMBOL(i2c_8xx_add_bus); EXPORT_SYMBOL(i2c_8xx_del_bus); -int __init i2c_algo_8xx_init (void) -{ - printk("i2c-algo-8xx.o: i2c mpc8xx algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); - return 0; -} - - -#ifdef MODULE MODULE_AUTHOR("Brad Parker "); MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return i2c_algo_8xx_init(); -} - -void cleanup_module(void) -{ -} -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-bit.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-bit.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-bit.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-bit.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,21 +21,19 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-algo-bit.c,v 1.40 2002/12/03 22:31:34 kmalkki Exp $ */ +/* $Id: i2c-algo-bit.c,v 1.41.2.3 2003/06/16 15:29:47 khali Exp $ */ #include #include #include #include -#include #include -#include -#include #include #include #include #include + /* ----- global defines ----------------------------------------------- */ #define DEB(x) if (i2c_debug>=1) x; #define DEB2(x) if (i2c_debug>=2) x; @@ -43,27 +41,13 @@ #define DEBPROTO(x) if (i2c_debug>=9) { x; } /* debug the protocol by showing transferred bits */ -/* debugging - slow down transfer to have a look at the data .. */ -/* I use this with two leds&resistors, each one connected to sda,scl */ -/* respectively. This makes sure that the algorithm works. Some chips */ -/* might not like this, as they have an internal timeout of some mils */ -/* -#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ - if (need_resched) schedule(); -*/ - /* ----- global variables --------------------------------------------- */ -#ifdef SLO_IO - int jif; -#endif - /* module parameters: */ static int i2c_debug; static int bit_test; /* see if the line-setting functions work */ -static int bit_scan; /* have a look at what's hanging 'round */ /* --- setting states on the bus with the right timing: --------------- */ @@ -88,9 +72,6 @@ static inline void scllo(struct i2c_algo { setscl(adap,0); udelay(adap->udelay); -#ifdef SLO_IO - SLO_IO -#endif } /* @@ -114,7 +95,7 @@ static inline int sclhi(struct i2c_algo_ * This is safer as some chips may hold it low * while they are processing data internally. */ - if ( time_after(jiffies, start+adap->timeout) ) { + if (time_after_eq(jiffies, start+adap->timeout)) { return -ETIMEDOUT; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) @@ -126,9 +107,6 @@ static inline int sclhi(struct i2c_algo_ } DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); udelay(adap->udelay); -#ifdef SLO_IO - SLO_IO -#endif return 0; } @@ -468,8 +446,8 @@ static inline int bit_doAddress(struct i addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) { - printk(KERN_ERR "died at extended address code.\n"); - return -EREMOTEIO; + printk(KERN_ERR "died at extended address code.\n"); + return -EREMOTEIO; } } } else { /* normal 7bit address */ @@ -530,12 +508,6 @@ static int bit_xfer(struct i2c_adapter * return num; } -static int algo_control(struct i2c_adapter *i2c_adap, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 bit_func(struct i2c_adapter *i2c_adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | @@ -546,115 +518,57 @@ static u32 bit_func(struct i2c_adapter * /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm i2c_bit_algo = { - "Bit-shift algorithm", - I2C_ALGO_BIT, - bit_xfer, - NULL, - NULL, /* slave_xmit */ - NULL, /* slave_recv */ - algo_control, /* ioctl */ - bit_func, /* functionality */ + .owner = THIS_MODULE, + .name = "Bit-shift algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = bit_xfer, + .functionality = bit_func, }; /* * registering functions to load algorithms at runtime */ -int i2c_bit_add_bus(struct i2c_adapter *i2c_adap) +int i2c_bit_add_bus(struct i2c_adapter *adap) { - int i; - struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + struct i2c_algo_bit_data *bit_adap = adap->algo_data; if (bit_test) { - int ret = test_bus(adap, i2c_adap->name); + int ret = test_bus(bit_adap, adap->name); if (ret<0) return -ENODEV; } DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: hw routines for %s registered.\n", - i2c_adap->name)); + adap->name)); /* register new adapter to i2c module... */ - i2c_adap->id |= i2c_bit_algo.id; - i2c_adap->algo = &i2c_bit_algo; + adap->id |= i2c_bit_algo.id; + adap->algo = &i2c_bit_algo; - i2c_adap->timeout = HZ; /* default values, should */ - i2c_adap->retries = 3; /* be replaced by defines */ - - /* scan bus */ - if (bit_scan) { - int ack; - printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", - i2c_adap->name); - for (i = 0x00; i < 0xff; i+=2) { - i2c_start(adap); - ack = i2c_outb(i2c_adap,i); - i2c_stop(adap); - if (ack>0) { - printk("(%02x)",i>>1); - } else - printk("."); - } - printk("\n"); - } - -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - i2c_add_adapter(i2c_adap); + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + i2c_add_adapter(adap); return 0; } -int i2c_bit_del_bus(struct i2c_adapter *i2c_adap) +int i2c_bit_del_bus(struct i2c_adapter *adap) { - int res; - - if ((res = i2c_del_adapter(i2c_adap)) < 0) - return res; - - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: adapter unregistered: %s\n",i2c_adap->name)); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; + return i2c_del_adapter(adap); } -int __init i2c_algo_bit_init (void) -{ - printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); - return 0; -} - - - EXPORT_SYMBOL(i2c_bit_add_bus); EXPORT_SYMBOL(i2c_bit_del_bus); -#ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_PARM(bit_test, "i"); -MODULE_PARM(bit_scan, "i"); MODULE_PARM(i2c_debug,"i"); MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); -MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); - -int init_module(void) -{ - return i2c_algo_bit_init(); -} - -void cleanup_module(void) -{ -} -#endif + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-ibm_ocp.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-ibm_ocp.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-ibm_ocp.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-ibm_ocp.c 2003-08-17 21:26:58.000000000 +0200 @@ -55,21 +55,13 @@ #include #include #include -#include #include -#include -#include #include #include - #include #include #include -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - /* ----- global defines ----------------------------------------------- */ #define DEB(x) if (i2c_debug>=1) x @@ -79,26 +71,13 @@ MODULE_LICENSE("GPL"); /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 5 -/* debugging - slow down transfer to have a look at the data .. */ -/* I use this with two leds&resistors, each one connected to sda,scl */ -/* respectively. This makes sure that the algorithm works. Some chips */ -/* might not like this, as they have an internal timeout of some mils */ -/* -#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ - if (need_resched) schedule(); -*/ - /* ----- global variables --------------------------------------------- */ -#ifdef SLO_IO - int jif; -#endif /* module parameters: */ static int i2c_debug=0; -static int iic_scan=0; /* have a look at what's hanging 'round */ /* --- setting states on the bus with the right timing: --------------- */ @@ -858,17 +837,14 @@ static u32 iic_func(struct i2c_adapter * /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm iic_algo = { - "IBM on-chip IIC algorithm", - I2C_ALGO_OCP, - iic_xfer, - NULL, - NULL, /* slave_xmit */ - NULL, /* slave_recv */ - algo_control, /* ioctl */ - iic_func, /* functionality */ + .owner = THIS_MODULE, + .name = "IBM on-chip IIC algorithm", + .id = I2C_ALGO_OCP, + .master_xfer = iic_xfer, + .algo_control = algo_control, + .functionality = iic_func, }; - /* * registering functions to load algorithms at runtime */ @@ -892,19 +868,8 @@ int i2c_ocp_add_bus(struct i2c_adapter * adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - iic_init(iic_adap); i2c_add_adapter(adap); - - /* scan bus */ - /* By default scanning the bus is turned off. */ - if (iic_scan) { - printk(KERN_INFO " i2c-algo-iic.o: scanning bus %s.\n", - adap->name); - } return 0; } @@ -914,31 +879,7 @@ int i2c_ocp_add_bus(struct i2c_adapter * // int i2c_ocp_del_bus(struct i2c_adapter *adap) { - int res; - if ((res = i2c_del_adapter(adap)) < 0) - return res; - DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: adapter unregistered: %s\n",adap->name)); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; -} - - -// -// Done -// -int __init i2c_algo_iic_init (void) -{ - printk(KERN_INFO "IBM On-chip iic (i2c) algorithm module 2002.27.03\n"); - return 0; -} - - -void i2c_algo_iic_exit(void) -{ - return; + return i2c_del_adapter(adap); } @@ -951,16 +892,10 @@ EXPORT_SYMBOL(i2c_ocp_del_bus); // MODULE_AUTHOR("MontaVista Software "); MODULE_DESCRIPTION("PPC 405 iic algorithm"); +MODULE_LICENSE("GPL"); -MODULE_PARM(iic_test, "i"); -MODULE_PARM(iic_scan, "i"); MODULE_PARM(i2c_debug,"i"); -MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available"); -MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus"); MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol"); - -module_init(i2c_algo_iic_init); -module_exit(i2c_algo_iic_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-ite.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-ite.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-ite.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-ite.c 2001-10-11 17:05:47.000000000 +0200 @@ -66,7 +66,7 @@ /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ if (need_resched) schedule(); */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-pcf.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-pcf.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-algo-pcf.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-algo-pcf.c 2003-08-17 21:26:58.000000000 +0200 @@ -31,15 +31,11 @@ #include #include #include -#include #include -#include -#include #include -#include #include #include -#include "i2c-pcf8584.h" + /* ----- global defines ----------------------------------------------- */ #define DEB(x) if (i2c_debug>=1) x @@ -52,7 +48,6 @@ /* module parameters: */ static int i2c_debug=0; -static int pcf_scan=0; /* have a look at what's hanging 'round */ /* --- setting states on the bus with the right timing: --------------- */ @@ -426,12 +421,6 @@ static int pcf_xfer(struct i2c_adapter * return (i); } -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 pcf_func(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | @@ -441,14 +430,11 @@ static u32 pcf_func(struct i2c_adapter * /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm pcf_algo = { - "PCF8584 algorithm", - I2C_ALGO_PCF, - pcf_xfer, - NULL, - NULL, /* slave_xmit */ - NULL, /* slave_recv */ - algo_control, /* ioctl */ - pcf_func, /* functionality */ + .owner = THIS_MODULE, + .name = "PCF8584 algorithm", + .id = I2C_ALGO_PCF, + .master_xfer = pcf_xfer, + .functionality = pcf_func, }; /* @@ -456,7 +442,7 @@ static struct i2c_algorithm pcf_algo = { */ int i2c_pcf_add_bus(struct i2c_adapter *adap) { - int i, status; + int i; struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n", @@ -474,81 +460,23 @@ int i2c_pcf_add_bus(struct i2c_adapter * return i; } -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - i2c_add_adapter(adap); - - /* scan bus */ - if (pcf_scan) { - printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n", - adap->name); - for (i = 0x00; i < 0xff; i+=2) { - if (wait_for_bb(pcf_adap)) { - printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s - TIMEOUTed.\n", - adap->name); - break; - } - i2c_outb(pcf_adap, i); - i2c_start(pcf_adap); - if ((wait_for_pin(pcf_adap, &status) >= 0) && - ((status & I2C_PCF_LRB) == 0)) { - printk("(%02x)",i>>1); - } else { - printk("."); - } - i2c_stop(pcf_adap); - udelay(pcf_adap->udelay); - } - printk("\n"); - } return 0; } int i2c_pcf_del_bus(struct i2c_adapter *adap) { - int res; - if ((res = i2c_del_adapter(adap)) < 0) - return res; - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; -} - -int __init i2c_algo_pcf_init (void) -{ - printk(KERN_INFO "i2c-algo-pcf.o: i2c pcf8584 algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); - return 0; + return i2c_del_adapter(adap); } - EXPORT_SYMBOL(i2c_pcf_add_bus); EXPORT_SYMBOL(i2c_pcf_del_bus); -#ifdef MODULE MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(pcf_scan, "i"); MODULE_PARM(i2c_debug,"i"); - -MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus"); MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); - - -int init_module(void) -{ - return i2c_algo_pcf_init(); -} - -void cleanup_module(void) -{ -} -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-ali1535.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-ali1535.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-ali1535.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-ali1535.c 2003-08-17 21:26:58.000000000 +0200 @@ -53,27 +53,19 @@ /* Note: we assume there can only be one ALI1535, with one SMBus interface */ -#include #include #include -#include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -#ifndef DECLARE_MUTEX -#define DECLARE_MUTEX(name) struct semaphore name = MUTEX -#endif /* def DECLARE_MUTEX */ /* ALI1535 SMBus address offsets */ #define SMBHSTSTS (0 + ali1535_smba) @@ -145,52 +137,9 @@ MODULE_LICENSE("GPL"); /* -> Read = 1 */ #define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_ali1535_init(void); -static int __init ali1535_cleanup(void); -static int ali1535_setup(void); -static s32 ali1535_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data); static void ali1535_do_pause(unsigned int amount); static int ali1535_transaction(void); -static void ali1535_inc(struct i2c_adapter *adapter); -static void ali1535_dec(struct i2c_adapter *adapter); -static u32 ali1535_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-i2c SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ ali1535_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ ali1535_func, -}; - -static struct i2c_adapter ali1535_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI1535, - &smbus_algorithm, - NULL, - ali1535_inc, - ali1535_dec, - NULL, - NULL, -}; - -static int __initdata ali1535_initialized; static unsigned short ali1535_smba = 0; DECLARE_MUTEX(i2c_ali1535_sem); @@ -199,32 +148,11 @@ DECLARE_MUTEX(i2c_ali1535_sem); Note the differences between kernels with the old PCI BIOS interface and newer kernels with the real PCI interface. In compat.h some things are defined to make the transition easier. */ -int ali1535_setup(void) +int ali1535_setup(struct pci_dev *ALI1535_dev) { int error_return = 0; unsigned char temp; - struct pci_dev *ALI1535_dev; - - /* First check whether we can access PCI at all */ - if (pci_present() == 0) { - printk("i2c-ali1535.o: Error: No PCI-bus found!\n"); - error_return = -ENODEV; - goto END; - } - - /* Look for the ALI1535, M7101 device */ - ALI1535_dev = NULL; - ALI1535_dev = pci_find_device(PCI_VENDOR_ID_AL, - PCI_DEVICE_ID_AL_M7101, - ALI1535_dev); - - if (ALI1535_dev == NULL) { - printk("i2c-ali1535.o: Error: Can't detect ali1535!\n"); - error_return = -ENODEV; - goto END; - } - /* Check the following things: - SMB I/O address is initialized - Device is enabled @@ -486,11 +414,6 @@ s32 ali1535_access(struct i2c_adapter * outb_p(0xFF, SMBHSTSTS); switch (size) { - case I2C_SMBUS_PROC_CALL: - printk - ("i2c-ali1535.o: I2C_SMBUS_PROC_CALL not supported!\n"); - result = -1; - goto EXIT; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); @@ -547,6 +470,11 @@ s32 ali1535_access(struct i2c_adapter * outb_p(data->block[i], SMBBLKDAT); } break; + default: + printk + (KERN_WARNING "i2c-ali1535.o: Unsupported transaction %d\n", size); + result = -1; + goto EXIT; } if (ali1535_transaction()) /* Error in transaction */ @@ -592,16 +520,6 @@ EXIT: return result; } -void ali1535_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void ali1535_dec(struct i2c_adapter *adapter) -{ - - MOD_DEC_USE_COUNT; -} u32 ali1535_func(struct i2c_adapter *adapter) { @@ -610,82 +528,82 @@ u32 ali1535_func(struct i2c_adapter *ada I2C_FUNC_SMBUS_BLOCK_DATA; } -int __init i2c_ali1535_init(void) +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-i2c SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = ali1535_access, + .functionality = ali1535_func, +}; + +static struct i2c_adapter ali1535_adapter = { + .owner = THIS_MODULE, + .name = "unset", + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI1535, + .algo = &smbus_algorithm, +}; + + +static struct pci_device_id ali1535_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_AL, + .device = PCI_DEVICE_ID_AL_M7101, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int res; - printk("i2c-ali1535.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (ali1535_initialized) { - printk - ("i2c-ali1535.o: Oops, ali1535_init called a second time!\n"); - return -EBUSY; - } -#endif - ali1535_initialized = 0; - if ((res = ali1535_setup())) { + if (ali1535_setup(dev)) { printk ("i2c-ali1535.o: ALI1535 not detected, module not inserted.\n"); - ali1535_cleanup(); - return res; + return -ENODEV; } - ali1535_initialized++; + sprintf(ali1535_adapter.name, "SMBus ALI1535 adapter at %04x", ali1535_smba); - if ((res = i2c_add_adapter(&ali1535_adapter))) { - printk - ("i2c-ali1535.o: Adapter registration failed, module not inserted.\n"); - ali1535_cleanup(); - return res; - } - ali1535_initialized++; - printk - ("i2c-ali1535.o: ALI1535 SMBus Controller detected and initialized\n"); - return 0; + return i2c_add_adapter(&ali1535_adapter); } -int __init ali1535_cleanup(void) +static void __devexit ali1535_remove(struct pci_dev *dev) { - int res; - if (ali1535_initialized >= 2) { - if ((res = i2c_del_adapter(&ali1535_adapter))) { - printk - ("i2c-ali1535.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - ali1535_initialized--; - } - if (ali1535_initialized >= 1) { - release_region(ali1535_smba, ALI1535_SMB_IOSIZE); - ali1535_initialized--; - } - return 0; + i2c_del_adapter(&ali1535_adapter); +} + + +static struct pci_driver ali1535_driver = { + .name = "ali1535 smbus", + .id_table = ali1535_ids, + .probe = ali1535_probe, + .remove = __devexit_p(ali1535_remove), +}; + +static int __init i2c_ali1535_init(void) +{ + printk("i2c-ali1535.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&ali1535_driver); +} + + +static void __exit i2c_ali1535_exit(void) +{ + pci_unregister_driver(&ali1535_driver); + release_region(ali1535_smba, ALI1535_SMB_IOSIZE); } #ifdef RLX EXPORT_SYMBOL(ali1535_smba); EXPORT_SYMBOL(ali1535_access); EXPORT_SYMBOL(i2c_ali1535_sem); -#else -EXPORT_NO_SYMBOLS; #endif -#ifdef MODULE - MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , " "Mark D. Studebaker and Dan Eaton "); MODULE_DESCRIPTION("ALI1535 SMBus driver"); +MODULE_LICENSE("GPL"); -int init_module(void) -{ - return i2c_ali1535_init(); -} - -int cleanup_module(void) -{ - return ali1535_cleanup(); -} - -#endif /* MODULE */ +module_init(i2c_ali1535_init); +module_exit(i2c_ali1535_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-ali15x3.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-ali15x3.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-ali15x3.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-ali15x3.c 2003-08-17 21:26:58.000000000 +0200 @@ -60,64 +60,62 @@ /* Note: we assume there can only be one ALI15X3, with one SMBus interface */ -#include +/* #define DEBUG 1 */ + #include #include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include /* ALI15X3 SMBus address offsets */ -#define SMBHSTSTS (0 + ali15x3_smba) -#define SMBHSTCNT (1 + ali15x3_smba) -#define SMBHSTSTART (2 + ali15x3_smba) -#define SMBHSTCMD (7 + ali15x3_smba) -#define SMBHSTADD (3 + ali15x3_smba) -#define SMBHSTDAT0 (4 + ali15x3_smba) -#define SMBHSTDAT1 (5 + ali15x3_smba) -#define SMBBLKDAT (6 + ali15x3_smba) +#define SMBHSTSTS (0 + ali15x3_smba) +#define SMBHSTCNT (1 + ali15x3_smba) +#define SMBHSTSTART (2 + ali15x3_smba) +#define SMBHSTCMD (7 + ali15x3_smba) +#define SMBHSTADD (3 + ali15x3_smba) +#define SMBHSTDAT0 (4 + ali15x3_smba) +#define SMBHSTDAT1 (5 + ali15x3_smba) +#define SMBBLKDAT (6 + ali15x3_smba) /* PCI Address Constants */ -#define SMBCOM 0x004 -#define SMBBA 0x014 -#define SMBATPC 0x05B /* used to unlock xxxBA registers */ -#define SMBHSTCFG 0x0E0 -#define SMBSLVC 0x0E1 -#define SMBCLK 0x0E2 -#define SMBREV 0x008 +#define SMBCOM 0x004 +#define SMBBA 0x014 +#define SMBATPC 0x05B /* used to unlock xxxBA registers */ +#define SMBHSTCFG 0x0E0 +#define SMBSLVC 0x0E1 +#define SMBCLK 0x0E2 +#define SMBREV 0x008 /* Other settings */ -#define MAX_TIMEOUT 200 /* times 1/100 sec */ -#define ALI15X3_SMB_IOSIZE 32 +#define MAX_TIMEOUT 200 /* times 1/100 sec */ +#define ALI15X3_SMB_IOSIZE 32 /* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB. We don't use these here. If the bases aren't set to some value we tell user to upgrade BIOS and we fail. */ -#define ALI15X3_SMB_DEFAULTBASE 0xE800 +#define ALI15X3_SMB_DEFAULTBASE 0xE800 /* ALI15X3 address lock bits */ -#define ALI15X3_LOCK 0x06 +#define ALI15X3_LOCK 0x06 /* ALI15X3 command constants */ -#define ALI15X3_ABORT 0x02 -#define ALI15X3_T_OUT 0x04 -#define ALI15X3_QUICK 0x00 -#define ALI15X3_BYTE 0x10 -#define ALI15X3_BYTE_DATA 0x20 -#define ALI15X3_WORD_DATA 0x30 -#define ALI15X3_BLOCK_DATA 0x40 -#define ALI15X3_BLOCK_CLR 0x80 +#define ALI15X3_ABORT 0x02 +#define ALI15X3_T_OUT 0x04 +#define ALI15X3_QUICK 0x00 +#define ALI15X3_BYTE 0x10 +#define ALI15X3_BYTE_DATA 0x20 +#define ALI15X3_WORD_DATA 0x30 +#define ALI15X3_BLOCK_DATA 0x40 +#define ALI15X3_BLOCK_CLR 0x80 /* ALI15X3 status register bits */ #define ALI15X3_STS_IDLE 0x04 @@ -136,119 +134,52 @@ MODULE_PARM(force_addr, "i"); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_ali15x3_init(void); -static int __init ali15x3_cleanup(void); -static int ali15x3_setup(void); -static s32 ali15x3_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data); -static void ali15x3_do_pause(unsigned int amount); -static int ali15x3_transaction(void); -static void ali15x3_inc(struct i2c_adapter *adapter); -static void ali15x3_dec(struct i2c_adapter *adapter); -static u32 ali15x3_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ ali15x3_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ ali15x3_func, -}; - -static struct i2c_adapter ali15x3_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3, - &smbus_algorithm, - NULL, - ali15x3_inc, - ali15x3_dec, - NULL, - NULL, -}; - -static int __initdata ali15x3_initialized; static unsigned short ali15x3_smba = 0; -static int locked=0; -/* Detect whether a ALI15X3 can be found, and initialize it, where necessary. - Note the differences between kernels with the old PCI BIOS interface and - newer kernels with the real PCI interface. In compat.h some things are - defined to make the transition easier. */ -int ali15x3_setup(void) +static int ali15x3_setup(struct pci_dev *ALI15X3_dev) { u16 a; unsigned char temp; - struct pci_dev *ALI15X3_dev; - - /* First check whether we can access PCI at all */ - if (pci_present() == 0) { - printk("i2c-ali15x3.o: Error: No PCI-bus found!\n"); - return -ENODEV; - } - - /* Look for the ALI15X3, M7101 device */ - ALI15X3_dev = NULL; - ALI15X3_dev = pci_find_device(PCI_VENDOR_ID_AL, - PCI_DEVICE_ID_AL_M7101, ALI15X3_dev); - if (ALI15X3_dev == NULL) { - printk("i2c-ali15x3.o: Error: Can't detect ali15x3!\n"); - return -ENODEV; - } - -/* Check the following things: - - SMB I/O address is initialized - - Device is enabled - - We can use the addresses -*/ - -/* Unlock the register. - The data sheet says that the address registers are read-only - if the lock bits are 1, but in fact the address registers - are zero unless you clear the lock bits. -*/ + /* Check the following things: + - SMB I/O address is initialized + - Device is enabled + - We can use the addresses + */ + + /* Unlock the register. + The data sheet says that the address registers are read-only + if the lock bits are 1, but in fact the address registers + are zero unless you clear the lock bits. + */ pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp); if (temp & ALI15X3_LOCK) { temp &= ~ALI15X3_LOCK; pci_write_config_byte(ALI15X3_dev, SMBATPC, temp); } -/* Determine the address of the SMBus area */ + /* Determine the address of the SMBus area */ pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba); ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1)); if (ali15x3_smba == 0 && force_addr == 0) { - printk - ("i2c-ali15x3.o: ALI15X3_smb region uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); + dev_err(ALI15X3_dev, "ALI15X3_smb region uninitialized " + "- upgrade BIOS or use force_addr=0xaddr\n"); return -ENODEV; } if(force_addr) ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1); - if (check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE)) { - printk - ("i2c-ali15x3.o: ALI15X3_smb region 0x%x already in use!\n", - ali15x3_smba); + if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) { + dev_err(ALI15X3_dev, + "ALI15X3_smb region 0x%x already in use!\n", + ali15x3_smba); return -ENODEV; } if(force_addr) { - printk("i2c-ali15x3.o: forcing ISA address 0x%04X\n", ali15x3_smba); + dev_info(ALI15X3_dev, "forcing ISA address 0x%04X\n", + ali15x3_smba); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba)) return -ENODEV; @@ -257,68 +188,60 @@ int ali15x3_setup(void) return -ENODEV; if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { /* make sure it works */ - printk("i2c-ali15x3.o: force address failed - not supported?\n"); + dev_err(ALI15X3_dev, + "force address failed - not supported?\n"); return -ENODEV; } } -/* check if whole device is enabled */ + /* check if whole device is enabled */ pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp); if ((temp & 1) == 0) { - printk("i2c-ali15x3: enabling SMBus device\n"); + dev_info(ALI15X3_dev, "enabling SMBus device\n"); pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01); } -/* Is SMB Host controller enabled? */ + /* Is SMB Host controller enabled? */ pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp); if ((temp & 1) == 0) { - printk("i2c-ali15x3: enabling SMBus controller\n"); + dev_info(ALI15X3_dev, "enabling SMBus controller\n"); pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01); } -/* set SMB clock to 74KHz as recommended in data sheet */ + /* set SMB clock to 74KHz as recommended in data sheet */ pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20); - /* Everything is happy, let's grab the memory and set things up. */ - request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb"); - -#ifdef DEBUG -/* - The interrupt routing for SMB is set up in register 0x77 in the - 1533 ISA Bridge device, NOT in the 7101 device. - Don't bother with finding the 1533 device and reading the register. - if ((....... & 0x0F) == 1) - printk("i2c-ali15x3.o: ALI15X3 using Interrupt 9 for SMBus.\n"); -*/ + /* + The interrupt routing for SMB is set up in register 0x77 in the + 1533 ISA Bridge device, NOT in the 7101 device. + Don't bother with finding the 1533 device and reading the register. + if ((....... & 0x0F) == 1) + dev_dbg(ALI15X3_dev, "ALI15X3 using Interrupt 9 for SMBus.\n"); + */ pci_read_config_byte(ALI15X3_dev, SMBREV, &temp); - printk("i2c-ali15x3.o: SMBREV = 0x%X\n", temp); - printk("i2c-ali15x3.o: ALI15X3_smba = 0x%X\n", ali15x3_smba); -#endif /* DEBUG */ + dev_dbg(ALI15X3_dev, "SMBREV = 0x%X\n", temp); + dev_dbg(ALI15X3_dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba); return 0; } - /* Internally used pause function */ -void ali15x3_do_pause(unsigned int amount) +static void ali15x3_do_pause(unsigned int amount) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(amount); } /* Another internally used function */ -int ali15x3_transaction(void) +static int ali15x3_transaction(struct i2c_adapter *adap) { int temp; int result = 0; int timeout = 0; -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); -#endif + dev_dbg(adap, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); /* get status */ temp = inb_p(SMBHSTSTS); @@ -326,43 +249,32 @@ int ali15x3_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ /* Check the busy bit first */ if (temp & ALI15X3_STS_BUSY) { -/* - If the host controller is still busy, it may have timed out in the previous transaction, - resulting in a "SMBus Timeout" printk. - I've tried the following to reset a stuck busy bit. - 1. Reset the controller with an ABORT command. - (this doesn't seem to clear the controller if an external device is hung) - 2. Reset the controller and the other SMBus devices with a T_OUT command. - (this clears the host busy bit if an external device is hung, - but it comes back upon a new access to a device) - 3. Disable and reenable the controller in SMBHSTCFG - Worst case, nothing seems to work except power reset. -*/ -/* Abort - reset the host controller */ -/* -#ifdef DEBUG - printk("i2c-ali15x3.o: Resetting host controller to clear busy condition\n",temp); -#endif - outb_p(ALI15X3_ABORT, SMBHSTCNT); - temp = inb_p(SMBHSTSTS); - if (temp & ALI15X3_STS_BUSY) { -*/ - -/* - Try resetting entire SMB bus, including other devices - - This may not work either - it clears the BUSY bit but - then the BUSY bit may come back on when you try and use the chip again. - If that's the case you are stuck. -*/ - printk - ("i2c-ali15x3.o: Resetting entire SMB Bus to clear busy condition (%02x)\n", - temp); + /* + If the host controller is still busy, it may have timed out in the + previous transaction, resulting in a "SMBus Timeout" Dev. + I've tried the following to reset a stuck busy bit. + 1. Reset the controller with an ABORT command. + (this doesn't seem to clear the controller if an external + device is hung) + 2. Reset the controller and the other SMBus devices with a + T_OUT command. (this clears the host busy bit if an + external device is hung, but it comes back upon a new access + to a device) + 3. Disable and reenable the controller in SMBHSTCFG + Worst case, nothing seems to work except power reset. + */ + /* Abort - reset the host controller */ + /* + Try resetting entire SMB bus, including other devices - + This may not work either - it clears the BUSY bit but + then the BUSY bit may come back on when you try and use the chip again. + If that's the case you are stuck. + */ + dev_info(adap, "Resetting entire SMB Bus to " + "clear busy condition (%02x)\n", temp); outb_p(ALI15X3_T_OUT, SMBHSTCNT); temp = inb_p(SMBHSTSTS); } -/* - } -*/ /* now check the error bits and the busy bit */ if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { @@ -373,9 +285,9 @@ int ali15x3_transaction(void) /* this is probably going to be correctable only by a power reset as one of the bits now appears to be stuck */ /* This may be a bus or device with electrical problems. */ - printk - ("i2c-ali15x3.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung\n", - temp); + dev_err(adap, "SMBus reset failed! (0x%02x) - " + "controller or device on bus is probably hung\n", + temp); return -1; } } else { @@ -399,48 +311,41 @@ int ali15x3_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; - printk("i2c-ali15x3.o: SMBus Timeout!\n"); + dev_err(adap, "SMBus Timeout!\n"); } if (temp & ALI15X3_STS_TERM) { result = -1; -#ifdef DEBUG - printk("i2c-ali15x3.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(adap, "Error: Failed bus transaction\n"); } -/* - Unfortunately the ALI SMB controller maps "no response" and "bus collision" - into a single bit. No reponse is the usual case so don't - do a printk. - This means that bus collisions go unreported. -*/ + /* + Unfortunately the ALI SMB controller maps "no response" and "bus + collision" into a single bit. No reponse is the usual case so don't + do a printk. + This means that bus collisions go unreported. + */ if (temp & ALI15X3_STS_COLL) { result = -1; -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Error: no response or bus collision ADD=%02x\n", - inb_p(SMBHSTADD)); -#endif + dev_dbg(adap, + "Error: no response or bus collision ADD=%02x\n", + inb_p(SMBHSTADD)); } -/* haven't ever seen this */ + /* haven't ever seen this */ if (temp & ALI15X3_STS_DEV) { result = -1; - printk("i2c-ali15x3.o: Error: device error\n"); + dev_err(adap, "Error: device error\n"); } -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); -#endif + dev_dbg(adap, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); return result; } /* Return -1 on error. */ -s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, +static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { @@ -448,9 +353,9 @@ s32 ali15x3_access(struct i2c_adapter * int temp; int timeout; -/* clear all the bits (clear-on-write) */ + /* clear all the bits (clear-on-write) */ outb_p(0xFF, SMBHSTSTS); -/* make sure SMBus is idle */ + /* make sure SMBus is idle */ temp = inb_p(SMBHSTSTS); for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); @@ -459,15 +364,10 @@ s32 ali15x3_access(struct i2c_adapter * temp = inb_p(SMBHSTSTS); } if (timeout >= MAX_TIMEOUT) { - printk("i2c-ali15x3.o: Idle wait Timeout! STS=0x%02x\n", - temp); + dev_err(adap, "Idle wait Timeout! STS=0x%02x\n", temp); } switch (size) { - case I2C_SMBUS_PROC_CALL: - printk - ("i2c-ali15x3.o: I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); @@ -513,17 +413,22 @@ s32 ali15x3_access(struct i2c_adapter * data->block[0] = len; } outb_p(len, SMBHSTDAT0); - outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); /* Reset SMBBLKDAT */ + /* Reset SMBBLKDAT */ + outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } size = ALI15X3_BLOCK_DATA; break; + default: + printk + (KERN_WARNING "i2c-ali15x3.o: Unsupported transaction %d\n", size); + return -1; } outb_p(size, SMBHSTCNT); /* output command */ - if (ali15x3_transaction()) /* Error in transaction */ + if (ali15x3_transaction(adap)) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK)) @@ -545,106 +450,91 @@ s32 ali15x3_access(struct i2c_adapter * if (len > 32) len = 32; data->block[0] = len; - outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); /* Reset SMBBLKDAT */ + /* Reset SMBBLKDAT */ + outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); for (i = 1; i <= data->block[0]; i++) { data->block[i] = inb_p(SMBBLKDAT); -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Blk: len=%d, i=%d, data=%02x\n", - len, i, data->block[i]); -#endif /* DEBUG */ + dev_dbg(adap, "Blk: len=%d, i=%d, data=%02x\n", + len, i, data->block[i]); } break; } return 0; } -void ali15x3_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void ali15x3_dec(struct i2c_adapter *adapter) -{ - - MOD_DEC_USE_COUNT; -} - -u32 ali15x3_func(struct i2c_adapter *adapter) +static u32 ali15x3_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; } -int __init i2c_ali15x3_init(void) +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = ali15x3_access, + .functionality = ali15x3_func, +}; + +static struct i2c_adapter ali15x3_adapter = { + .owner = THIS_MODULE, + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3, + .algo = &smbus_algorithm, + .name = "unset", +}; + +static struct pci_device_id ali15x3_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_AL, + .device = PCI_DEVICE_ID_AL_M7101, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int res; - printk("i2c-ali15x3.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (ali15x3_initialized) { - printk - ("i2c-ali15x3.o: Oops, ali15x3_init called a second time!\n"); - return -EBUSY; + if (ali15x3_setup(dev)) { + dev_err(dev, + "ALI15X3 not detected, module not inserted.\n"); + return -ENODEV; } -#endif - ali15x3_initialized = 0; - if ((res = ali15x3_setup())) { - printk - ("i2c-ali15x3.o: ALI15X3 not detected, module not inserted.\n"); - ali15x3_cleanup(); - return res; - } - ali15x3_initialized++; - sprintf(ali15x3_adapter.name, "SMBus ALI15X3 adapter at %04x", - ali15x3_smba); - if ((res = i2c_add_adapter(&ali15x3_adapter))) { - printk - ("i2c-ali15x3.o: Adapter registration failed, module not inserted.\n"); - ali15x3_cleanup(); - return res; - } - ali15x3_initialized++; - printk - ("i2c-ali15x3.o: ALI15X3 SMBus Controller detected and initialized\n"); - return 0; + + snprintf(ali15x3_adapter.name, 32, + "SMBus ALI15X3 adapter at %04x", ali15x3_smba); + return i2c_add_adapter(&ali15x3_adapter); } -int __init ali15x3_cleanup(void) +static void __devexit ali15x3_remove(struct pci_dev *dev) { - int res; - if (ali15x3_initialized >= 2) { - if ((res = i2c_del_adapter(&ali15x3_adapter))) { - printk - ("i2c-ali15x3.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - ali15x3_initialized--; - } - if (ali15x3_initialized >= 1) { - release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); - ali15x3_initialized--; - } - return 0; + i2c_del_adapter(&ali15x3_adapter); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , and Mark D. Studebaker "); -MODULE_DESCRIPTION("ALI15X3 SMBus driver"); +static struct pci_driver ali15x3_driver = { + .name = "ali15x3 smbus", + .id_table = ali15x3_ids, + .probe = ali15x3_probe, + .remove = __devexit_p(ali15x3_remove), +}; -int init_module(void) +static int __init i2c_ali15x3_init(void) { - return i2c_ali15x3_init(); + printk("i2c-ali15x3.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&ali15x3_driver); } -int cleanup_module(void) +static void __exit i2c_ali15x3_exit(void) { - return ali15x3_cleanup(); + pci_unregister_driver(&ali15x3_driver); + release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); } -#endif /* MODULE */ +MODULE_AUTHOR ("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark D. Studebaker "); +MODULE_DESCRIPTION("ALI15X3 SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_ali15x3_init); +module_exit(i2c_ali15x3_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-amd756.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-amd756.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-amd756.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-amd756.c 2003-08-17 21:26:58.000000000 +0200 @@ -27,6 +27,7 @@ /* 2002-04-08: Added nForce support. (Csaba Halasz) 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil) + 2002-12-28: Rewritten into something that resembles a Linux driver (hch) */ /* @@ -34,65 +35,33 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include #include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifndef PCI_DEVICE_ID_AMD_756 -#define PCI_DEVICE_ID_AMD_756 0x740B -#endif -#ifndef PCI_DEVICE_ID_AMD_766 -#define PCI_DEVICE_ID_AMD_766 0x7413 -#endif -#ifndef PCI_DEVICE_ID_AMD_768_SMBUS -#define PCI_DEVICE_ID_AMD_768_SMBUS 0x7443 -#endif -#ifndef PCI_DEVICE_ID_AMD_8111_SMBUS -#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746B -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS -#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01B4 -#endif - -struct sd { - const unsigned short vendor; - const unsigned short device; - const unsigned short function; - const char* name; - int amdsetup:1; -}; - -static struct sd supported[] = { - {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_756, 3, "AMD756", 1}, - {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_766, 3, "AMD766", 1}, - {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_768_SMBUS, 3, "AMD768", 1}, - {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, 3, "AMD8111", 1}, - {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS, 1, "nVidia nForce", 0}, - {0, 0, 0} -}; +#define DRV_NAME "i2c-amd756" /* AMD756 SMBus address offsets */ #define SMB_ADDR_OFFSET 0xE0 #define SMB_IOSIZE 16 -#define SMB_GLOBAL_STATUS (0x0 + amd756_smba) -#define SMB_GLOBAL_ENABLE (0x2 + amd756_smba) -#define SMB_HOST_ADDRESS (0x4 + amd756_smba) -#define SMB_HOST_DATA (0x6 + amd756_smba) -#define SMB_HOST_COMMAND (0x8 + amd756_smba) -#define SMB_HOST_BLOCK_DATA (0x9 + amd756_smba) -#define SMB_HAS_DATA (0xA + amd756_smba) -#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_smba) -#define SMB_HAS_HOST_ADDRESS (0xE + amd756_smba) -#define SMB_SNOOP_ADDRESS (0xF + amd756_smba) +#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport) +#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport) +#define SMB_HOST_ADDRESS (0x4 + amd756_ioport) +#define SMB_HOST_DATA (0x6 + amd756_ioport) +#define SMB_HOST_COMMAND (0x8 + amd756_ioport) +#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport) +#define SMB_HAS_DATA (0xA + amd756_ioport) +#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport) +#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport) +#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport) /* PCI Address Constants */ @@ -117,128 +86,8 @@ static struct sd supported[] = { #define AMD756_PROCESS_CALL 0x04 #define AMD756_BLOCK_DATA 0x05 -/* insmod parameters */ -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_amd756_init(void); -static int __init amd756_cleanup(void); -static int amd756_setup(void); -static s32 amd756_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data); -static void amd756_do_pause(unsigned int amount); -static void amd756_abort(void); -static int amd756_transaction(void); -static void amd756_inc(struct i2c_adapter *adapter); -static void amd756_dec(struct i2c_adapter *adapter); -static u32 amd756_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ amd756_access, - /* slave;_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ amd756_func, -}; - -static struct i2c_adapter amd756_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, - &smbus_algorithm, - NULL, - amd756_inc, - amd756_dec, - NULL, - NULL, -}; - -static int __initdata amd756_initialized; -static struct sd *amd756_sd = NULL; -static unsigned short amd756_smba = 0; - -int amd756_setup(void) -{ - unsigned char temp; - struct sd *currdev; - struct pci_dev *AMD756_dev = NULL; - - if (pci_present() == 0) { - return -ENODEV; - } - - /* Look for a supported chip */ - for(currdev = supported; currdev->vendor; ) { - AMD756_dev = pci_find_device(currdev->vendor, - currdev->device, AMD756_dev); - if (AMD756_dev != NULL) { - if (PCI_FUNC(AMD756_dev->devfn) == currdev->function) - break; - } else { - currdev++; - } - } - - if (AMD756_dev == NULL) { - printk - ("i2c-amd756.o: Error: No AMD756 or compatible device detected!\n"); - return -ENODEV; - } - printk(KERN_INFO "i2c-amd756.o: Found %s SMBus controller.\n", currdev->name); - - if (currdev->amdsetup) - { - pci_read_config_byte(AMD756_dev, SMBGCFG, &temp); - if ((temp & 128) == 0) { - printk("i2c-amd756.o: Error: SMBus controller I/O not enabled!\n"); - return -ENODEV; - } - - /* Determine the address of the SMBus areas */ - /* Technically it is a dword but... */ - pci_read_config_word(AMD756_dev, SMBBA, &amd756_smba); - amd756_smba &= 0xff00; - amd756_smba += SMB_ADDR_OFFSET; - } else { - pci_read_config_word(AMD756_dev, SMBBANFORCE, &amd756_smba); - amd756_smba &= 0xfffc; - } - if(amd756_smba == 0) { - printk(KERN_ERR "i2c-amd756.o: Error: SMB base address uninitialized\n"); - return -ENODEV; - } - if (check_region(amd756_smba, SMB_IOSIZE)) { - printk - ("i2c-amd756.o: SMB region 0x%x already in use!\n", - amd756_smba); - return -ENODEV; - } - - /* Everything is happy, let's grab the memory and set things up. */ - request_region(amd756_smba, SMB_IOSIZE, "amd756-smbus"); - -#ifdef DEBUG - pci_read_config_byte(AMD756_dev, SMBREV, &temp); - printk("i2c-amd756.o: SMBREV = 0x%X\n", temp); - printk("i2c-amd756.o: AMD756_smba = 0x%X\n", amd756_smba); -#endif /* DEBUG */ - - /* store struct sd * for future reference */ - amd756_sd = currdev; - - return 0; -} +static unsigned short amd756_ioport = 0; /* SMBUS event = I/O 28-29 bit 11 @@ -247,7 +96,7 @@ int amd756_setup(void) */ /* Internally used pause function */ -void amd756_do_pause(unsigned int amount) +static void amd756_do_pause(unsigned int amount) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(amount); @@ -268,33 +117,21 @@ void amd756_do_pause(unsigned int amount #define GE_HOST_STC (1 << 3) #define GE_ABORT (1 << 5) -void amd756_abort(void) -{ - printk("i2c-amd756.o: Sending abort.\n"); - outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); - amd756_do_pause(100); - outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); -} -int amd756_transaction(void) +static int amd756_transaction(void) { int temp; int result = 0; int timeout = 0; -#ifdef DEBUG - printk - ("i2c-amd756.o: Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", - inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), - inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); -#endif + pr_debug(DRV_NAME + ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) { -#ifdef DEBUG - printk - ("i2c-amd756.o: SMBus busy (%04x). Waiting... \n", temp); -#endif + pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp); do { amd756_do_pause(1); temp = inw_p(SMB_GLOBAL_STATUS); @@ -302,9 +139,8 @@ int amd756_transaction(void) (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { - printk("i2c-amd756.o: Busy wait timeout! (%04x)\n", temp); - amd756_abort(); - return -1; + pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp); + goto abort; } timeout = 0; } @@ -320,66 +156,63 @@ int amd756_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { - printk("i2c-amd756.o: Completion timeout!\n"); - amd756_abort (); - return -1; + pr_debug(DRV_NAME ": Completion timeout!\n"); + goto abort; } if (temp & GS_PRERR_STS) { result = -1; -#ifdef DEBUG - printk("i2c-amd756.o: SMBus Protocol error (no response)!\n"); -#endif + pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n"); } if (temp & GS_COL_STS) { result = -1; - printk("i2c-amd756.o: SMBus collision!\n"); + printk(KERN_WARNING DRV_NAME " SMBus collision!\n"); } if (temp & GS_TO_STS) { result = -1; -#ifdef DEBUG - printk("i2c-amd756.o: SMBus protocol timeout!\n"); -#endif - } -#ifdef DEBUG - if (temp & GS_HCYC_STS) { - printk("i2c-amd756.o: SMBus protocol success!\n"); + pr_debug(DRV_NAME ": SMBus protocol timeout!\n"); } -#endif + + if (temp & GS_HCYC_STS) + pr_debug(DRV_NAME " SMBus protocol success!\n"); outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); #ifdef DEBUG if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) { - printk - ("i2c-amd756.o: Failed reset at end of transaction (%04x)\n", - temp); + pr_debug(DRV_NAME + ": Failed reset at end of transaction (%04x)\n", temp); } - printk - ("i2c-amd756.o: Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", - inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), - inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); + + pr_debug(DRV_NAME + ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); #endif return result; + + abort: + printk(KERN_WARNING DRV_NAME ": Sending abort.\n"); + outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); + amd756_do_pause(100); + outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); + return -1; } /* Return -1 on error. */ -s32 amd756_access(struct i2c_adapter * adap, u16 addr, + +static s32 amd756_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { int i, len; - /** TODO: Should I supporte the 10-bit transfers? */ + /** TODO: Should I supporte the 10-bit transfers? */ switch (size) { - case I2C_SMBUS_PROC_CALL: - printk - ("i2c-amd756.o: I2C_SMBUS_PROC_CALL not supported!\n"); - /* TODO: Well... It is supported, I'm just not sure what to do here... */ - return -1; + /* TODO: proc call is supported, I'm just not sure what to do here... */ case I2C_SMBUS_QUICK: outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMB_HOST_ADDRESS); @@ -427,6 +260,10 @@ s32 amd756_access(struct i2c_adapter * a } size = AMD756_BLOCK_DATA; break; + default: + printk + (KERN_WARNING "i2c-amd756.o: Unsupported transaction %d\n", size); + return -1; } /* How about enabling interrupts... */ @@ -462,95 +299,131 @@ s32 amd756_access(struct i2c_adapter * a return 0; } -void amd756_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void amd756_dec(struct i2c_adapter *adapter) -{ - - MOD_DEC_USE_COUNT; -} - -u32 amd756_func(struct i2c_adapter *adapter) +static u32 amd756_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL; } -int __init i2c_amd756_init(void) +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = amd756_access, + .functionality = amd756_func, +}; + +static struct i2c_adapter amd756_adapter = { + .owner = THIS_MODULE, + .name = "unset", + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, + .algo = &smbus_algorithm, +}; + +enum chiptype { AMD756, AMD766, AMD768, NFORCE }; + +static struct pci_device_id amd756_ids[] __devinitdata = { + {PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 }, + {PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 }, + {PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 }, + {PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE }, + { 0, } +}; + +static int __devinit amd756_probe(struct pci_dev *pdev, + const struct pci_device_id *id) { - int res; - printk("i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (amd756_initialized) { - printk - ("i2c-amd756.o: Oops, amd756_init called a second time!\n"); - return -EBUSY; + int nforce = (id->driver_data == NFORCE), error; + u8 temp; + + if (amd756_ioport) { + printk(KERN_ERR DRV_NAME ": Only one device supported. " + "(you have a strange motherboard, btw..)\n"); + return -ENODEV; + } + + if (nforce) { + if (PCI_FUNC(pdev->devfn) != 1) + return -ENODEV; + + pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport); + amd756_ioport &= 0xfffc; + } else { /* amd */ + if (PCI_FUNC(pdev->devfn) != 3) + return -ENODEV; + + pci_read_config_byte(pdev, SMBGCFG, &temp); + if ((temp & 128) == 0) { + printk(KERN_ERR DRV_NAME + ": Error: SMBus controller I/O not enabled!\n"); + return -ENODEV; + } + + /* Determine the address of the SMBus areas */ + /* Technically it is a dword but... */ + pci_read_config_word(pdev, SMBBA, &amd756_ioport); + amd756_ioport &= 0xff00; + amd756_ioport += SMB_ADDR_OFFSET; } + + if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { + printk(KERN_ERR DRV_NAME + ": SMB region 0x%x already in use!\n", amd756_ioport); + return -ENODEV; + } + +#ifdef DEBUG + pci_read_config_byte(pdev, SMBREV, &temp); + printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp); + printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport); #endif - amd756_initialized = 0; - if ((res = amd756_setup())) { - printk - ("i2c-amd756.o: AMD756 or compatible device not detected, module not inserted.\n"); - amd756_cleanup(); - return res; - } - amd756_initialized++; - sprintf(amd756_adapter.name, "SMBus %s adapter at %04x", - amd756_sd->name, amd756_smba); - if ((res = i2c_add_adapter(&amd756_adapter))) { - printk - ("i2c-amd756.o: Adapter registration failed, module not inserted.\n"); - amd756_cleanup(); - return res; - } - amd756_initialized++; - printk("i2c-amd756.o: %s bus detected and initialized\n", - amd756_sd->name); - return 0; -} -int __init amd756_cleanup(void) -{ - int res; - if (amd756_initialized >= 2) { - if ((res = i2c_del_adapter(&amd756_adapter))) { - printk - ("i2c-amd756.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - amd756_initialized--; - } - if (amd756_initialized >= 1) { - release_region(amd756_smba, SMB_IOSIZE); - amd756_initialized--; + sprintf(amd756_adapter.name, + "SMBus AMD75x adapter at %04x", amd756_ioport); + + error = i2c_add_adapter(&amd756_adapter); + if (error) { + printk(KERN_ERR DRV_NAME + ": Adapter registration failed, module not inserted.\n"); + goto out_err; } + return 0; -} -EXPORT_NO_SYMBOLS; + out_err: + release_region(amd756_ioport, SMB_IOSIZE); + return error; +} -#ifdef MODULE -MODULE_AUTHOR("Merlin Hughes "); -MODULE_DESCRIPTION("AMD756/766/768/nVidia nForce SMBus driver"); +static void __devexit amd756_remove(struct pci_dev *dev) +{ + i2c_del_adapter(&amd756_adapter); +} -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif +static struct pci_driver amd756_driver = { + .name = "amd75x smbus", + .id_table = amd756_ids, + .probe = amd756_probe, + .remove = __devexit_p(amd756_remove), +}; -int init_module(void) +static int __init i2c_amd756_init(void) { - return i2c_amd756_init(); + printk(KERN_INFO "i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&amd756_driver); } -int cleanup_module(void) + +static void __exit i2c_amd756_exit(void) { - return amd756_cleanup(); + pci_unregister_driver(&amd756_driver); + release_region(amd756_ioport, SMB_IOSIZE); } -#endif /* MODULE */ +MODULE_AUTHOR("Merlin Hughes "); +MODULE_DESCRIPTION("AMD756/766/768/nVidia nForce SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_amd756_init) +module_exit(i2c_amd756_exit) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-amd8111.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-amd8111.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-amd8111.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-amd8111.c 2003-08-17 21:26:58.000000000 +0200 @@ -8,10 +8,8 @@ * the Free Software Foundation version 2. */ -#include #include #include -#include #include #include #include @@ -19,62 +17,15 @@ #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" #ifndef I2C_HW_SMBUS_AMD8111 #error Your i2c is too old - i2c-2.7.0 or greater required! #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) -#include -#define MAX_PCI_DEVS 8 -static struct pci_dev *amd8111_devs[MAX_PCI_DEVS] = { NULL, /* ... */ }; -static void *amd8111_drvdata[MAX_PCI_DEVS]; -static int amd8111_devcnt = 0; - -#define min_t(t, x, y) (((x)<(y))?(x):(y)) -#define __devinit -#define __devexit -#define __devinitdata -#define __devexit_p(x) x -struct pci_device_id { - unsigned int vendor, device; - unsigned int subvendor, subdevice; - unsigned int class, class_mask; - unsigned long driver_data; -}; -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; - int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); - void (*remove)(struct pci_dev *dev); -}; -#define PCI_ANY_ID 0xffff - -static void *pci_get_drvdata(struct pci_dev *dev) -{ - int i; - for (i = 0; i < amd8111_devcnt; i++) - if (amd8111_devs[i] == dev) - return amd8111_drvdata[i]; - return NULL; -} - -static void pci_set_drvdata(struct pci_dev *dev, void *driver_data) -{ - int i; - for (i = 0; i < amd8111_devcnt; i++) - if (amd8111_devs[i] == dev) - amd8111_drvdata[i] = driver_data; -} - -#endif - -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_AUTHOR ("Vojtech Pavlik "); MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver"); @@ -369,15 +320,6 @@ s32 amd8111_access(struct i2c_adapter * return 0; } -void amd8111_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void amd8111_dec(struct i2c_adapter *adapter) -{ - MOD_DEC_USE_COUNT; -} u32 amd8111_func(struct i2c_adapter *adapter) { @@ -394,14 +336,21 @@ static struct i2c_algorithm smbus_algori .functionality = amd8111_func, }; + +static struct pci_device_id amd8111_ids[] __devinitdata = { + { 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct amd_smbus *smbus; + int error; if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) return -1; - if (!(smbus = kmalloc(sizeof(struct amd_smbus), GFP_KERNEL))) + if (!(smbus = (void*)kmalloc(sizeof(struct amd_smbus), GFP_KERNEL))) return -1; memset(smbus, 0, sizeof(struct amd_smbus)); @@ -410,27 +359,19 @@ static int __devinit amd8111_probe(struc smbus->base = pci_resource_start(dev, 0); smbus->size = pci_resource_len(dev, 0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,14) if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) { kfree(smbus); return -1; } -#else - if (check_region(smbus->base, smbus->size) < 0) { - kfree(smbus); - return -1; - } - request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0"); -#endif + smbus->adapter.owner = THIS_MODULE; sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base); smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; - smbus->adapter.inc_use = amd8111_inc; - smbus->adapter.dec_use = amd8111_dec; - if (i2c_add_adapter(&smbus->adapter)) { + error = i2c_add_adapter(&smbus->adapter); + if (error) { printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n"); release_region(smbus->base, smbus->size); kfree(smbus); @@ -439,83 +380,37 @@ static int __devinit amd8111_probe(struc pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at %#x\n", smbus->base); -#else - printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at pci%s\n", dev->slot_name); -#endif return 0; } + static void __devexit amd8111_remove(struct pci_dev *dev) { - struct amd_smbus *smbus = pci_get_drvdata(dev); - if (i2c_del_adapter(&smbus->adapter)) { - printk(KERN_WARNING "i2c-amd8111.c: Failed to unregister adapter.\n"); - return; - } + struct amd_smbus *smbus = (void*) pci_get_drvdata(dev); + i2c_del_adapter(&smbus->adapter); release_region(smbus->base, smbus->size); kfree(smbus); } -static struct pci_device_id amd8111_id_table[] __devinitdata = -{{ 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0 }}; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - -int i2c_amd8111_init(void) -{ - struct pci_dev *pci; - struct pci_device_id *id; - int found = 0; - - for (id = amd8111_id_table; id->vendor; id++) { - pci = NULL; - while ((pci = pci_find_device(id->vendor, id->device, pci))) - if (amd8111_devcnt < 8 && !amd8111_probe(pci, id)) - amd8111_devs[amd8111_devcnt++] = pci; - } - - return found ? 0 : -ENODEV; -} - -int __init amd8111_init(void) -{ - return i2c_amd8111_init(); -} - -void __exit amd8111_exit(void) -{ - int i; - for (i = 0; i < amd8111_devcnt; i++) - amd8111_remove(amd8111_devs[i]); -} - -#else - static struct pci_driver amd8111_driver = { - .name = "amd8111 smbus 2.0", - .id_table = amd8111_id_table, - .probe = amd8111_probe, - .remove = __devexit_p(amd8111_remove), + .name = "amd8111 smbus 2.0", + .id_table = amd8111_ids, + .probe = amd8111_probe, + .remove = __devexit_p(amd8111_remove), }; -int __init amd8111_init(void) +static int __init i2c_amd8111_init(void) { + printk(KERN_INFO "i2c-amd8111.o version %s (%s)\n", LM_VERSION, LM_DATE); return pci_module_init(&amd8111_driver); } -void __exit amd8111_exit(void) + +static void __exit i2c_amd8111_exit(void) { pci_unregister_driver(&amd8111_driver); } - -MODULE_DEVICE_TABLE(pci, amd8111_id_table); - -#endif - -module_init(amd8111_init); -module_exit(amd8111_exit); - +module_init(i2c_amd8111_init); +module_exit(i2c_amd8111_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-core.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-core.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-core.c 2003-05-03 01:58:36.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-core.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,55 +21,27 @@ All SMBus-related things are written by Frodo Looijaard SMBus 2.0 support by Mark Studebaker */ -/* $Id: i2c-core.c,v 1.90 2002/11/23 20:58:13 mds Exp $ */ +/* i2c-core.c,v 1.91.2.2 2003/01/21 10:00:19 kmalkki Exp */ #include #include #include #include #include -#include -#include - -/* ----- compatibility stuff ----------------------------------------------- */ - -#include #include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - +#include #include /* ----- global defines ---------------------------------------------------- */ -/* exclusive access to the bus */ -#define I2C_LOCK(adap) down(&adap->lock) -#define I2C_UNLOCK(adap) up(&adap->lock) - -#define ADAP_LOCK() down(&adap_lock) -#define ADAP_UNLOCK() up(&adap_lock) - -#define DRV_LOCK() down(&driver_lock) -#define DRV_UNLOCK() up(&driver_lock) - #define DEB(x) if (i2c_debug>=1) x; #define DEB2(x) if (i2c_debug>=2) x; /* ----- global variables -------------------------------------------------- */ -/**** lock for writing to global variables: the adapter & driver list */ -struct semaphore adap_lock; -struct semaphore driver_lock; - -/**** adapter list */ +DECLARE_MUTEX(core_lists); static struct i2c_adapter *adapters[I2C_ADAP_MAX]; -static int adap_count; - -/**** drivers list */ static struct i2c_driver *drivers[I2C_DRIVER_MAX]; -static int driver_count; /**** debug level */ static int i2c_debug; @@ -80,14 +52,6 @@ static int i2c_debug; */ #ifdef CONFIG_PROC_FS - -static int i2cproc_init(void); -static int i2cproc_cleanup(void); - -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) -static void monitor_bus_i2c(struct inode *inode, int fill); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, loff_t *ppos); static int read_bus_i2c(char *buf, char **start, off_t offset, int len, @@ -99,18 +63,8 @@ static struct file_operations i2cproc_op .read = i2cproc_bus_read, }; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)) -static struct inode_operations i2cproc_inode_operations = { - &i2cproc_operations -}; -#endif - -static int i2cproc_initialized = 0; - -#else /* undef CONFIG_PROC_FS */ - -#define i2cproc_init() 0 -#define i2cproc_cleanup() 0 +static int i2cproc_register(struct i2c_adapter *adap, int bus); +static void i2cproc_remove(int bus); #endif /* CONFIG_PROC_FS */ @@ -127,9 +81,9 @@ static int i2cproc_initialized = 0; */ int i2c_add_adapter(struct i2c_adapter *adap) { - int i,j,res; + int i,j,res = 0; - ADAP_LOCK(); + down(&core_lists); for (i = 0; i < I2C_ADAP_MAX; i++) if (NULL == adapters[i]) break; @@ -140,76 +94,39 @@ int i2c_add_adapter(struct i2c_adapter * res = -ENOMEM; goto ERROR0; } + +#ifdef CONFIG_PROC_FS + res = i2cproc_register(adap, i); + if (res<0) + goto ERROR0; +#endif /* def CONFIG_PROC_FS */ adapters[i] = adap; - adap_count++; - ADAP_UNLOCK(); /* init data types */ - init_MUTEX(&adap->lock); - -#ifdef CONFIG_PROC_FS - - if (i2cproc_initialized) { - char name[8]; - struct proc_dir_entry *proc_entry; - - sprintf(name,"i2c-%d", i); - - proc_entry = create_proc_entry(name,0,proc_bus); - if (! proc_entry) { - printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", - name); - res = -ENOENT; - goto ERROR1; - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,48)) - proc_entry->proc_fops = &i2cproc_operations; -#else - proc_entry->ops = &i2cproc_inode_operations; -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) - proc_entry->owner = THIS_MODULE; -#else - proc_entry->fill_inode = &monitor_bus_i2c; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - adap->inode = proc_entry->low_ino; - } - -#endif /* def CONFIG_PROC_FS */ + init_MUTEX(&adap->bus); + init_MUTEX(&adap->list); /* inform drivers of new adapters */ - DRV_LOCK(); for (j=0;jflags&(I2C_DF_NOTIFY|I2C_DF_DUMMY))) /* We ignore the return code; if it fails, too bad */ drivers[j]->attach_adapter(adap); - DRV_UNLOCK(); DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", adap->name,i)); - - return 0; - - -ERROR1: - ADAP_LOCK(); - adapters[i] = NULL; - adap_count--; -ERROR0: - ADAP_UNLOCK(); + ERROR0: + up(&core_lists); return res; } int i2c_del_adapter(struct i2c_adapter *adap) { - int i,j,res; - - ADAP_LOCK(); + int i,j, res=0; + down(&core_lists); for (i = 0; i < I2C_ADAP_MAX; i++) if (adap == adapters[i]) break; @@ -225,17 +142,14 @@ int i2c_del_adapter(struct i2c_adapter * * *detach* it! Of course, each dummy driver should know about * this or hell will break loose... */ - DRV_LOCK(); for (j = 0; j < I2C_DRIVER_MAX; j++) if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) if ((res = drivers[j]->attach_adapter(adap))) { printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " "while detaching driver %s: driver not " "detached!",adap->name,drivers[j]->name); - goto ERROR1; + goto ERROR0; } - DRV_UNLOCK(); - /* detach any active clients. This must be done first, because * it can fail; in which case we give upp. */ @@ -254,26 +168,15 @@ int i2c_del_adapter(struct i2c_adapter * goto ERROR0; } } + #ifdef CONFIG_PROC_FS - if (i2cproc_initialized) { - char name[8]; - sprintf(name,"i2c-%d", i); - remove_proc_entry(name,proc_bus); - } + i2cproc_remove(i); #endif /* def CONFIG_PROC_FS */ adapters[i] = NULL; - adap_count--; - - ADAP_UNLOCK(); - DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); - return 0; - -ERROR0: - ADAP_UNLOCK(); - return res; -ERROR1: - DRV_UNLOCK(); + DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); + ERROR0: + up(&core_lists); return res; } @@ -287,7 +190,8 @@ ERROR1: int i2c_add_driver(struct i2c_driver *driver) { int i; - DRV_LOCK(); + + down(&core_lists); for (i = 0; i < I2C_DRIVER_MAX; i++) if (NULL == drivers[i]) break; @@ -296,19 +200,12 @@ int i2c_add_driver(struct i2c_driver *dr " i2c-core.o: register_driver(%s) " "- enlarge I2C_DRIVER_MAX.\n", driver->name); - DRV_UNLOCK(); + up(&core_lists); return -ENOMEM; } - - drivers[i] = driver; - driver_count++; - - DRV_UNLOCK(); /* driver was successfully added */ - + drivers[i] = driver; DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); - ADAP_LOCK(); - /* now look for instances of driver on our adapters */ if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) { @@ -317,15 +214,15 @@ int i2c_add_driver(struct i2c_driver *dr /* Ignore errors */ driver->attach_adapter(adapters[i]); } - ADAP_UNLOCK(); + up(&core_lists); return 0; } int i2c_del_driver(struct i2c_driver *driver) { - int i,j,k,res; + int i,j,k,res = 0; - DRV_LOCK(); + down(&core_lists); for (i = 0; i < I2C_DRIVER_MAX; i++) if (driver == drivers[i]) break; @@ -333,7 +230,7 @@ int i2c_del_driver(struct i2c_driver *dr printk(KERN_WARNING " i2c-core.o: unregister_driver: " "[%s] not found\n", driver->name); - DRV_UNLOCK(); + up(&core_lists); return -ENODEV; } /* Have a look at each adapter, if clients of this driver are still @@ -345,7 +242,6 @@ int i2c_del_driver(struct i2c_driver *dr * invalid operation might (will!) result, when using stale client * pointers. */ - ADAP_LOCK(); /* should be moved inside the if statement... */ for (k=0;kname, adap->name); - ADAP_UNLOCK(); - return res; + goto ERROR0; } } else { for (j=0;jname, client->addr, adap->name); - ADAP_UNLOCK(); - return res; + goto ERROR0; } } } } } - ADAP_UNLOCK(); drivers[i] = NULL; - driver_count--; - DRV_UNLOCK(); - DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); - return 0; + + ERROR0: + up(&core_lists); + return res; } -int i2c_check_addr (struct i2c_adapter *adapter, int addr) +static int __i2c_check_addr (struct i2c_adapter *adapter, int addr) { int i; for (i = 0; i < I2C_CLIENT_MAX ; i++) if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) return -EBUSY; + + return 0; +} + +int i2c_check_addr (struct i2c_adapter *adapter, int addr) +{ + int rval; + + down(&adapter->list); + rval = __i2c_check_addr(adapter, addr); + up(&adapter->list); + return 0; } @@ -419,6 +326,7 @@ int i2c_attach_client(struct i2c_client if (i2c_check_addr(client->adapter,client->addr)) return -EBUSY; + down(&adapter->list); for (i = 0; i < I2C_CLIENT_MAX; i++) if (NULL == adapter->clients[i]) break; @@ -426,11 +334,11 @@ int i2c_attach_client(struct i2c_client printk(KERN_WARNING " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", client->name); + up(&adapter->list); return -ENOMEM; } - adapter->clients[i] = client; - adapter->client_count++; + up(&adapter->list); if (adapter->client_register) if (adapter->client_register(client)) @@ -452,16 +360,6 @@ int i2c_detach_client(struct i2c_client struct i2c_adapter *adapter = client->adapter; int i,res; - for (i = 0; i < I2C_CLIENT_MAX; i++) - if (client == adapter->clients[i]) - break; - if (I2C_CLIENT_MAX == i) { - printk(KERN_WARNING " i2c-core.o: unregister_client " - "[%s] not found\n", - client->name); - return -ENODEV; - } - if( (client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count>0)) return -EBUSY; @@ -473,33 +371,41 @@ int i2c_detach_client(struct i2c_client return res; } + down(&adapter->list); + for (i = 0; i < I2C_CLIENT_MAX; i++) + if (client == adapter->clients[i]) + break; + if (I2C_CLIENT_MAX == i) { + printk(KERN_WARNING " i2c-core.o: unregister_client " + "[%s] not found\n", + client->name); + up(&adapter->list); + return -ENODEV; + } adapter->clients[i] = NULL; - adapter->client_count--; + up(&adapter->list); DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name)); return 0; } -void i2c_inc_use_client(struct i2c_client *client) +static void i2c_inc_use_client(struct i2c_client *client) { - - if (client->driver->inc_use != NULL) - client->driver->inc_use(client); - - if (client->adapter->inc_use != NULL) - client->adapter->inc_use(client->adapter); + if(client->driver->owner) + __MOD_INC_USE_COUNT(client->driver->owner); + if(client->adapter->owner) + __MOD_INC_USE_COUNT(client->adapter->owner); } -void i2c_dec_use_client(struct i2c_client *client) +static void i2c_dec_use_client(struct i2c_client *client) { - - if (client->driver->dec_use != NULL) - client->driver->dec_use(client); - - if (client->adapter->dec_use != NULL) - client->adapter->dec_use(client->adapter); + if(client->driver->owner) + __MOD_DEC_USE_COUNT(client->driver->owner); + if(client->adapter->owner) + __MOD_DEC_USE_COUNT(client->adapter->owner); } +#if 0 /* just forget about this for now --km */ struct i2c_client *i2c_get_client(int driver_id, int adapter_id, struct i2c_client *prev) { @@ -566,18 +472,17 @@ struct i2c_client *i2c_get_client(int dr return 0; } +#endif int i2c_use_client(struct i2c_client *client) { - if(client->flags & I2C_CLIENT_ALLOW_USE) { - if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) + if (client->flags & I2C_CLIENT_ALLOW_USE) { + if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) + client->usage_count++; + else if (client->usage_count > 0) + return -EBUSY; + else client->usage_count++; - else { - if(client->usage_count > 0) - return -EBUSY; - else - client->usage_count++; - } } i2c_inc_use_client(client); @@ -609,25 +514,14 @@ int i2c_release_client(struct i2c_client #ifdef CONFIG_PROC_FS -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) -/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible - if some process still uses it or some file in it */ -void monitor_bus_i2c(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} -#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,37)) */ - /* This function generates the output for /proc/bus/i2c */ -int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, +static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, void *private) { int i; int nr = 0; /* Note that it is safe to write a `little' beyond len. Yes, really. */ + down(&core_lists); for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++) if (adapters[i]) { nr += sprintf(buf+nr, "i2c-%d\t", i); @@ -644,6 +538,7 @@ int read_bus_i2c(char *buf, char **start adapters[i]->name, adapters[i]->algo->name); } + up(&core_lists); return nr; } @@ -654,6 +549,7 @@ ssize_t i2cproc_bus_read(struct file * f struct inode * inode = file->f_dentry->d_inode; char *kbuf; struct i2c_client *client; + struct i2c_adapter *adap; int i,j,k,order_nr,len=0; size_t len_total; int order[I2C_CLIENT_MAX]; @@ -663,94 +559,115 @@ ssize_t i2cproc_bus_read(struct file * f if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) ) /* adjust to maximum file size */ len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE); - for (i = 0; i < I2C_ADAP_MAX; i++) - if (adapters[i]->inode == inode->i_ino) { - /* We need a bit of slack in the kernel buffer; this makes the - sprintf safe. */ - if (! (kbuf = kmalloc(len_total + - OUTPUT_LENGTH_PER_LINE, - GFP_KERNEL))) - return -ENOMEM; - /* Order will hold the indexes of the clients - sorted by address */ - order_nr=0; - for (j = 0; j < I2C_CLIENT_MAX; j++) { - if ((client = adapters[i]->clients[j]) && - (client->driver->id != I2C_DRIVERID_I2CDEV)) { - for(k = order_nr; - (k > 0) && - adapters[i]->clients[order[k-1]]-> - addr > client->addr; - k--) - order[k] = order[k-1]; - order[k] = j; - order_nr++; - } - } - - for (j = 0; (j < order_nr) && (len < len_total); j++) { - client = adapters[i]->clients[order[j]]; - len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", - client->addr, - client->name, - client->driver->name); - } - len = len - file->f_pos; - if (len > count) - len = count; - if (len < 0) - len = 0; - if (copy_to_user (buf,kbuf+file->f_pos, len)) { - kfree(kbuf); - return -EFAULT; - } - file->f_pos += len; - kfree(kbuf); - return len; - } - return -ENOENT; + down(&core_lists); + /* adap = file->private_data; ?? --km */ + for (i = 0; i < I2C_ADAP_MAX; i++) { + adap = adapters[i]; + if (adap && (adap->inode == inode->i_ino)) + break; + } + if ( I2C_ADAP_MAX == i ) { + up(&core_lists); + return -ENOENT; + } + + /* We need a bit of slack in the kernel buffer; this makes the + sprintf safe. */ + if (! (kbuf = kmalloc(len_total + + OUTPUT_LENGTH_PER_LINE, + GFP_KERNEL))) + return -ENOMEM; + + /* Order will hold the indexes of the clients + sorted by address */ + order_nr=0; + down(&adap->list); + for (j = 0; j < I2C_CLIENT_MAX; j++) { + if ((client = adap->clients[j]) && + (client->driver->id != I2C_DRIVERID_I2CDEV)) { + for(k = order_nr; + (k > 0) && + adap->clients[order[k-1]]-> + addr > client->addr; + k--) + order[k] = order[k-1]; + order[k] = j; + order_nr++; + } + } + + + for (j = 0; (j < order_nr) && (len < len_total); j++) { + client = adap->clients[order[j]]; + len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", + client->addr, + client->name, + client->driver->name); + } + up(&adap->list); + up(&core_lists); + + len = len - file->f_pos; + if (len > count) + len = count; + if (len < 0) + len = 0; + if (copy_to_user (buf,kbuf+file->f_pos, len)) { + kfree(kbuf); + return -EFAULT; + } + file->f_pos += len; + kfree(kbuf); + return len; +} + +static int i2cproc_register(struct i2c_adapter *adap, int bus) +{ + char name[8]; + struct proc_dir_entry *proc_entry; + + sprintf(name,"i2c-%d", bus); + proc_entry = create_proc_entry(name,0,proc_bus); + if (! proc_entry) { + printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", + name); + return -ENOENT; + } + + proc_entry->proc_fops = &i2cproc_operations; + proc_entry->owner = adap->owner; + adap->inode = proc_entry->low_ino; + return 0; } -int i2cproc_init(void) +static void i2cproc_remove(int bus) { + char name[8]; + sprintf(name,"i2c-%d", bus); + remove_proc_entry(name, proc_bus); +} +static int __init i2cproc_init(void) +{ struct proc_dir_entry *proc_bus_i2c; - i2cproc_initialized = 0; - - if (! proc_bus) { - printk(KERN_ERR "i2c-core.o: /proc/bus/ does not exist"); - i2cproc_cleanup(); - return -ENOENT; - } proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); if (!proc_bus_i2c) { printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); - i2cproc_cleanup(); return -ENOENT; } + proc_bus_i2c->read_proc = &read_bus_i2c; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) proc_bus_i2c->owner = THIS_MODULE; -#else - proc_bus_i2c->fill_inode = &monitor_bus_i2c; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */ - i2cproc_initialized += 2; return 0; } -int i2cproc_cleanup(void) +static void __exit i2cproc_cleanup(void) { - - if (i2cproc_initialized >= 1) { - remove_proc_entry("i2c",proc_bus); - i2cproc_initialized -= 2; - } - return 0; + remove_proc_entry("i2c",proc_bus); } - #endif /* def CONFIG_PROC_FS */ /* ---------------------------------------------------- @@ -766,9 +683,9 @@ int i2c_transfer(struct i2c_adapter * ad DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n", adap->name,num)); - I2C_LOCK(adap); + down(&adap->bus); ret = adap->algo->master_xfer(adap,msgs,num); - I2C_UNLOCK(adap); + up(&adap->bus); return ret; } else { @@ -793,9 +710,9 @@ int i2c_master_send(struct i2c_client *c DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", count,client->adapter->name)); - I2C_LOCK(adap); + down(&adap->bus); ret = adap->algo->master_xfer(adap,&msg,1); - I2C_UNLOCK(adap); + up(&adap->bus); /* if everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. @@ -823,9 +740,9 @@ int i2c_master_recv(struct i2c_client *c DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", count,client->adapter->name)); - I2C_LOCK(adap); + down(&adap->bus); ret = adap->algo->master_xfer(adap,&msg,1); - I2C_UNLOCK(adap); + up(&adap->bus); DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", ret, count, client->addr)); @@ -1411,7 +1328,7 @@ static s32 i2c_smbus_xfer_emulated(struc } -s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, +s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { @@ -1421,7 +1338,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * flags &= I2C_M_TEN | I2C_CLIENT_PEC; if((flags & I2C_CLIENT_PEC) && - !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { + !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) { swpec = 1; if(read_write == I2C_SMBUS_READ && size == I2C_SMBUS_BLOCK_DATA) @@ -1439,13 +1356,13 @@ s32 i2c_smbus_xfer(struct i2c_adapter * size = i2c_smbus_add_pec(addr, command, size, data); } - if (adapter->algo->smbus_xfer) { - I2C_LOCK(adapter); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, + if (adap->algo->smbus_xfer) { + down(&adap->bus); + res = adap->algo->smbus_xfer(adap,addr,flags,read_write, command,size,data); - I2C_UNLOCK(adapter); + up(&adap->bus); } else - res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, + res = i2c_smbus_xfer_emulated(adap,addr,flags,read_write, command,size,data); if(res >= 0 && swpec && @@ -1481,258 +1398,35 @@ static int __init i2c_init(void) printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE); memset(adapters,0,sizeof(adapters)); memset(drivers,0,sizeof(drivers)); - adap_count=0; - driver_count=0; - init_MUTEX(&adap_lock); - init_MUTEX(&driver_lock); - - i2cproc_init(); - +#ifdef CONFIG_PROC_FS + return i2cproc_init(); +#else return 0; +#endif + } static void __exit i2c_exit(void) { +#ifdef CONFIG_PROC_FS i2cproc_cleanup(); -} - -#ifndef MODULE -#ifdef CONFIG_I2C_CHARDEV - extern int i2c_dev_init(void); -#endif -#ifdef CONFIG_I2C_ALGOBIT - extern int i2c_algo_bit_init(void); -#endif -#ifdef CONFIG_I2C_PHILIPSPAR - extern int i2c_bitlp_init(void); -#endif -#ifdef CONFIG_I2C_ELV - extern int i2c_bitelv_init(void); -#endif -#ifdef CONFIG_I2C_VELLEMAN - extern int i2c_bitvelle_init(void); -#endif -#ifdef CONFIG_I2C_PPORT - extern int i2c_bitpport_init(void); -#endif -#ifdef CONFIG_I2C_FRODO - extern int i2c_frodo_init(void); -#endif -#ifdef CONFIG_I2C_BITVIA - extern int i2c_bitvia_init(void); -#endif - -#ifdef CONFIG_I2C_ALGOPCF - extern int i2c_algo_pcf_init(void); -#endif -#ifdef CONFIG_I2C_ELEKTOR - extern int i2c_pcfisa_init(void); -#endif -#ifdef CONFIG_I2C_PCFEPP - extern int i2c_pcfepp_init(void); -#endif - -#ifdef CONFIG_I2C_ALGO8XX - extern int i2c_algo_8xx_init(void); -#endif -#ifdef CONFIG_I2C_RPXLITE - extern int i2c_rpx_init(void); -#endif -#ifdef CONFIG_I2C_IBM_OCP_ALGO - extern int i2c_algo_iic_init(void); -#endif -#ifdef CONFIG_I2C_IBM_OCP_ADAP - extern int iic_ibmocp_init(void); -#endif -#ifdef CONFIG_I2C_PROC - extern int sensors_init(void); -#endif - -/* This is needed for automatic patch generation: sensors code starts here */ -#ifdef CONFIG_I2C_ALI1535 - extern int i2c_ali1535_init(void); -#endif -#ifdef CONFIG_I2C_ALI15X3 - extern int i2c_ali15x3_init(void); -#endif -#ifdef CONFIG_I2C_AMD756 - extern int i2c_amd756_init(void); -#endif -#ifdef CONFIG_I2C_AMD8111 - extern int i2c_amd8111_init(void); -#endif -#ifdef CONFIG_I2C_HYDRA - extern int i2c_hydra_init(void); -#endif -#ifdef CONFIG_I2C_I801 - extern int i2c_i801_init(void); -#endif -#ifdef CONFIG_I2C_I810 - extern int i2c_i810_init(void); -#endif -#ifdef CONFIG_I2C_ISA - extern int i2c_isa_init(void); -#endif -#ifdef CONFIG_I2C_PIIX4 - extern int i2c_piix4_init(void); -#endif -#ifdef CONFIG_I2C_SIS5595 - extern int i2c_sis5595_init(void); -#endif -#ifdef CONFIG_I2C_SIS630 - extern int i2c_sis630_init(void); #endif -#ifdef CONFIG_I2C_SIS645 - extern int sis645_init(void); -#endif -#ifdef CONFIG_I2C_SAVAGE4 - extern int i2c_savage4_init(void); -#endif -#ifdef CONFIG_I2C_TSUNAMI - extern int i2c_tsunami_init(void); -#endif -#ifdef CONFIG_I2C_VIA - extern int i2c_via_init(void); -#endif -#ifdef CONFIG_I2C_VIAPRO - extern int i2c_vt596_init(void); -#endif -#ifdef CONFIG_I2C_VOODOO3 - extern int i2c_voodoo3_init(void); -#endif -/* This is needed for automatic patch generation: sensors code ends here */ +} +/* leave this in for now simply to make patching easier so we don't have + to remove the call in drivers/char/mem.c */ int __init i2c_init_all(void) { - /* --------------------- global ----- */ - i2c_init(); - -#ifdef CONFIG_I2C_CHARDEV - i2c_dev_init(); -#endif - /* --------------------- bit -------- */ -#ifdef CONFIG_I2C_ALGOBIT - i2c_algo_bit_init(); -#endif -#ifdef CONFIG_I2C_PHILIPSPAR - i2c_bitlp_init(); -#endif -#ifdef CONFIG_I2C_ELV - i2c_bitelv_init(); -#endif -#ifdef CONFIG_I2C_VELLEMAN - i2c_bitvelle_init(); -#endif -#ifdef CONFIG_I2C_PPORT - i2c_bitpport_init(); -#endif -#ifdef CONFIG_I2C_FRODO - i2c_frodo_init(); -#endif -#ifdef CONFIG_I2C_BITVIA - i2c_bitvia_init(); -#endif - - /* --------------------- pcf -------- */ -#ifdef CONFIG_I2C_ALGOPCF - i2c_algo_pcf_init(); -#endif -#ifdef CONFIG_I2C_ELEKTOR - i2c_pcfisa_init(); -#endif -#ifdef CONFIG_I2C_PCFEPP - i2c_pcfepp_init(); -#endif - - /* --------------------- 8xx -------- */ -#ifdef CONFIG_I2C_ALGO8XX - i2c_algo_8xx_init(); -#endif -#ifdef CONFIG_I2C_RPXLITE - i2c_rpx_init(); -#endif -#ifdef CONFIG_I2C_IBM_OCP_ALGO - i2c_algo_iic_init(); -#endif -#ifdef CONFIG_I2C_IBM_OCP_ADAP - iic_ibmocp_init(); -#endif - - /* -------------- proc interface ---- */ -#ifdef CONFIG_I2C_PROC - sensors_init(); -#endif -/* This is needed for automatic patch generation: sensors code starts here */ -#ifdef CONFIG_I2C_ALI1535 - i2c_ali1535_init(); -#endif -#ifdef CONFIG_I2C_ALI15X3 - i2c_ali15x3_init(); -#endif -#ifdef CONFIG_I2C_AMD756 - i2c_amd756_init(); -#endif -#ifdef CONFIG_I2C_AMD8111 - i2c_amd8111_init(); -#endif -#ifdef CONFIG_I2C_HYDRA - i2c_hydra_init(); -#endif -#ifdef CONFIG_I2C_I801 - i2c_i801_init(); -#endif -#ifdef CONFIG_I2C_I810 - i2c_i810_init(); -#endif -#ifdef CONFIG_I2C_PIIX4 - i2c_piix4_init(); -#endif -#ifdef CONFIG_I2C_SIS5595 - i2c_sis5595_init(); -#endif -#ifdef CONFIG_I2C_SIS630 - i2c_sis630_init(); -#endif -#ifdef CONFIG_I2C_SIS645 - sis645_init(); -#endif -#ifdef CONFIG_I2C_SAVAGE4 - i2c_savage4_init(); -#endif -#ifdef CONFIG_I2C_TSUNAMI - i2c_tsunami_init(); -#endif -#ifdef CONFIG_I2C_VIA - i2c_via_init(); -#endif -#ifdef CONFIG_I2C_VIAPRO - i2c_vt596_init(); -#endif -#ifdef CONFIG_I2C_VOODOO3 - i2c_voodoo3_init(); -#endif -#ifdef CONFIG_I2C_ISA - i2c_isa_init(); -#endif -/* This is needed for automatic patch generation: sensors code ends here */ - return 0; } -#endif - - - EXPORT_SYMBOL(i2c_add_adapter); EXPORT_SYMBOL(i2c_del_adapter); EXPORT_SYMBOL(i2c_add_driver); EXPORT_SYMBOL(i2c_del_driver); EXPORT_SYMBOL(i2c_attach_client); EXPORT_SYMBOL(i2c_detach_client); -EXPORT_SYMBOL(i2c_inc_use_client); -EXPORT_SYMBOL(i2c_dec_use_client); -EXPORT_SYMBOL(i2c_get_client); EXPORT_SYMBOL(i2c_use_client); EXPORT_SYMBOL(i2c_release_client); EXPORT_SYMBOL(i2c_check_addr); @@ -1762,15 +1456,12 @@ EXPORT_SYMBOL(i2c_smbus_write_i2c_block_ EXPORT_SYMBOL(i2c_get_functionality); EXPORT_SYMBOL(i2c_check_functionality); -#ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); +MODULE_LICENSE("GPL"); + MODULE_PARM(i2c_debug, "i"); MODULE_PARM_DESC(i2c_debug,"debug level"); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif module_init(i2c_init); module_exit(i2c_exit); -#endif /* MODULE */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-dev.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-dev.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-dev.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-dev.c 2003-08-17 21:26:58.000000000 +0200 @@ -28,35 +28,27 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -/* $Id: i2c-dev.c,v 1.49 2002/11/23 20:58:13 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.50.2.6 2003/06/28 18:19:12 mds Exp $ */ -#include #include #include #include #include -#include -#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) #include -#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ #ifdef CONFIG_DEVFS_FS #include #endif - +#include +#include +#include +#include /* If you want debugging uncomment: */ /* #define DEBUG */ -#include -#include -#include -#include /* struct file_operations changed too often in the 2.1 series for nice code */ -#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9) -static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin); -#endif static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, loff_t *offset); static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, @@ -74,14 +66,8 @@ static int i2cdev_command(struct i2c_cli void *arg); static struct file_operations i2cdev_fops = { -#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) .owner = THIS_MODULE, -#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ -#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9) - .llseek = i2cdev_lseek, -#else .llseek = no_llseek, -#endif .read = i2cdev_read, .write = i2cdev_write, .ioctl = i2cdev_ioctl, @@ -97,6 +83,7 @@ static devfs_handle_t devfs_handle = NUL #endif static struct i2c_driver i2cdev_driver = { + .owner = THIS_MODULE, /* not really used */ .name = "i2c-dev dummy driver", .id = I2C_DRIVERID_I2CDEV, .flags = I2C_DF_DUMMY, @@ -112,22 +99,6 @@ static struct i2c_client i2cdev_client_t .driver = &i2cdev_driver, }; -static int i2cdev_initialized; - -#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9) -/* Note that the lseek function is called llseek in 2.1 kernels. But things - are complicated enough as is. */ -loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin) -{ -#ifdef DEBUG - struct inode *inode = file->f_dentry->d_inode; - printk(KERN_DEBUG "i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", - MINOR(inode->i_rdev),(long) offset,origin); -#endif /* DEBUG */ - return -ESPIPE; -} -#endif - static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, loff_t *offset) { @@ -149,7 +120,7 @@ static ssize_t i2cdev_read (struct file return -ENOMEM; #ifdef DEBUG - printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), + printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev), count); #endif @@ -184,7 +155,7 @@ static ssize_t i2cdev_write (struct file } #ifdef DEBUG - printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), + printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev), count); #endif ret = i2c_master_send(client,tmp,count); @@ -205,7 +176,7 @@ int i2cdev_ioctl (struct inode *inode, s #ifdef DEBUG printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - MINOR(inode->i_rdev),cmd, arg); + minor(inode->i_rdev),cmd, arg); #endif /* DEBUG */ switch ( cmd ) { @@ -241,6 +212,11 @@ int i2cdev_ioctl (struct inode *inode, s sizeof(rdwr_arg))) return -EFAULT; + /* Put an arbritrary limit on the number of messages that can + * be sent at once */ + if (rdwr_arg.nmsgs > 42) + return -EINVAL; + rdwr_pa = (struct i2c_msg *) kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); @@ -257,6 +233,11 @@ int i2cdev_ioctl (struct inode *inode, s res = -EFAULT; break; } + /* Limit the size of the message to a sane amount */ + if (rdwr_pa[i].len > 8192) { + res = -EINVAL; + break; + } rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); if(rdwr_pa[i].buf == NULL) { @@ -267,11 +248,17 @@ int i2cdev_ioctl (struct inode *inode, s rdwr_arg.msgs[i].buf, rdwr_pa[i].len)) { - kfree(rdwr_pa[i].buf); res = -EFAULT; break; } } + if (res < 0) { + int j; + for (j = 0; j < i; ++j) + kfree(rdwr_pa[j].buf); + kfree(rdwr_pa); + return res; + } if (!res) { res = i2c_transfer(client->adapter, @@ -378,7 +365,7 @@ int i2cdev_ioctl (struct inode *inode, s int i2cdev_open (struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct i2c_client *client; if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { @@ -394,14 +381,13 @@ int i2cdev_open (struct inode *inode, st if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) return -ENOMEM; memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); + + /* registered with adapter, passed as client to user */ client->adapter = i2cdev_adaps[minor]; file->private_data = client; - if (i2cdev_adaps[minor]->inc_use) - i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]); -#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) - MOD_INC_USE_COUNT; -#endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */ + if(client->adapter->owner) + __MOD_INC_USE_COUNT(client->adapter->owner); #ifdef DEBUG printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor); @@ -411,22 +397,19 @@ int i2cdev_open (struct inode *inode, st static int i2cdev_release (struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - kfree(file->private_data); - file->private_data=NULL; + struct i2c_client *client; +#ifdef DEBUG + unsigned int minor = minor(inode->i_rdev); +#endif + + client = file->private_data; + file->private_data = NULL; + if(client->adapter->owner) + __MOD_DEC_USE_COUNT(client->adapter->owner); + kfree(client); #ifdef DEBUG printk(KERN_DEBUG "i2c-dev.o: Closed: i2c-%d\n", minor); #endif -#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) - MOD_DEC_USE_COUNT; -#else /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ - lock_kernel(); -#endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */ - if (i2cdev_adaps[minor]->dec_use) - i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); -#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) - unlock_kernel(); -#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ return 0; } @@ -451,7 +434,7 @@ int i2cdev_attach_adapter(struct i2c_ada devfs_i2c[i] = devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, I2C_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR, - &i2cdev_fops, NULL); + &i2cdev_fops, adap); #endif printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); } else { @@ -479,37 +462,12 @@ static int i2cdev_command(struct i2c_cli return -1; } -static void i2cdev_cleanup(void) -{ - int res; - - if (i2cdev_initialized >= 2) { - if ((res = i2c_del_driver(&i2cdev_driver))) { - printk(KERN_ERR "i2c-dev.o: Driver deregistration failed, " - "module not removed.\n"); - } - i2cdev_initialized --; - } - - if (i2cdev_initialized >= 1) { -#ifdef CONFIG_DEVFS_FS - devfs_unregister(devfs_handle); -#endif - if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { - printk(KERN_ERR "i2c-dev.o: unable to release major %d for i2c bus\n", - I2C_MAJOR); - } - i2cdev_initialized --; - } -} - int __init i2c_dev_init(void) { int res; printk(KERN_INFO "i2c-dev.o: i2c /dev entries driver module version %s (%s)\n", I2C_VERSION, I2C_DATE); - i2cdev_initialized = 0; #ifdef CONFIG_DEVFS_FS if (devfs_register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops)) { #else @@ -522,22 +480,29 @@ int __init i2c_dev_init(void) #ifdef CONFIG_DEVFS_FS devfs_handle = devfs_mk_dir(NULL, "i2c", NULL); #endif - i2cdev_initialized ++; - if ((res = i2c_add_driver(&i2cdev_driver))) { printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n"); - i2cdev_cleanup(); +#ifdef CONFIG_DEVFS_FS + devfs_unregister(devfs_handle); +#endif + unregister_chrdev(I2C_MAJOR,"i2c"); return res; } - i2cdev_initialized ++; return 0; } -EXPORT_NO_SYMBOLS; +static void __exit i2c_dev_exit(void) +{ + i2c_del_driver(&i2cdev_driver); +#ifdef CONFIG_DEVFS_FS + devfs_unregister(devfs_handle); +#endif + unregister_chrdev(I2C_MAJOR,"i2c"); +} MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); MODULE_DESCRIPTION("I2C /dev entries driver"); MODULE_LICENSE("GPL"); module_init(i2c_dev_init); -module_exit(i2cdev_cleanup); +module_exit(i2c_dev_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-elektor.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-elektor.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-elektor.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-elektor.c 2003-08-17 21:26:58.000000000 +0200 @@ -30,20 +30,15 @@ #include #include #include -#include #include #include #include #include #include #include -#include - #include #include -#include "i2c-pcf8584.h" - #define DEFAULT_BASE 0x330 static int base; @@ -58,11 +53,7 @@ static int i2c_debug; in some functions, called from the algo-pcf module. Sometimes it's need to be rewriten - but for now just remove this for simpler reading */ -#if (LINUX_VERSION_CODE < 0x020301) -static struct wait_queue *pcf_wait = NULL; -#else static wait_queue_head_t pcf_wait; -#endif static int pcf_pending; static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; @@ -146,11 +137,11 @@ static void pcf_isa_handler(int this_irq static int pcf_isa_init(void) { if (!mmapped) { - if (check_region(base, 2) < 0 ) { - printk(KERN_ERR "i2c-elektor.o: requested I/O region (0x%X:2) is in use.\n", base); + if (!request_region(base, 2, "i2c (isa bus adapter)")) { + printk(KERN_ERR + "i2c-elektor.o: requested I/O region (0x%X:2) " + "is in use.\n", base); return -ENODEV; - } else { - request_region(base, 2, "i2c (isa bus adapter)"); } } if (irq > 0) { @@ -164,44 +155,6 @@ static int pcf_isa_init(void) } -static void pcf_isa_exit(void) -{ - if (irq > 0) { - disable_irq(irq); - free_irq(irq, 0); - } - if (!mmapped) { - release_region(base , 2); - } -} - - -static int pcf_isa_reg(struct i2c_client *client) -{ - return 0; -} - - -static int pcf_isa_unreg(struct i2c_client *client) -{ - return 0; -} - -static void pcf_isa_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void pcf_isa_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - /* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. @@ -214,20 +167,17 @@ static struct i2c_algo_pcf_data pcf_isa_ .waitforpin = pcf_isa_waitforpin, .udelay = 10, .mdelay = 10, - .timeout = 100, + .timeout = HZ, }; static struct i2c_adapter pcf_isa_ops = { + .owner = THIS_MODULE, .name = "PCF8584 ISA adapter", .id = I2C_HW_P_ELEK, .algo_data = &pcf_isa_data, - .inc_use = pcf_isa_inc_use, - .dec_use = pcf_isa_dec_use, - .client_register = pcf_isa_reg, - .client_unregister = pcf_isa_unreg, }; -int __init i2c_pcfisa_init(void) +static int __init i2c_pcfisa_init(void) { #ifdef __alpha__ /* check to see we have memory mapped PCF8584 connected to the @@ -284,27 +234,41 @@ int __init i2c_pcfisa_init(void) base = DEFAULT_BASE; } -#if (LINUX_VERSION_CODE >= 0x020301) init_waitqueue_head(&pcf_wait); -#endif - if (pcf_isa_init() == 0) { - if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) { - pcf_isa_exit(); - return -ENODEV; - } - } else { + if (pcf_isa_init()) return -ENODEV; - } + if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) + goto fail; printk(KERN_ERR "i2c-elektor.o: found device at %#x.\n", base); return 0; + + fail: + if (irq > 0) { + disable_irq(irq); + free_irq(irq, 0); + } + + if (!mmapped) + release_region(base , 2); + return -ENODEV; } -EXPORT_NO_SYMBOLS; +static void i2c_pcfisa_exit(void) +{ + i2c_pcf_del_bus(&pcf_isa_ops); + + if (irq > 0) { + disable_irq(irq); + free_irq(irq, 0); + } + + if (!mmapped) + release_region(base , 2); +} -#ifdef MODULE MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_LICENSE("GPL"); @@ -316,15 +280,5 @@ MODULE_PARM(own, "i"); MODULE_PARM(mmapped, "i"); MODULE_PARM(i2c_debug, "i"); -int init_module(void) -{ - return i2c_pcfisa_init(); -} - -void cleanup_module(void) -{ - i2c_pcf_del_bus(&pcf_isa_ops); - pcf_isa_exit(); -} - -#endif +module_init(i2c_pcfisa_init); +module_exit(i2c_pcfisa_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-elv.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-elv.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-elv.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-elv.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,20 +21,18 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-elv.c,v 1.23 2002/11/24 05:44:15 mds Exp $ */ +/* $Id: i2c-elv.c,v 1.24.2.2 2003/01/21 10:00:19 kmalkki Exp $ */ #include #include #include #include -#include #include -#include #include -#include #include #include #include +#include #define DEFAULT_BASE 0x378 static int base=0; @@ -88,58 +86,31 @@ static int bit_elv_getsda(void *data) static int bit_elv_init(void) { - if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { - return -ENODEV; - } else { - /* test for ELV adap. */ - if (inb(base+1) & 0x80) { /* BUSY should be high */ - DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n")); - return -ENODEV; - } else { - outb(0x0c,base+2); /* SLCT auf low */ - udelay(400); - if ( !(inb(base+1) && 0x10) ) { - outb(0x04,base+2); - DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n")); - return -ENODEV; - } - } - request_region(base,(base == 0x3bc)? 3 : 8, - "i2c (ELV adapter)"); - PortData = 0; - bit_elv_setsda((void*)base,1); - bit_elv_setscl((void*)base,1); + if (!request_region(base, (base == 0x3bc) ? 3 : 8, + "i2c (ELV adapter)")) + return -ENODEV; + + if (inb(base+1) & 0x80) { /* BUSY should be high */ + DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n")); + goto fail; + } + + outb(0x0c,base+2); /* SLCT auf low */ + udelay(400); + if (!(inb(base+1) && 0x10)) { + outb(0x04,base+2); + DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n")); + goto fail; } - return 0; -} -static void __exit bit_elv_exit(void) -{ - release_region( base , (base == 0x3bc)? 3 : 8 ); -} - -static int bit_elv_reg(struct i2c_client *client) -{ + PortData = 0; + bit_elv_setsda((void*)base,1); + bit_elv_setscl((void*)base,1); return 0; -} -static int bit_elv_unreg(struct i2c_client *client) -{ - return 0; -} - -static void bit_elv_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void bit_elv_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif +fail: + release_region(base , (base == 0x3bc) ? 3 : 8); + return -ENODEV; } /* ------------------------------------------------------------------------ @@ -147,26 +118,23 @@ static void bit_elv_dec_use(struct i2c_a * This is only done when more than one hardware adapter is supported. */ static struct i2c_algo_bit_data bit_elv_data = { - NULL, - bit_elv_setsda, - bit_elv_setscl, - bit_elv_getsda, - bit_elv_getscl, - 80, 80, HZ, /* waits, timeout */ + .setsda = bit_elv_setsda, + .setscl = bit_elv_setscl, + .getsda = bit_elv_getsda, + .getscl = bit_elv_getscl, + .udelay = 80, + .mdelay = 80, + .timeout = HZ }; static struct i2c_adapter bit_elv_ops = { - "ELV Parallel port adaptor", - I2C_HW_B_ELV, - NULL, - &bit_elv_data, - bit_elv_inc_use, - bit_elv_dec_use, - bit_elv_reg, - bit_elv_unreg, + .owner = THIS_MODULE, + .name = "ELV Parallel port adaptor", + .id = I2C_HW_B_ELV, + .algo_data = &bit_elv_data, }; -int __init i2c_bitelv_init(void) +static int __init i2c_bitelv_init(void) { printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { @@ -192,26 +160,19 @@ int __init i2c_bitelv_init(void) return 0; } +static void __exit i2c_bitelv_exit(void) +{ + i2c_bit_del_bus(&bit_elv_ops); + release_region(base , (base == 0x3bc) ? 3 : 8); +} EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter"); MODULE_LICENSE("GPL"); - MODULE_PARM(base, "i"); -int init_module(void) -{ - return i2c_bitelv_init(); -} - -void cleanup_module(void) -{ - i2c_bit_del_bus(&bit_elv_ops); - bit_elv_exit(); -} - -#endif +module_init(i2c_bitelv_init); +module_exit(i2c_bitelv_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-frodo.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-frodo.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-frodo.c 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-frodo.c 2003-08-17 21:26:58.000000000 +0200 @@ -12,18 +12,14 @@ * version 2 as published by the Free Software Foundation. */ -#include -#include #include - #include #include #include - -#include - #include #include +#include + static void frodo_setsda (void *data,int state) { @@ -61,56 +57,26 @@ static struct i2c_algo_bit_data bit_frod .timeout = HZ }; -static int frodo_client_register (struct i2c_client *client) -{ - return (0); -} - -static int frodo_client_unregister (struct i2c_client *client) -{ - return (0); -} - -static void frodo_inc_use (struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -static void frodo_dec_use (struct i2c_adapter *adapter) -{ - MOD_DEC_USE_COUNT; -} - static struct i2c_adapter frodo_ops = { + .owner = THIS_MODULE, .name = "Frodo adapter driver", .id = I2C_HW_B_FRODO, .algo_data = &bit_frodo_data, - .inc_use = frodo_inc_use, - .dec_use = frodo_dec_use, - .client_register = frodo_client_register, - .client_unregister = frodo_client_unregister }; -int __init i2c_frodo_init (void) +static int __init i2c_frodo_init (void) { - return (i2c_bit_add_bus (&frodo_ops)); + return i2c_bit_add_bus(&frodo_ops); } -EXPORT_NO_SYMBOLS; - static void __exit i2c_frodo_exit (void) { - i2c_bit_del_bus (&frodo_ops); + i2c_bit_del_bus(&frodo_ops); } MODULE_AUTHOR ("Abraham van der Merwe "); MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo"); - -#ifdef MODULE_LICENSE MODULE_LICENSE ("GPL"); -#endif /* #ifdef MODULE_LICENSE */ - -EXPORT_NO_SYMBOLS; module_init (i2c_frodo_init); module_exit (i2c_frodo_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-hydra.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-hydra.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-hydra.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-hydra.c 2003-08-17 21:26:58.000000000 +0200 @@ -24,24 +24,18 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include -#include -#include #include #include #include #include +#include +#include -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif -/* PCI device */ -#define VENDOR PCI_VENDOR_ID_APPLE -#define DEVICE PCI_DEVICE_ID_APPLE_HYDRA #define HYDRA_CACHE_PD 0x00000030 @@ -104,105 +98,77 @@ static int bit_hydra_getsda(void *data) return (pdregr() & HYDRA_SDAT) != 0; } -static void bit_hydra_inc(struct i2c_adapter *adap) -{ - MOD_INC_USE_COUNT; -} - -static void bit_hydra_dec(struct i2c_adapter *adap) -{ - MOD_DEC_USE_COUNT; -} - /* ------------------------------------------------------------------------ */ static struct i2c_algo_bit_data bit_hydra_data = { - NULL, - bit_hydra_setsda, - bit_hydra_setscl, - bit_hydra_getsda, - bit_hydra_getscl, - 5, 5, 100, /*waits, timeout */ + .setsda = bit_hydra_setsda, + .setscl = bit_hydra_setscl, + .getsda = bit_hydra_getsda, + .getscl = bit_hydra_getscl, + .udelay = 5, + .mdelay = 5, + .timeout = HZ }; static struct i2c_adapter bit_hydra_ops = { - "Hydra i2c", - I2C_HW_B_HYDRA, - NULL, - &bit_hydra_data, - bit_hydra_inc, - bit_hydra_dec, - NULL, - NULL, + .owner = THIS_MODULE, + .name = "Hydra i2c", + .id = I2C_HW_B_HYDRA, + .algo_data = &bit_hydra_data, }; +static struct pci_device_id hydra_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_APPLE, + .device = PCI_DEVICE_ID_APPLE_HYDRA, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; -static int find_hydra(void) +static int __devinit hydra_probe(struct pci_dev *dev, const struct pci_device_id *id) { - struct pci_dev *dev; unsigned int base_addr; - if (!pci_present()) - return -ENODEV; - - dev = pci_find_device(VENDOR, DEVICE, NULL); - if (!dev) { - printk("Hydra not found\n"); - return -ENODEV; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) base_addr = dev->resource[0].start; -#else - base_addr = dev->base_address[0]; -#endif hydra_base = (unsigned long) ioremap(base_addr, 0x100); - return 0; -} - -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_hydra_init(void) -{ - if (find_hydra() < 0) { - printk("Error while reading PCI configuration\n"); - return -ENODEV; - } - pdregw(0); /* clear SCLK_OE and SDAT_OE */ + return i2c_bit_add_bus(&bit_hydra_ops); +} - if (i2c_bit_add_bus(&bit_hydra_ops) == 0) { - printk("Hydra i2c: Module succesfully loaded\n"); - return 0; - } else { - iounmap((void *) hydra_base); - printk - ("Hydra i2c: Algo-bit error, couldn't register bus\n"); - return -ENODEV; - } +static void __devexit hydra_remove(struct pci_dev *dev) +{ + pdregw(0); /* clear SCLK_OE and SDAT_OE */ + i2c_bit_del_bus(&bit_hydra_ops); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE -MODULE_AUTHOR("Geert Uytterhoeven "); -MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); +static struct pci_driver hydra_driver = { + .name = "hydra smbus", + .id_table = hydra_ids, + .probe = hydra_probe, + .remove = __devexit_p(hydra_remove), +}; -int init_module(void) +static int __init i2c_hydra_init(void) { - return i2c_hydra_init(); + return pci_module_init(&hydra_driver); } -void cleanup_module(void) + +static void __exit i2c_hydra_exit(void) { - i2c_bit_del_bus(&bit_hydra_ops); - if (hydra_base) { - pdregw(0); /* clear SCLK_OE and SDAT_OE */ - iounmap((void *) hydra_base); - } + pci_unregister_driver(&hydra_driver); + iounmap((void *) hydra_base); } -#endif + + + +MODULE_AUTHOR("Geert Uytterhoeven "); +MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); + +module_init(i2c_hydra_init); +module_exit(i2c_hydra_exit); + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-i801.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-i801.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-i801.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-i801.c 2003-08-17 21:26:58.000000000 +0200 @@ -27,6 +27,7 @@ 82801BA 2443 82801CA/CAM 2483 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) + 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part @@ -39,84 +40,66 @@ /* #define DEBUG 1 */ -#include #include #include -#include #include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include + +/* 82801DB is undefined before kernel 2.4.19 */ +#ifndef PCI_DEVICE_ID_INTEL_82801DB_3 +#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3 #endif #ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC #define HAVE_PEC #endif -#ifndef PCI_DEVICE_ID_INTEL_82801AA_3 -#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82801AB_3 -#define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82801BA_2 -#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443 -#endif -#define PCI_DEVICE_ID_INTEL_82801CA_SMBUS 0x2483 -#define PCI_DEVICE_ID_INTEL_82801DB_SMBUS 0x24C3 - -static int supported[] = {PCI_DEVICE_ID_INTEL_82801AA_3, - PCI_DEVICE_ID_INTEL_82801AB_3, - PCI_DEVICE_ID_INTEL_82801BA_2, - PCI_DEVICE_ID_INTEL_82801CA_SMBUS, - PCI_DEVICE_ID_INTEL_82801DB_SMBUS, - 0 }; - /* I801 SMBus address offsets */ -#define SMBHSTSTS (0 + i801_smba) -#define SMBHSTCNT (2 + i801_smba) -#define SMBHSTCMD (3 + i801_smba) -#define SMBHSTADD (4 + i801_smba) -#define SMBHSTDAT0 (5 + i801_smba) -#define SMBHSTDAT1 (6 + i801_smba) -#define SMBBLKDAT (7 + i801_smba) -#define SMBPEC (8 + i801_smba) /* ICH4 only */ -#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ -#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ +#define SMBHSTSTS (0 + i801_smba) +#define SMBHSTCNT (2 + i801_smba) +#define SMBHSTCMD (3 + i801_smba) +#define SMBHSTADD (4 + i801_smba) +#define SMBHSTDAT0 (5 + i801_smba) +#define SMBHSTDAT1 (6 + i801_smba) +#define SMBBLKDAT (7 + i801_smba) +#define SMBPEC (8 + i801_smba) /* ICH4 only */ +#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ +#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ /* PCI Address Constants */ -#define SMBBA 0x020 -#define SMBHSTCFG 0x040 -#define SMBREV 0x008 +#define SMBBA 0x020 +#define SMBHSTCFG 0x040 +#define SMBREV 0x008 /* Host configuration bits for SMBHSTCFG */ -#define SMBHSTCFG_HST_EN 1 -#define SMBHSTCFG_SMB_SMI_EN 2 -#define SMBHSTCFG_I2C_EN 4 +#define SMBHSTCFG_HST_EN 1 +#define SMBHSTCFG_SMB_SMI_EN 2 +#define SMBHSTCFG_I2C_EN 4 /* Other settings */ -#define MAX_TIMEOUT 100 -#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ +#define MAX_TIMEOUT 100 +#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ /* I801 command constants */ -#define I801_QUICK 0x00 -#define I801_BYTE 0x04 -#define I801_BYTE_DATA 0x08 -#define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ -#define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ -#define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ -#define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH4 only */ +#define I801_QUICK 0x00 +#define I801_BYTE 0x04 +#define I801_BYTE_DATA 0x08 +#define I801_WORD_DATA 0x0C +#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ +#define I801_BLOCK_DATA 0x14 +#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ +#define I801_BLOCK_LAST 0x34 +#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ +#define I801_START 0x40 +#define I801_PEC_EN 0x80 /* ICH4 only */ /* insmod parameters */ @@ -128,188 +111,110 @@ MODULE_PARM_DESC(force_addr, "Forcibly enable the I801 at the given address. " "EXTREMELY DANGEROUS!"); -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_i801_init(void); -static int __init i801_cleanup(void); -static int i801_setup(void); -static s32 i801_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data); static void i801_do_pause(unsigned int amount); static int i801_transaction(void); static int i801_block_transaction(union i2c_smbus_data *data, char read_write, int command); -static void i801_inc(struct i2c_adapter *adapter); -static void i801_dec(struct i2c_adapter *adapter); -static u32 i801_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_xfer */ i801_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ i801_func, -}; -static struct i2c_adapter i801_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801, - &smbus_algorithm, - NULL, - i801_inc, - i801_dec, - NULL, - NULL, -}; +static unsigned short i801_smba; +static struct pci_dev *I801_dev; +static int isich4; -static int __initdata i801_initialized; -static unsigned short i801_smba = 0; -static struct pci_dev *I801_dev = NULL; -static int isich4 = 0; - -/* Detect whether a I801 can be found, and initialize it, where necessary. - Note the differences between kernels with the old PCI BIOS interface and - newer kernels with the real PCI interface. In compat.h some things are - defined to make the transition easier. */ -int i801_setup(void) +static int i801_setup(struct pci_dev *dev) { int error_return = 0; - int *num = supported; unsigned char temp; - /* First check whether we can access PCI at all */ - if (pci_present() == 0) { - printk(KERN_WARNING "i2c-i801.o: Error: No PCI-bus found!\n"); - error_return = -ENODEV; - goto END; - } - - /* Look for each chip */ /* Note: we keep on searching until we have found 'function 3' */ - I801_dev = NULL; - do { - if((I801_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - *num, I801_dev))) { - if(PCI_FUNC(I801_dev->devfn) != 3) - continue; - break; - } - num++; - } while (*num != 0); - - if (I801_dev == NULL) { - printk - (KERN_WARNING "i2c-i801.o: Error: Can't detect I801, function 3!\n"); - error_return = -ENODEV; - goto END; - } - isich4 = *num == PCI_DEVICE_ID_INTEL_82801DB_SMBUS; + if(PCI_FUNC(dev->devfn) != 3) + return -ENODEV; + + I801_dev = dev; + if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3 || + dev->device == 0x24d3) + isich4 = 1; + else + isich4 = 0; -/* Determine the address of the SMBus areas */ + /* Determine the address of the SMBus areas */ if (force_addr) { i801_smba = force_addr & 0xfff0; } else { pci_read_config_word(I801_dev, SMBBA, &i801_smba); i801_smba &= 0xfff0; if(i801_smba == 0) { - printk(KERN_ERR "i2c-i801.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); + dev_err(dev, "SMB base address uninitialized" + "- upgrade BIOS or use force_addr=0xaddr\n"); return -ENODEV; } } - if (check_region(i801_smba, (isich4 ? 16 : 8))) { - printk - (KERN_ERR "i2c-i801.o: I801_smb region 0x%x already in use!\n", - i801_smba); - error_return = -ENODEV; + if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) { + dev_err(dev, "I801_smb region 0x%x already in use!\n", + i801_smba); + error_return = -EBUSY; goto END; } pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ pci_write_config_byte(I801_dev, SMBHSTCFG, temp); -/* If force_addr is set, we program the new address here. Just to make - sure, we disable the device first. */ + + /* If force_addr is set, we program the new address here. Just to make + sure, we disable the device first. */ if (force_addr) { pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe); pci_write_config_word(I801_dev, SMBBA, i801_smba); pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01); - printk - (KERN_WARNING "i2c-i801.o: WARNING: I801 SMBus interface set to new " - "address %04x!\n", i801_smba); + dev_warn(dev, "WARNING: I801 SMBus interface set to " + "new address %04x!\n", i801_smba); } else if ((temp & 1) == 0) { pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1); - printk(KERN_WARNING "i2c-i801.o: enabling SMBus device\n"); + dev_warn(dev, "enabling SMBus device\n"); } - request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus"); - -#ifdef DEBUG if (temp & 0x02) - printk - (KERN_DEBUG "i2c-i801.o: I801 using Interrupt SMI# for SMBus.\n"); + dev_dbg(dev, "I801 using Interrupt SMI# for SMBus.\n"); else - printk - (KERN_DEBUG "i2c-i801.o: I801 using PCI Interrupt for SMBus.\n"); + dev_dbg(dev, "I801 using PCI Interrupt for SMBus.\n"); pci_read_config_byte(I801_dev, SMBREV, &temp); - printk(KERN_DEBUG "i2c-i801.o: SMBREV = 0x%X\n", temp); - printk(KERN_DEBUG "i2c-i801.o: I801_smba = 0x%X\n", i801_smba); -#endif /* DEBUG */ + dev_dbg(dev, "SMBREV = 0x%X\n", temp); + dev_dbg(dev, "I801_smba = 0x%X\n", i801_smba); - END: +END: return error_return; } -void i801_do_pause(unsigned int amount) +static void i801_do_pause(unsigned int amount) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(amount); } -int i801_transaction(void) +static int i801_transaction(void) { int temp; int result = 0; int timeout = 0; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(I801_dev, "Transaction (pre): CNT=%02x, CMD=%02x," + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n", - temp); -#endif + dev_dbg(I801_dev, "SMBus busy (%02x). Resetting... \n", + temp); outb_p(temp, SMBHSTSTS); if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Failed! (%02x)\n", temp); -#endif + dev_dbg(I801_dev, "Failed! (%02x)\n", temp); return -1; } else { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Successfull!\n"); -#endif + dev_dbg(I801_dev, "Successfull!\n"); } } @@ -323,76 +228,64 @@ int i801_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n"); + dev_dbg(I801_dev, "SMBus Timeout!\n"); result = -1; -#endif } if (temp & 0x10) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(I801_dev, "Error: Failed bus transaction\n"); } if (temp & 0x08) { result = -1; - printk - (KERN_ERR "i2c-i801.o: Bus collision! SMBus may be locked until next hard\n" - "reset. (sorry!)\n"); + dev_err(I801_dev, "Bus collision! SMBus may be locked " + "until next hard reset. (sorry!)\n"); /* Clock stops and slave is stuck in mid-transmission */ } if (temp & 0x04) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n"); -#endif + dev_dbg(I801_dev, "Error: no response!\n"); } if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00) outb_p(inb(SMBHSTSTS), SMBHSTSTS); if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Failed reset at end of transaction (%02x)\n", - temp); -#endif + dev_dbg(I801_dev, "Failed reset at end of transaction" + "(%02x)\n", temp); } -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(I801_dev, "Transaction (post): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); return result; } /* All-inclusive block transaction function */ -int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command) +static int i801_block_transaction(union i2c_smbus_data *data, char read_write, + int command) { int i, len; int smbcmd; int temp; int result = 0; int timeout; - unsigned char hostc, errmask; + unsigned char hostc, errmask; - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (read_write == I2C_SMBUS_WRITE) { - /* set I2C_EN bit in configuration register */ - pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); - pci_write_config_byte(I801_dev, SMBHSTCFG, - hostc | SMBHSTCFG_I2C_EN); - } else { - printk("i2c-i801.o: " - "I2C_SMBUS_I2C_BLOCK_READ not supported!\n"); - return -1; - } - } + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(I801_dev, SMBHSTCFG, + hostc | SMBHSTCFG_I2C_EN); + } else { + dev_err(I801_dev, + "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + return -1; + } + } if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; @@ -415,60 +308,43 @@ int i801_block_transaction(union i2c_smb smbcmd = I801_BLOCK_LAST; else smbcmd = I801_BLOCK_DATA; -#if 0 /* now using HW PEC */ - if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) - smbcmd |= I801_PEC_EN; -#endif outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Block (pre %d): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBBLKDAT)); -#endif + dev_dbg(I801_dev, "Block (pre %d): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); /* Make sure the SMBus host is ready to start transmitting */ temp = inb_p(SMBHSTSTS); - if (i == 1) { - /* Erronenous conditions before transaction: - * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ - errmask=0x9f; - } else { - /* Erronenous conditions during transaction: - * Failed, Bus_Err, Dev_Err, Intr */ - errmask=0x1e; - } + if (i == 1) { + /* Erronenous conditions before transaction: + * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ + errmask=0x9f; + } else { + /* Erronenous conditions during transaction: + * Failed, Bus_Err, Dev_Err, Intr */ + errmask=0x1e; + } if (temp & errmask) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n", - temp); -#endif + dev_dbg(I801_dev, "SMBus busy (%02x). " + "Resetting... \n", temp); outb_p(temp, SMBHSTSTS); if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { - printk - (KERN_ERR "i2c-i801.o: Reset failed! (%02x)\n", - temp); + dev_err(I801_dev, + "Reset failed! (%02x)\n", temp); result = -1; goto END; } if (i != 1) { - result = -1; /* if die in middle of block transaction, fail */ - goto END; - } + /* if die in middle of block transaction, fail */ + result = -1; + goto END; + } } - if (i == 1) { -#if 0 /* #ifdef HAVE_PEC (now using HW PEC) */ - if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) { - if(read_write == I2C_SMBUS_WRITE) - outb_p(data->block[len + 1], SMBPEC); - } -#endif + if (i == 1) outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); - } /* We will always wait for a fraction of a second! */ timeout = 0; @@ -482,25 +358,19 @@ int i801_block_transaction(union i2c_smb /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n"); -#endif + dev_dbg(I801_dev, "SMBus Timeout!\n"); } if (temp & 0x10) { result = -1; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(I801_dev, + "Error: Failed bus transaction\n"); } else if (temp & 0x08) { result = -1; - printk(KERN_ERR "i2c-i801.o: Bus collision!\n"); + dev_err(I801_dev, "Bus collision!\n"); } else if (temp & 0x04) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n"); -#endif + dev_dbg(I801_dev, "Error: no response!\n"); } if (i == 1 && read_write == I2C_SMBUS_READ) { @@ -512,7 +382,7 @@ int i801_block_transaction(union i2c_smb data->block[0] = len; } - /* Retrieve/store value in SMBBLKDAT */ + /* Retrieve/store value in SMBBLKDAT */ if (read_write == I2C_SMBUS_READ) data->block[i] = inb_p(SMBBLKDAT); if (read_write == I2C_SMBUS_WRITE && i+1 <= len) @@ -520,18 +390,15 @@ int i801_block_transaction(union i2c_smb if ((temp & 0x9e) != 0x00) outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */ -#ifdef DEBUG if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) { - printk - (KERN_DEBUG "i2c-i801.o: Bad status (%02x) at end of transaction\n", - temp); - } - printk - (KERN_DEBUG "i2c-i801.o: Block (post %d): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBBLKDAT)); -#endif + dev_dbg(I801_dev, + "Bad status (%02x) at end of transaction\n", + temp); + } + dev_dbg(I801_dev, "Block (post %d): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); if (result < 0) goto END; @@ -548,29 +415,24 @@ int i801_block_transaction(union i2c_smb && (timeout++ < MAX_TIMEOUT)); if (timeout >= MAX_TIMEOUT) { - printk(KERN_DEBUG "i2c-i801.o: PEC Timeout!\n"); - } -#if 0 /* now using HW PEC */ - if(read_write == I2C_SMBUS_READ) { - data->block[len + 1] = inb_p(SMBPEC); + dev_dbg(I801_dev, "PEC Timeout!\n"); } -#endif outb_p(temp, SMBHSTSTS); } #endif - result = 0; + result = 0; END: - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - /* restore saved configuration register value */ + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); - } + } return result; } /* Return -1 on error. */ -s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, - union i2c_smbus_data * data) +static s32 i801_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data * data) { int hwpec = 0; int block = 0; @@ -626,7 +488,7 @@ s32 i801_access(struct i2c_adapter * ada break; case I2C_SMBUS_PROC_CALL: default: - printk(KERN_ERR "i2c-i801.o: Unsupported transaction %d\n", size); + dev_err(I801_dev, "Unsupported transaction %d\n", size); return -1; } @@ -671,17 +533,8 @@ s32 i801_access(struct i2c_adapter * ada return 0; } -void i801_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} -void i801_dec(struct i2c_adapter *adapter) -{ - MOD_DEC_USE_COUNT; -} - -u32 i801_func(struct i2c_adapter *adapter) +static u32 i801_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | @@ -694,73 +547,103 @@ u32 i801_func(struct i2c_adapter *adapte ; } -int __init i2c_i801_init(void) +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = i801_access, + .functionality = i801_func, +}; + +static struct i2c_adapter i801_adapter = { + .owner = THIS_MODULE, + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801, + .algo = &smbus_algorithm, + .name = "unset", +}; + +static struct pci_device_id i801_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801AA_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801AB_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801BA_2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801CA_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801DB_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x24d3, /* 82801EB ICH5 */ + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int res; - printk(KERN_INFO "i2c-i801.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (i801_initialized) { - printk - (KERN_DEBUG "i2c-i801.o: Oops, i801_init called a second time!\n"); - return -EBUSY; - } -#endif - i801_initialized = 0; - if ((res = i801_setup())) { - printk - (KERN_WARNING "i2c-i801.o: I801 not detected, module not inserted.\n"); - i801_cleanup(); - return res; - } - i801_initialized++; - sprintf(i801_adapter.name, "SMBus I801 adapter at %04x", - i801_smba); - if ((res = i2c_add_adapter(&i801_adapter))) { - printk - (KERN_ERR "i2c-i801.o: Adapter registration failed, module not inserted.\n"); - i801_cleanup(); - return res; + + if (i801_setup(dev)) { + dev_warn(dev, + "I801 not detected, module not inserted.\n"); + return -ENODEV; } - i801_initialized++; - printk(KERN_INFO "i2c-i801.o: I801 bus detected and initialized\n"); - return 0; + + snprintf(i801_adapter.name, 32, + "SMBus I801 adapter at %04x", i801_smba); + return i2c_add_adapter(&i801_adapter); } -int __init i801_cleanup(void) +static void __devexit i801_remove(struct pci_dev *dev) { - int res; - if (i801_initialized >= 2) { - if ((res = i2c_del_adapter(&i801_adapter))) { - printk - (KERN_ERR "i2c-i801.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - i801_initialized--; - } - if (i801_initialized >= 1) { - release_region(i801_smba, (isich4 ? 16 : 8)); - i801_initialized--; - } - return 0; + i2c_del_adapter(&i801_adapter); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , and Mark D. Studebaker "); -MODULE_DESCRIPTION("I801 SMBus driver"); +static struct pci_driver i801_driver = { + .name = "i801 smbus", + .id_table = i801_ids, + .probe = i801_probe, + .remove = __devexit_p(i801_remove), +}; -int init_module(void) +static int __init i2c_i801_init(void) { - return i2c_i801_init(); + printk(KERN_INFO "i2c-i801 version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&i801_driver); } -int cleanup_module(void) +static void __exit i2c_i801_exit(void) { - return i801_cleanup(); + pci_unregister_driver(&i801_driver); + release_region(i801_smba, (isich4 ? 16 : 8)); } -#endif /* MODULE */ +MODULE_AUTHOR ("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark D. Studebaker "); +MODULE_DESCRIPTION("I801 SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_i801_init); +module_exit(i2c_i801_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-i810.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-i810.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-i810.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-i810.c 2003-08-17 21:26:58.000000000 +0200 @@ -35,38 +35,21 @@ */ -#include #include #include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif -/* PCI defines */ -#ifndef PCI_DEVICE_ID_INTEL_82810_IG1 -#define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82810_IG3 -#define PCI_DEVICE_ID_INTEL_82810_IG3 0x7123 -#endif #ifndef PCI_DEVICE_ID_INTEL_82815_2 #define PCI_DEVICE_ID_INTEL_82815_2 0x1132 #endif -static int i810_supported[] = {PCI_DEVICE_ID_INTEL_82810_IG1, - PCI_DEVICE_ID_INTEL_82810_IG3, - 0x7125, - PCI_DEVICE_ID_INTEL_82815_2, - 0x2562, - 0 }; - /* GPIO register locations */ #define I810_IOCONTROL_OFFSET 0x5000 #define I810_HVSYNC 0x00 /* not used */ @@ -94,24 +77,10 @@ static int i810_supported[] = {PCI_DEVIC #define CYCLE_DELAY 10 #define TIMEOUT (HZ / 2) -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_i810_init(void); -static int __init i810i2c_cleanup(void); -static int i810i2c_setup(void); + static void config_i810(struct pci_dev *dev); -static void i810_inc(struct i2c_adapter *adapter); -static void i810_dec(struct i2c_adapter *adapter); -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ -static int __initdata i810i2c_initialized; static unsigned char *mem; static inline void outlong(unsigned int dat, int off) @@ -193,46 +162,6 @@ static int bit_i810ddc_getsda(void *data return (0 != (readlong(I810_GPIOA) & SDA_VAL_IN)); } -static struct i2c_algo_bit_data i810_i2c_bit_data = { - NULL, - bit_i810i2c_setsda, - bit_i810i2c_setscl, - bit_i810i2c_getsda, - bit_i810i2c_getscl, - CYCLE_DELAY, CYCLE_DELAY, TIMEOUT -}; - -static struct i2c_adapter i810_i2c_adapter = { - "I810/I815 I2C Adapter", - I2C_HW_B_I810, - NULL, - &i810_i2c_bit_data, - i810_inc, - i810_dec, - NULL, - NULL, -}; - -static struct i2c_algo_bit_data i810_ddc_bit_data = { - NULL, - bit_i810ddc_setsda, - bit_i810ddc_setscl, - bit_i810ddc_getsda, - bit_i810ddc_getscl, - CYCLE_DELAY, CYCLE_DELAY, TIMEOUT -}; - -static struct i2c_adapter i810_ddc_adapter = { - "I810/I815 DDC Adapter", - I2C_HW_B_I810, - NULL, - &i810_ddc_bit_data, - i810_inc, - i810_dec, - NULL, - NULL, -}; - /* Configures the chip */ void config_i810(struct pci_dev *dev) @@ -240,11 +169,7 @@ void config_i810(struct pci_dev *dev) unsigned long cadr; /* map I810 memory */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) cadr = dev->resource[1].start; -#else - cadr = dev->base_address[1]; -#endif cadr += I810_IOCONTROL_OFFSET; cadr &= PCI_BASE_ADDRESS_MEM_MASK; mem = ioremap_nocache(cadr, 0x1000); @@ -256,110 +181,139 @@ void config_i810(struct pci_dev *dev) } } -/* Detect whether a supported device can be found, - and initialize it */ -static int i810i2c_setup(void) -{ - struct pci_dev *dev = NULL; - int *num = i810_supported; - - do { - if ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, - *num++, dev))) { - config_i810(dev); - if(!mem) - return -ENOMEM; - printk("i2c-i810.o: i810/i815 found.\n"); - return 0; - } - } while (*num != 0); - return -ENODEV; -} +static struct i2c_algo_bit_data i810_i2c_bit_data = { + .setsda = bit_i810i2c_setsda, + .setscl = bit_i810i2c_setscl, + .getsda = bit_i810i2c_getsda, + .getscl = bit_i810i2c_getscl, + .udelay = CYCLE_DELAY, + .mdelay = CYCLE_DELAY, + .timeout = TIMEOUT, +}; + +static struct i2c_adapter i810_i2c_adapter = { + .owner = THIS_MODULE, + .name = "I810/I815 I2C Adapter", + .id = I2C_HW_B_I810, + .algo_data = &i810_i2c_bit_data, +}; + +static struct i2c_algo_bit_data i810_ddc_bit_data = { + .setsda = bit_i810ddc_setsda, + .setscl = bit_i810ddc_setscl, + .getsda = bit_i810ddc_getsda, + .getscl = bit_i810ddc_getscl, + .udelay = CYCLE_DELAY, + .mdelay = CYCLE_DELAY, + .timeout = TIMEOUT, +}; +static struct i2c_adapter i810_ddc_adapter = { + .owner = THIS_MODULE, + .name = "I810/I815 DDC Adapter", + .id = I2C_HW_B_I810, + .algo_data = &i810_ddc_bit_data, +}; + + +static struct pci_device_id i810_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82810_IG1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82810_IG3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x7125, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82815_2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x2562, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; -void i810_inc(struct i2c_adapter *adapter) +static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id) { - MOD_INC_USE_COUNT; + int retval; + + config_i810(dev); + printk("i2c-i810.o: i810/i815 found.\n"); + + retval = i2c_bit_add_bus(&i810_i2c_adapter); + if(retval) + return retval; + retval = i2c_bit_add_bus(&i810_ddc_adapter); + if(retval) + i2c_bit_del_bus(&i810_i2c_adapter); + return retval; } -void i810_dec(struct i2c_adapter *adapter) +static void __devexit i810_remove(struct pci_dev *dev) { - MOD_DEC_USE_COUNT; + i2c_bit_del_bus(&i810_ddc_adapter); + i2c_bit_del_bus(&i810_i2c_adapter); } -int __init i2c_i810_init(void) + +/* Don't register driver to avoid driver conflicts */ +/* +static struct pci_driver i810_driver = { + .name = "i810 smbus", + .id_table = i810_ids, + .probe = i810_probe, + .remove = __devexit_p(i810_remove), +}; +*/ + +static int __init i2c_i810_init(void) { - int res; - printk("i2c-i810.o version %s (%s)\n", LM_VERSION, LM_DATE); + struct pci_dev *dev; + const struct pci_device_id *id; - i810i2c_initialized = 0; - if ((res = i810i2c_setup())) { - printk - ("i2c-i810.o: i810/i815 not detected, module not inserted.\n"); - i810i2c_cleanup(); - return res; - } - if ((res = i2c_bit_add_bus(&i810_i2c_adapter))) { - printk("i2c-i810.o: I2C adapter registration failed\n"); - } else { - printk("i2c-i810.o: I810/I815 I2C bus initialized\n"); - i810i2c_initialized |= INIT2; - } - if ((res = i2c_bit_add_bus(&i810_ddc_adapter))) { - printk("i2c-i810.o: DDC adapter registration failed\n"); - } else { - printk("i2c-i810.o: I810/I815 DDC bus initialized\n"); - i810i2c_initialized |= INIT3; - } - if(!(i810i2c_initialized & (INIT2 | INIT3))) { - printk("i2c-i810.o: Both registrations failed, module not inserted\n"); - i810i2c_cleanup(); - return res; + printk("i2c-i810.o version %s (%s)\n", LM_VERSION, LM_DATE); +/* + return pci_module_init(&i810_driver); +*/ + pci_for_each_dev(dev) { + id = pci_match_device(i810_ids, dev); + if(id) + if(i810_probe(dev, id) >= 0) + return 0; } - return 0; + return -ENODEV; } -int __init i810i2c_cleanup(void) +static void __exit i2c_i810_exit(void) { - int res; - +/* + pci_unregister_driver(&i810_driver); +*/ + i810_remove(NULL); iounmap(mem); - if (i810i2c_initialized & INIT3) { - if ((res = i2c_bit_del_bus(&i810_ddc_adapter))) { - printk - ("i2c-i810.o: i2c_del_adapter failed, module not removed\n"); - return res; - } - } - if (i810i2c_initialized & INIT2) { - if ((res = i2c_bit_del_bus(&i810_i2c_adapter))) { - printk - ("i2c-i810.o: i2c_del_adapter failed, module not removed\n"); - return res; - } - } - i810i2c_initialized = 0; - return 0; } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , Ralph Metzler , and Mark D. Studebaker "); MODULE_DESCRIPTION("I810/I815 I2C/DDC driver"); - -int init_module(void) -{ - return i2c_i810_init(); -} - -int cleanup_module(void) -{ - return i810i2c_cleanup(); -} - -#endif /* MODULE */ +module_init(i2c_i810_init); +module_exit(i2c_i810_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-isa.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-isa.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-isa.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-isa.c 2003-08-17 21:26:58.000000000 +0200 @@ -24,134 +24,51 @@ the SMBus and the ISA bus very much easier. See lm78.c for an example of this. */ -#include +#include #include #include +#include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -static void isa_inc_use(struct i2c_adapter *adapter); -static void isa_dec_use(struct i2c_adapter *adapter); static u32 isa_func(struct i2c_adapter *adapter); -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_isa_init(void); -static int __init isa_cleanup(void); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* This is the actual algorithm we define */ static struct i2c_algorithm isa_algorithm = { - /* name */ "ISA bus algorithm", - /* id */ I2C_ALGO_ISA, - /* master_xfer */ NULL, - /* smbus_access */ NULL, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ &isa_func, + .name = "ISA bus algorithm", + .id = I2C_ALGO_ISA, + .functionality = isa_func, }; /* There can only be one... */ static struct i2c_adapter isa_adapter = { - /* name */ "ISA main adapter", - /* id */ I2C_ALGO_ISA | I2C_HW_ISA, - /* algorithm */ &isa_algorithm, - /* algo_data */ NULL, - /* inc_use */ &isa_inc_use, - /* dec_use */ &isa_dec_use, - /* data */ NULL, - /* Other fields not initialized */ + .owner = THIS_MODULE, + .name = "ISA main adapter", + .id = I2C_ALGO_ISA | I2C_HW_ISA, + .algo = &isa_algorithm, }; -/* Used in isa_init/cleanup */ -static int __initdata isa_initialized; - -void isa_inc_use(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void isa_dec_use(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* We can't do a thing... */ static u32 isa_func(struct i2c_adapter *adapter) { return 0; } -int __init i2c_isa_init(void) +static int __init i2c_isa_init(void) { - int res; printk("i2c-isa.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG - if (isa_initialized) { - printk - ("i2c-isa.o: Oops, isa_init called a second time!\n"); - return -EBUSY; - } -#endif - isa_initialized = 0; - if ((res = i2c_add_adapter(&isa_adapter))) { - printk("i2c-isa.o: Adapter registration failed, " - "module i2c-isa.o is not inserted\n."); - isa_cleanup(); - return res; - } - isa_initialized++; - printk("i2c-isa.o: ISA bus access for i2c modules initialized.\n"); - return 0; + return i2c_add_adapter(&isa_adapter); } -int __init isa_cleanup(void) +static void __exit i2c_isa_exit(void) { - int res; - if (isa_initialized >= 1) { - if ((res = i2c_del_adapter(&isa_adapter))) { - printk - ("i2c-isa.o: Adapter deregistration failed, module not removed.\n"); - return res; - } else - isa_initialized--; - } - return 0; + i2c_del_adapter(&isa_adapter); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("ISA bus access through i2c"); +MODULE_LICENSE("GPL"); -int init_module(void) -{ - return i2c_isa_init(); -} - -int cleanup_module(void) -{ - return isa_cleanup(); -} - -#endif /* MODULE */ +module_init(i2c_isa_init); +module_exit(i2c_isa_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-pcf-epp.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-pcf-epp.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-pcf-epp.c 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-pcf-epp.c 2003-08-17 21:26:58.000000000 +0200 @@ -1,21 +1,37 @@ /* ------------------------------------------------------------------------- */ /* i2c-pcf-epp.c i2c-hw access for PCF8584 style EPP parallel port adapters */ /* ------------------------------------------------------------------------- */ +/* Copyright (C) 1998-99 Hans Berglund + + 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. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Ryosuke Tajima */ #include #include #include #include #include -#include #include #include +#include +#include #include #include -#include -#include -#include "i2c-pcf8584.h" struct i2c_pcf_epp { int pe_base; @@ -35,11 +51,7 @@ static int clock = 0; static int own = 0; static int i2c_debug=0; static struct i2c_pcf_epp gpe; -#if (LINUX_VERSION_CODE < 0x020301) -static struct wait_queue *pcf_wait = NULL; -#else static wait_queue_head_t pcf_wait; -#endif static int pcf_pending; static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; @@ -178,69 +190,29 @@ static int pcf_epp_init(void *data) return 0; } - -static void __exit pcf_epp_exit(void) -{ - if (gpe.pe_irq > 0) { - disable_irq(gpe.pe_irq); - free_irq(gpe.pe_irq, 0); - } - release_region(gpe.pe_base , 5); -} - - -static int pcf_epp_reg(struct i2c_client *client) -{ - return 0; -} - - -static int pcf_epp_unreg(struct i2c_client *client) -{ - return 0; -} - -static void pcf_epp_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void pcf_epp_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - /* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. */ static struct i2c_algo_pcf_data pcf_epp_data = { - NULL, - pcf_epp_setbyte, - pcf_epp_getbyte, - pcf_epp_getown, - pcf_epp_getclock, - pcf_epp_waitforpin, - 80, 80, 100, /* waits, timeout */ + .setpcf = pcf_epp_setbyte, + .getpcf = pcf_epp_getbyte, + .getown = pcf_epp_getown, + .getclock = pcf_epp_getclock, + .waitforpin = pcf_epp_waitforpin, + .udelay = 80, + .mdelay = 80, + .timeout = HZ, }; static struct i2c_adapter pcf_epp_ops = { - "PCF8584 EPP adapter", - I2C_HW_P_LP, - NULL, - &pcf_epp_data, - pcf_epp_inc_use, - pcf_epp_dec_use, - pcf_epp_reg, - pcf_epp_unreg, + .owner = THIS_MODULE, + .name = "PCF8584 EPP adapter", + .id = I2C_HW_P_LP, + .algo_data = &pcf_epp_data, }; -int __init i2c_pcfepp_init(void) +static int __init i2c_pcfepp_init(void) { struct i2c_pcf_epp *pepp = &gpe; @@ -269,9 +241,7 @@ int __init i2c_pcfepp_init(void) pepp->pe_own = own; pcf_epp_data.data = (void *)pepp; -#if (LINUX_VERSION_CODE >= 0x020301) init_waitqueue_head(&pcf_wait); -#endif if (pcf_epp_init(pepp) == 0) { int ret; if ( (ret = i2c_pcf_add_bus(&pcf_epp_ops)) < 0) { @@ -287,12 +257,19 @@ int __init i2c_pcfepp_init(void) return 0; } +static void __exit pcf_epp_exit(void) +{ + i2c_pcf_del_bus(&pcf_epp_ops); + if (gpe.pe_irq > 0) { + disable_irq(gpe.pe_irq); + free_irq(gpe.pe_irq, 0); + } + release_region(gpe.pe_base , 5); +} -EXPORT_NO_SYMBOLS; - -#ifdef MODULE MODULE_AUTHOR("Hans Berglund \n modified by Ryosuke Tajima "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 EPP parallel port adapter"); +MODULE_LICENSE("GPL"); MODULE_PARM(base, "i"); MODULE_PARM(irq, "i"); @@ -300,17 +277,5 @@ MODULE_PARM(clock, "i"); MODULE_PARM(own, "i"); MODULE_PARM(i2c_debug, "i"); -int init_module(void) -{ - return i2c_pcfepp_init(); -} - -void cleanup_module(void) -{ - i2c_pcf_del_bus(&pcf_epp_ops); - pcf_epp_exit(); -} - -#endif - - +module_init(i2c_pcfepp_init); +module_exit(pcf_epp_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-pcf8584.h linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-pcf8584.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-pcf8584.h 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-pcf8584.h 2001-02-09 20:40:02.000000000 +0100 @@ -21,7 +21,7 @@ /* With some changes from Frodo Looijaard */ -/* $Id: i2c-pcf8584.h,v 1.4 2001/10/02 00:07:37 mds Exp $ */ +/* $Id: i2c-pcf8584.h,v 1.3 2000/01/18 23:54:07 frodo Exp $ */ #ifndef I2C_PCF8584_H #define I2C_PCF8584_H 1 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-philips-par.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-philips-par.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-philips-par.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-philips-par.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,7 +21,7 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-philips-par.c,v 1.25 2002/11/24 05:44:15 mds Exp $ */ +/* $Id: i2c-philips-par.c,v 1.26.2.2 2003/01/21 10:00:19 kmalkki Exp $ */ #include #include @@ -32,10 +32,6 @@ #include #include -#ifndef __exit -#define __exit __init -#endif - static int type; struct i2c_par @@ -129,59 +125,34 @@ static int bit_lp_getsda2(void *data) PARPORT_STATUS_BUSY) ? 0 : 1; } -static int bit_lp_reg(struct i2c_client *client) -{ - return 0; -} - -static int bit_lp_unreg(struct i2c_client *client) -{ - return 0; -} - -static void bit_lp_inc_use(struct i2c_adapter *adap) -{ - MOD_INC_USE_COUNT; -} - -static void bit_lp_dec_use(struct i2c_adapter *adap) -{ - MOD_DEC_USE_COUNT; -} - /* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. */ static struct i2c_algo_bit_data bit_lp_data = { - NULL, - bit_lp_setsda, - bit_lp_setscl, - bit_lp_getsda, - bit_lp_getscl, - 80, 80, HZ, /* waits, timeout */ + .setsda = bit_lp_setsda, + .setscl = bit_lp_setscl, + .getsda = bit_lp_getsda, + .getscl = bit_lp_getscl, + .udelay = 80, + .mdelay = 80, + .timeout = HZ }; static struct i2c_algo_bit_data bit_lp_data2 = { - NULL, - bit_lp_setsda2, - bit_lp_setscl2, - bit_lp_getsda2, - NULL, - 80, 80, HZ, /* waits, timeout */ + .setsda = bit_lp_setsda2, + .setscl = bit_lp_setscl2, + .getsda = bit_lp_getsda2, + .udelay = 80, + .mdelay = 80, + .timeout = HZ }; static struct i2c_adapter bit_lp_ops = { - "Philips Parallel port adapter", - I2C_HW_B_LP, - NULL, - NULL, - bit_lp_inc_use, - bit_lp_dec_use, - bit_lp_reg, - - bit_lp_unreg, + .owner = THIS_MODULE, + .name = "Philips Parallel port adapter", + .id = I2C_HW_B_LP, }; static void i2c_parport_attach (struct parport *port) @@ -254,41 +225,25 @@ static void i2c_parport_detach (struct p } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,4) static struct parport_driver i2c_driver = { "i2c-philips-par", i2c_parport_attach, i2c_parport_detach, NULL }; -#endif int __init i2c_bitlp_init(void) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,4) - struct parport *port; -#endif printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,4) parport_register_driver(&i2c_driver); -#else - for (port = parport_enumerate(); port; port=port->next) - i2c_parport_attach(port); -#endif return 0; } void __exit i2c_bitlp_exit(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,4) parport_unregister_driver(&i2c_driver); -#else - struct parport *port; - for (port = parport_enumerate(); port; port=port->next) - i2c_parport_detach(port); -#endif } EXPORT_NO_SYMBOLS; @@ -299,14 +254,5 @@ MODULE_LICENSE("GPL"); MODULE_PARM(type, "i"); -#ifdef MODULE -int init_module(void) -{ - return i2c_bitlp_init(); -} - -void cleanup_module(void) -{ - i2c_bitlp_exit(); -} -#endif +module_init(i2c_bitlp_init); +module_exit(i2c_bitlp_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-piix4.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-piix4.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-piix4.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-piix4.c 2003-08-17 21:26:58.000000000 +0200 @@ -32,44 +32,18 @@ #include #include #include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" #include -/* Note: We assume all devices are identical - to the Intel PIIX4; we only mention it during detection. */ - -#ifndef PCI_DEVICE_ID_SERVERWORKS_OSB4 -#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 -#endif - -#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB5 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 -#endif - -#ifndef PCI_VENDOR_ID_SERVERWORKS -#define PCI_VENDOR_ID_SERVERWORKS 0x01166 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_82443MX_3 -#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b -#endif - -#ifndef PCI_VENDOR_ID_EFAR -#define PCI_VENDOR_ID_EFAR 0x1055 -#endif - -#ifndef PCI_DEVICE_ID_EFAR_SLC90E66_3 -#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463 -#endif struct sd { const unsigned short mfr; @@ -78,15 +52,6 @@ struct sd { const char *name; }; -static struct sd supported[] = { - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, 3, "PIIX4"}, - {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, 0, "OSB4"}, - {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5, 0, "CSB5"}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, 3, "440MX"}, - {PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3, 0, "Victory66"}, - {0, 0, 0, NULL} -}; - /* PIIX4 SMBus address offsets */ #define SMBHSTSTS (0 + piix4_smba) #define SMBHSLVSTS (1 + piix4_smba) @@ -136,51 +101,10 @@ MODULE_PARM_DESC(force_addr, "Forcibly enable the PIIX4 at the given address. " "EXTREMELY DANGEROUS!"); -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_piix4_init(void); -static int __init piix4_cleanup(void); -static int piix4_setup(void); -static s32 piix4_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data); static void piix4_do_pause(unsigned int amount); static int piix4_transaction(void); -static void piix4_inc(struct i2c_adapter *adapter); -static void piix4_dec(struct i2c_adapter *adapter); -static u32 piix4_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ piix4_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ piix4_func, -}; -static struct i2c_adapter piix4_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4, - &smbus_algorithm, - NULL, - piix4_inc, - piix4_dec, - NULL, - NULL, -}; -static int __initdata piix4_initialized; static unsigned short piix4_smba = 0; #ifdef CONFIG_X86 @@ -190,6 +114,7 @@ static unsigned short piix4_smba = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,34) void dmi_scan_mach(void); #endif + static int __init ibm_dmi_probe(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) @@ -212,37 +137,16 @@ static int __init ibm_dmi_probe(void) Note the differences between kernels with the old PCI BIOS interface and newer kernels with the real PCI interface. In compat.h some things are defined to make the transition easier. */ -int piix4_setup(void) +static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id) { int error_return = 0; unsigned char temp; - struct sd *num = supported; - struct pci_dev *PIIX4_dev = NULL; - - if (pci_present() == 0) { - error_return = -ENODEV; - goto END; - } - /* Look for a supported device/function */ - do { - if((PIIX4_dev = pci_find_device(num->mfr, num->dev, - PIIX4_dev))) { - if(PCI_FUNC(PIIX4_dev->devfn) != num->fn) - continue; - break; - } - PIIX4_dev = NULL; - num++; - } while (num->mfr); + /* match up the function */ + if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data) + return -ENODEV; - if (PIIX4_dev == NULL) { - printk - (KERN_ERR "i2c-piix4.o: Error: Can't detect PIIX4 or compatible device!\n"); - error_return = -ENODEV; - goto END; - } - printk(KERN_INFO "i2c-piix4.o: Found %s device\n", num->name); + printk(KERN_INFO "Found %s device\n", PIIX4_dev->name); #ifdef CONFIG_X86 if(ibm_dmi_probe()) { @@ -436,10 +340,6 @@ s32 piix4_access(struct i2c_adapter * ad int i, len; switch (size) { - case I2C_SMBUS_PROC_CALL: - printk - (KERN_ERR "i2c-piix4.o: I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); @@ -487,6 +387,10 @@ s32 piix4_access(struct i2c_adapter * ad } size = PIIX4_BLOCK_DATA; break; + default: + printk + (KERN_WARNING "i2c-piix4.o: Unsupported transaction %d\n", size); + return -1; } outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); @@ -521,16 +425,6 @@ s32 piix4_access(struct i2c_adapter * ad return 0; } -void piix4_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void piix4_dec(struct i2c_adapter *adapter) -{ - - MOD_DEC_USE_COUNT; -} u32 piix4_func(struct i2c_adapter *adapter) { @@ -539,72 +433,105 @@ u32 piix4_func(struct i2c_adapter *adapt I2C_FUNC_SMBUS_BLOCK_DATA; } -int __init i2c_piix4_init(void) +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = piix4_access, + .functionality = piix4_func, +}; + +static struct i2c_adapter piix4_adapter = { + .owner = THIS_MODULE, + .name = "unset", + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4, + .algo = &smbus_algorithm, +}; + +static struct pci_device_id piix4_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82371AB_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 3 + }, + { + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_OSB4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 0, + }, + { + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_CSB5, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 0, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82443MX_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 3, + }, + { + .vendor = PCI_VENDOR_ID_EFAR, + .device = PCI_DEVICE_ID_EFAR_SLC90E66_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 0, + }, + { 0, } +}; + +static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int res; - printk("i2c-piix4.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (piix4_initialized) { - printk - (KERN_ERR "i2c-piix4.o: Oops, piix4_init called a second time!\n"); - return -EBUSY; - } - piix4_initialized = 0; - if ((res = piix4_setup())) { - printk(KERN_ERR "i2c-piix4.o: Module insertion failed.\n"); - piix4_cleanup(); - return res; - } - piix4_initialized++; + int retval; + + retval = piix4_setup(dev, id); + if (retval) + return retval; + sprintf(piix4_adapter.name, "SMBus PIIX4 adapter at %04x", piix4_smba); - if ((res = i2c_add_adapter(&piix4_adapter))) { - printk - (KERN_ERR "i2c-piix4.o: Adapter registration failed, module not inserted.\n"); - piix4_cleanup(); - return res; - } - piix4_initialized++; - printk(KERN_ERR "i2c-piix4.o: SMBus detected and initialized\n"); - return 0; + + retval = i2c_add_adapter(&piix4_adapter); + + return retval; } -int __init piix4_cleanup(void) +static void __devexit piix4_remove(struct pci_dev *dev) { - int res; - if (piix4_initialized >= 2) { - if ((res = i2c_del_adapter(&piix4_adapter))) { - printk - (KERN_ERR "i2c-piix4.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - piix4_initialized--; - } - if (piix4_initialized >= 1) { - release_region(piix4_smba, 8); - piix4_initialized--; - } - return 0; + i2c_del_adapter(&piix4_adapter); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("PIIX4 SMBus driver"); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif +static struct pci_driver piix4_driver = { + .name = "piix4 smbus", + .id_table = piix4_ids, + .probe = piix4_probe, + .remove = __devexit_p(piix4_remove), +}; -int init_module(void) +static int __init i2c_piix4_init(void) { - return i2c_piix4_init(); + printk("i2c-piix4.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&piix4_driver); } -int cleanup_module(void) + +static void __exit i2c_piix4_exit(void) { - return piix4_cleanup(); + pci_unregister_driver(&piix4_driver); + release_region(piix4_smba, 8); } -#endif /* MODULE */ +MODULE_AUTHOR + ("Frodo Looijaard and Philip Edelbrock "); +MODULE_DESCRIPTION("PIIX4 SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_piix4_init); +module_exit(i2c_piix4_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-pport.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-pport.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-pport.c 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-pport.c 2003-08-17 21:26:58.000000000 +0200 @@ -30,18 +30,13 @@ #include #include #include -#include #include -#include #include -#include #include #include #include +#include -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif #define DEFAULT_BASE 0x378 static int base=0; @@ -112,17 +107,9 @@ static int bit_pport_getsda(void *data) static int bit_pport_init(void) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,14) if (!request_region((base+2),1, "i2c (PPORT adapter)")) { return -ENODEV; } else { -#else - if (check_region((base+2),1) < 0) { - return -ENODEV; - } - request_region((base+2),1, "i2c (PPORT adapter)"); - { -#endif /* test for PPORT adap. */ @@ -151,54 +138,26 @@ static int bit_pport_init(void) return 0; } -static int bit_pport_reg(struct i2c_client *client) -{ - return 0; -} - -static int bit_pport_unreg(struct i2c_client *client) -{ - release_region((base+2),1); - return 0; -} - -static void bit_pport_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void bit_pport_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} /* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. */ static struct i2c_algo_bit_data bit_pport_data = { - NULL, - bit_pport_setsda, - bit_pport_setscl, - bit_pport_getsda, - bit_pport_getscl, - //NULL, - 40, 80, HZ, /* waits, timeout */ + .setsda = bit_pport_setsda, + .setscl = bit_pport_setscl, + .getsda = bit_pport_getsda, + .getscl = bit_pport_getscl, + .udelay = 40, + .mdelay = 80, + .timeout = HZ }; static struct i2c_adapter bit_pport_ops = { - "Primitive Parallel port adaptor", - I2C_HW_B_PPORT, - NULL, - &bit_pport_data, - bit_pport_inc_use, - bit_pport_dec_use, - bit_pport_reg, - bit_pport_unreg, + .owner = THIS_MODULE, + .name = "Primitive Parallel port adaptor", + .id = I2C_HW_B_PPORT, + .algo_data = &bit_pport_data, }; int __init i2c_bitpport_init(void) @@ -237,8 +196,9 @@ static void __exit i2c_bitpport_exit(voi EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Daniel Smolik "); -MODULE_DESCRIPTION("I2C-Bus adapter routines for Primitive parallel port adapter") -; +MODULE_DESCRIPTION("I2C-Bus adapter routines for Primitive parallel port adapter"); +MODULE_LICENSE("GPL"); + MODULE_PARM(base, "i"); module_init(i2c_bitpport_init); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-proc.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-proc.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-proc.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-proc.c 2003-08-17 21:26:58.000000000 +0200 @@ -23,63 +23,34 @@ This driver puts entries in /proc/sys/dev/sensors for each I2C device */ -#include #include #include #include #include #include #include +#include #include -#include #include #include -#include - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#include -static int i2c_create_name(char **name, const char *prefix, - struct i2c_adapter *adapter, int addr); static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, long *results, int magnitude); -static int i2c_write_reals(int nrels, void *buffer, int *bufsize, +static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize, long *results, int magnitude); static int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) -static int i2c_sysctl_chips(ctl_table * table, int *name, unsigned nlen, - void *oldval, size_t * oldlenp, - void *newval, size_t newlen, - void **context); -#else static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context); -#endif /* 2.2.19+ */ #define SENSORS_ENTRY_MAX 20 static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX]; static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX]; -static unsigned short i2c_inodes[SENSORS_ENTRY_MAX]; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) -static void i2c_fill_inode(struct inode *inode, int fill); -static void i2c_dir_fill_inode(struct inode *inode, int fill); -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) */ - -static ctl_table sysctl_table[] = { - {CTL_DEV, "dev", NULL, 0, 0555}, - {0}, - {DEV_SENSORS, "sensors", NULL, 0, 0555}, - {0}, - {0, NULL, NULL, 0, 0555}, - {0} -}; static ctl_table i2c_proc_dev_sensors[] = { {SENSORS_CHIPS, "chips", NULL, 0, 0644, NULL, &i2c_proc_chips, @@ -100,42 +71,45 @@ static ctl_table i2c_proc[] = { static struct ctl_table_header *i2c_proc_header; -static int i2c_initialized; /* This returns a nice name for a new directory; for example lm78-isa-0310 (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for a LM75 chip on the third i2c bus at address 0x4e). name is allocated first. */ -int i2c_create_name(char **name, const char *prefix, - struct i2c_adapter *adapter, int addr) +static char *generate_name(struct i2c_client *client, const char *prefix) { - char name_buffer[50]; - int id, i, end; - if (i2c_is_isa_adapter(adapter)) + struct i2c_adapter *adapter = client->adapter; + int addr = client->addr; + char name_buffer[50], *name; + + if (i2c_is_isa_adapter(adapter)) { sprintf(name_buffer, "%s-isa-%04x", prefix, addr); - else if (!adapter->algo->smbus_xfer && !adapter->algo->master_xfer) { - /* dummy adapter, generate prefix */ + } else if (adapter->algo->smbus_xfer || adapter->algo->master_xfer) { + int id = i2c_adapter_id(adapter); + if (id < 0) + return ERR_PTR(-ENOENT); + sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr); + } else { /* dummy adapter, generate prefix */ + int end, i; + sprintf(name_buffer, "%s-", prefix); end = strlen(name_buffer); - for(i = 0; i < 32; i++) { - if(adapter->algo->name[i] == ' ') + + for (i = 0; i < 32; i++) { + if (adapter->algo->name[i] == ' ') break; name_buffer[end++] = tolower(adapter->algo->name[i]); } + name_buffer[end] = 0; sprintf(name_buffer + end, "-%04x", addr); - } else { - if ((id = i2c_adapter_id(adapter)) < 0) - return -ENOENT; - sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr); } - *name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); - if (!*name) { - printk (KERN_WARNING "i2c_create_name: not enough memory\n"); - return -ENOMEM; - } - strcpy(*name, name_buffer); - return 0; + + name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); + if (!name) + return ERR_PTR(-ENOMEM); + strcpy(name, name_buffer); + return name; } /* This rather complex function must be called when you want to add an entry @@ -144,145 +118,91 @@ int i2c_create_name(char **name, const c ctl_template should be a template of the newly created directory. It is copied in memory. The extra2 field of each file is set to point to client. If any driver wants subdirectories within the newly created directory, - this function must be updated! - controlling_mod is the controlling module. It should usually be - THIS_MODULE when calling. Note that this symbol is not defined in - kernels before 2.3.13; define it to NULL in that case. We will not use it - for anything older than 2.3.27 anyway. */ + this function must be updated! */ int i2c_register_entry(struct i2c_client *client, const char *prefix, - ctl_table * ctl_template, - struct module *controlling_mod) + struct ctl_table *ctl_template) { - int i, res, len, id; - ctl_table *new_table; - char *name; - struct ctl_table_header *new_header; + struct { struct ctl_table root[2], dev[2], sensors[2]; } *tbl; + struct ctl_table_header *hdr; + struct ctl_table *tmp, *leaf; + const char *name; + int id, len = 0; - if ((res = i2c_create_name(&name, prefix, client->adapter, - client->addr))) return res; + name = generate_name(client, prefix); + if (IS_ERR(name)) + return PTR_ERR(name); - for (id = 0; id < SENSORS_ENTRY_MAX; id++) - if (!i2c_entries[id]) { - break; - } - if (id == SENSORS_ENTRY_MAX) { - kfree(name); - return -ENOMEM; + for (id = 0; id < SENSORS_ENTRY_MAX; id++) { + if (!i2c_entries[id]) + goto free_slot; } - id += 256; - len = 0; + goto out_free_name; + + free_slot: while (ctl_template[len].procname) len++; - len += 7; - if (!(new_table = kmalloc(sizeof(ctl_table) * len, GFP_KERNEL))) { - kfree(name); - return -ENOMEM; - } - - memcpy(new_table, sysctl_table, 6 * sizeof(ctl_table)); - new_table[0].child = &new_table[2]; - new_table[2].child = &new_table[4]; - new_table[4].child = &new_table[6]; - new_table[4].procname = name; - new_table[4].ctl_name = id; - memcpy(new_table + 6, ctl_template, (len - 6) * sizeof(ctl_table)); - for (i = 6; i < len; i++) - new_table[i].extra2 = client; - - if (!(new_header = register_sysctl_table(new_table, 0))) { - printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); - kfree(new_table); - kfree(name); - return -EPERM; - } - - i2c_entries[id - 256] = new_header; - - i2c_clients[id - 256] = client; -#ifdef DEBUG - if (!new_header || !new_header->ctl_table || - !new_header->ctl_table->child || - !new_header->ctl_table->child->child || - !new_header->ctl_table->child->child->de) { - printk - (KERN_ERR "i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n"); - return id; - } -#endif /* DEBUG */ - i2c_inodes[id - 256] = - new_header->ctl_table->child->child->de->low_ino; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) - new_header->ctl_table->child->child->de->owner = controlling_mod; -#else - new_header->ctl_table->child->child->de->fill_inode = - &i2c_dir_fill_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */ - - return id; + tbl = kmalloc(sizeof(*tbl) + sizeof(ctl_table) * (len + 1), + GFP_KERNEL); + if (!tbl) + goto out_free_name; + memset(tbl, 0, sizeof(*tbl)); + + /* The client sysctls */ + leaf = (struct ctl_table *) (tbl + 1); + memcpy(leaf, ctl_template, sizeof(ctl_table) * (len+1)); + for (tmp = leaf; tmp->ctl_name; tmp++) + tmp->extra2 = client; + + tbl->sensors->ctl_name = id+256; + tbl->sensors->procname = name; + tbl->sensors->mode = 0555; + tbl->sensors->child = leaf; + + tbl->dev->ctl_name = DEV_SENSORS; + tbl->dev->procname = "sensors"; + tbl->dev->mode = 0555; + tbl->dev->child = tbl->sensors; + + tbl->root->ctl_name = CTL_DEV; + tbl->root->procname = "dev"; + tbl->root->mode = 0555; + tbl->root->child = tbl->dev; + + hdr = register_sysctl_table(tbl->root, 0); + if (!hdr) + goto out_free_tbl; + + i2c_entries[id] = hdr; + i2c_clients[id] = client; + + return (id + 256); /* XXX(hch) why?? */ + + out_free_tbl: + kfree(tbl); + out_free_name: + kfree(name); + return -ENOMEM; } void i2c_deregister_entry(int id) { - ctl_table *table; - char *temp; id -= 256; - if (i2c_entries[id]) { - table = i2c_entries[id]->ctl_table; - unregister_sysctl_table(i2c_entries[id]); - /* 2-step kfree needed to keep gcc happy about const points */ - (const char *) temp = table[4].procname; - kfree(temp); - kfree(table); - i2c_entries[id] = NULL; - i2c_clients[id] = NULL; - } -} -/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o - impossible if some process still uses it or some file in it */ -void i2c_fill_inode(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading - the corresponding module impossible if some process still uses it or - some file in it */ -void i2c_dir_fill_inode(struct inode *inode, int fill) -{ - int i; - struct i2c_client *client; + if (i2c_entries[id]) { + struct ctl_table_header *hdr = i2c_entries[id]; + struct ctl_table *tbl = hdr->ctl_table; -#ifdef DEBUG - if (!inode) { - printk(KERN_ERR "i2c-proc.o: Warning: inode NULL in fill_inode()\n"); - return; + unregister_sysctl_table(hdr); + kfree(tbl->child->child->procname); + kfree(tbl); /* actually the whole anonymous struct */ } -#endif /* def DEBUG */ - for (i = 0; i < SENSORS_ENTRY_MAX; i++) - if (i2c_clients[i] - && (i2c_inodes[i] == inode->i_ino)) break; -#ifdef DEBUG - if (i == SENSORS_ENTRY_MAX) { - printk - (KERN_ERR "i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", - inode->i_ino); - return; - } -#endif /* def DEBUG */ - client = i2c_clients[i]; - if (fill) - client->driver->inc_use(client); - else - client->driver->dec_use(client); + i2c_entries[id] = NULL; + i2c_clients[id] = NULL; } -int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, +static int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp) { char BUF[SENSORS_PREFIX_MAX + 30]; @@ -320,16 +240,9 @@ int i2c_proc_chips(ctl_table * ctl, int return 0; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) -int i2c_sysctl_chips(ctl_table * table, int *name, unsigned nlen, - void *oldval, size_t * oldlenp, void *newval, - size_t newlen, void **context) -#else -int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, +static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context) -#endif /* 2.2.19+ */ { struct i2c_chips_data data; int i, oldlen, nrels, maxels,ret=0; @@ -434,16 +347,9 @@ int i2c_proc_real(ctl_table * ctl, int w /* This function is equivalent to i2c_proc_real, only it interacts with the sysctl(2) syscall, and returns no reals, but integers */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) -int i2c_sysctl_real(ctl_table * table, int *name, unsigned nlen, - void *oldval, size_t * oldlenp, void *newval, - size_t newlen, void **context) -#else int i2c_sysctl_real(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context) -#endif /* 2.2.19+ */ { long results[MAX_RESULTS]; int oldlen, nrels = MAX_RESULTS,ret=0; @@ -496,7 +402,7 @@ int i2c_sysctl_real(ctl_table * table, i WARNING! This is tricky code. I have tested it, but there may still be hidden bugs in it, even leading to crashes and things! */ -int i2c_parse_reals(int *nrels, void *buffer, int bufsize, +static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, long *results, int magnitude) { int maxels, min, mag; @@ -597,7 +503,7 @@ int i2c_parse_reals(int *nrels, void *bu return 0; } -int i2c_write_reals(int nrels, void *buffer, int *bufsize, +static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize, long *results, int magnitude) { #define BUFLEN 20 @@ -686,6 +592,7 @@ int i2c_detect(struct i2c_adapter *adapt I2C_FUNC_SMBUS_QUICK)) return -1; for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { + /* XXX: WTF is going on here??? */ if ((is_isa && check_region(addr, 1)) || (!is_isa && i2c_check_addr(adapter, addr))) continue; @@ -755,7 +662,7 @@ int i2c_detect(struct i2c_adapter *adapt || ((address_data-> ignore_range[i] == - SENSORS_ANY_I2C_BUS) & !is_isa)) + SENSORS_ANY_I2C_BUS) && !is_isa)) && (addr >= address_data->ignore_range[i + 1]) && (addr <= address_data->ignore_range[i + 2])) { #ifdef DEBUG @@ -844,7 +751,7 @@ int i2c_detect(struct i2c_adapter *adapt i += 2) { if (((adapter_id == address_data->probe[i]) || ((address_data-> - probe[i] == SENSORS_ANY_I2C_BUS) & !is_isa)) + probe[i] == SENSORS_ANY_I2C_BUS) && !is_isa)) && (addr == address_data->probe[i + 1])) { #ifdef DEBUG printk @@ -861,7 +768,7 @@ int i2c_detect(struct i2c_adapter *adapt ((adapter_id == address_data->probe_range[i]) || ((address_data->probe_range[i] == - SENSORS_ANY_I2C_BUS) & !is_isa)) + SENSORS_ANY_I2C_BUS) && !is_isa)) && (addr >= address_data->probe_range[i + 1]) && (addr <= address_data->probe_range[i + 2])) { found = 1; @@ -886,43 +793,33 @@ int i2c_detect(struct i2c_adapter *adapt return 0; } -int __init sensors_init(void) +static int __init i2c_proc_init(void) { printk(KERN_INFO "i2c-proc.o version %s (%s)\n", I2C_VERSION, I2C_DATE); - i2c_initialized = 0; if (! (i2c_proc_header = register_sysctl_table(i2c_proc, 0))) { printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); return -EPERM; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)) i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE; -#else - i2c_proc_header->ctl_table->child->de->fill_inode = - &i2c_fill_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)) */ - i2c_initialized++; return 0; } -static void __exit i2c_cleanup(void) +static void __exit i2c_proc_exit(void) { - if (i2c_initialized >= 1) { - unregister_sysctl_table(i2c_proc_header); - i2c_initialized--; - } + unregister_sysctl_table(i2c_proc_header); } +EXPORT_SYMBOL(i2c_register_entry); EXPORT_SYMBOL(i2c_deregister_entry); -EXPORT_SYMBOL(i2c_detect); EXPORT_SYMBOL(i2c_proc_real); -EXPORT_SYMBOL(i2c_register_entry); EXPORT_SYMBOL(i2c_sysctl_real); +EXPORT_SYMBOL(i2c_detect); MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("i2c-proc driver"); MODULE_LICENSE("GPL"); -module_init(sensors_init); -module_exit(i2c_cleanup); +module_init(i2c_proc_init); +module_exit(i2c_proc_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-rpx.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-rpx.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-rpx.c 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-rpx.c 2003-08-17 21:26:58.000000000 +0200 @@ -17,12 +17,11 @@ #include #include #include - +#include +#include #include #include -#include -#include static void rpx_iic_init(struct i2c_algo_8xx_data *data) @@ -66,44 +65,15 @@ static int rpx_install_isr(int irq, void return 0; } -static int rpx_reg(struct i2c_client *client) -{ - return 0; -} - -static int rpx_unreg(struct i2c_client *client) -{ - return 0; -} - -static void rpx_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void rpx_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - static struct i2c_algo_8xx_data rpx_data = { .setisr = rpx_install_isr }; - static struct i2c_adapter rpx_ops = { - "m8xx", - I2C_HW_MPC8XX_EPON, - NULL, - &rpx_data, - rpx_inc_use, - rpx_dec_use, - rpx_reg, - rpx_unreg, + .owner = THIS_MODULE, + .name = "m8xx", + .id = I2C_HW_MPC8XX_EPON, + .algo_data = &rpx_data, }; int __init i2c_rpx_init(void) @@ -126,11 +96,8 @@ void __exit i2c_rpx_exit(void) i2c_8xx_del_bus(&rpx_ops); } -#ifdef MODULE MODULE_AUTHOR("Dan Malek "); MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards"); module_init(i2c_rpx_init); module_exit(i2c_rpx_exit); -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-savage4.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-savage4.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-savage4.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-savage4.c 2003-08-17 21:26:58.000000000 +0200 @@ -31,15 +31,14 @@ it easier to add later. */ -#include #include #include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* 3DFX defines */ /* #define PCI_VENDOR_ID_S3 0x5333 */ @@ -76,33 +75,19 @@ #define CYCLE_DELAY 10 #define TIMEOUT (HZ / 2) -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_savage4_init(void); -static int __init savage4_cleanup(void); -static int savage4_setup(void); + static void config_s4(struct pci_dev *dev); -static void savage4_inc(struct i2c_adapter *adapter); -static void savage4_dec(struct i2c_adapter *adapter); -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ -static int __initdata savage4_initialized; static unsigned char *mem; -extern inline void outlong(unsigned int dat) +static inline void outlong(unsigned int dat) { *((unsigned int *) (mem + REG)) = dat; } -extern inline unsigned int readlong(void) +static inline unsigned int readlong(void) { return *((unsigned int *) (mem + REG)); } @@ -148,78 +133,6 @@ static int bit_savi2c_getsda(void *data) return (0 != (readlong() & I2C_SDA_IN)); } -/*static void bit_savddc_setscl(void *data, int val) -{ - unsigned int r; - r = readlong(); - if(val) - r |= DDC_SCL_OUT; - else - r &= ~DDC_SCL_OUT; - outlong(r); -} - -static void bit_savddc_setsda(void *data, int val) -{ - unsigned int r; - r = readlong(); - if(val) - r |= DDC_SDA_OUT; - else - r &= ~DDC_SDA_OUT; - outlong(r); -} - -static int bit_savddc_getscl(void *data) -{ - return (0 != (readlong() & DDC_SCL_IN)); -} - -static int bit_savddc_getsda(void *data) -{ - return (0 != (readlong() & DDC_SDA_IN)); -} -*/ -static struct i2c_algo_bit_data sav_i2c_bit_data = { - NULL, - bit_savi2c_setsda, - bit_savi2c_setscl, - bit_savi2c_getsda, - bit_savi2c_getscl, - CYCLE_DELAY, CYCLE_DELAY, TIMEOUT -}; - -static struct i2c_adapter savage4_i2c_adapter = { - "I2C Savage4 adapter", - I2C_HW_B_SAVG, - NULL, - &sav_i2c_bit_data, - savage4_inc, - savage4_dec, - NULL, - NULL, -}; -/* -static struct i2c_algo_bit_data sav_ddc_bit_data = { - NULL, - bit_savddc_setsda, - bit_savddc_setscl, - bit_savddc_getsda, - bit_savddc_getscl, - CYCLE_DELAY, CYCLE_DELAY, TIMEOUT -}; - -static struct i2c_adapter savage4_ddc_adapter = { - "DDC Voodoo3/Banshee adapter", - I2C_HW_B_VOO, - NULL, - &sav_ddc_bit_data, - savage4_inc, - savage4_dec, - NULL, - NULL, -}; -*/ /* Configures the chip */ void config_s4(struct pci_dev *dev) @@ -227,11 +140,7 @@ void config_s4(struct pci_dev *dev) unsigned int cadr; /* map memory */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) cadr = dev->resource[0].start; -#else - cadr = dev->base_address[0]; -#endif cadr &= PCI_BASE_ADDRESS_MEM_MASK; mem = ioremap_nocache(cadr, 0x0080000); if(mem) { @@ -241,136 +150,93 @@ void config_s4(struct pci_dev *dev) } } -/* Detect chip and initialize it. */ -static int savage4_setup(void) -{ - struct pci_dev *dev; - int s4_num; - s4_num = 0; +static struct i2c_algo_bit_data sav_i2c_bit_data = { + .setsda = bit_savi2c_setsda, + .setscl = bit_savi2c_setscl, + .getsda = bit_savi2c_getsda, + .getscl = bit_savi2c_getscl, + .udelay = CYCLE_DELAY, + .mdelay = CYCLE_DELAY, + .timeout = TIMEOUT +}; - dev = NULL; - do { - if ((dev = pci_find_device(PCI_VENDOR_ID_S3, - PCI_CHIP_SAVAGE4, - dev))) { - if (!s4_num) - config_s4(dev); - s4_num++; - } - } while (dev); - - dev = NULL; - do { - if ((dev = pci_find_device(PCI_VENDOR_ID_S3, - PCI_CHIP_SAVAGE2000, - dev))) { - if (!s4_num) - config_s4(dev); - s4_num++; - } - } while (dev); - - if (s4_num > 0) { - if(!mem) - return -ENOMEM; - printk("i2c-savage4: %d Savage4 found.\n", s4_num); - if (s4_num > 1) - printk("i2c-savage4: warning: only 1 supported.\n"); - return 0; - } else { - printk("i2c-savage4: No Savage4 found.\n"); - return -ENODEV; - } -} +static struct i2c_adapter savage4_i2c_adapter = { + .owner = THIS_MODULE, + .name = "I2C Savage4 adapter", + .id = I2C_HW_B_SAVG, + .algo_data = &sav_i2c_bit_data, +}; -void savage4_inc(struct i2c_adapter *adapter) +static struct pci_device_id savage4_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_S3, + .device = PCI_CHIP_SAVAGE4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_S3, + .device = PCI_CHIP_SAVAGE2000, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id) { - MOD_INC_USE_COUNT; + config_s4(dev); + return i2c_bit_add_bus(&savage4_i2c_adapter); } -void savage4_dec(struct i2c_adapter *adapter) +static void __devexit savage4_remove(struct pci_dev *dev) { - MOD_DEC_USE_COUNT; + i2c_bit_del_bus(&savage4_i2c_adapter); } -int __init i2c_savage4_init(void) + +/* Don't register driver to avoid driver conflicts */ +/* +static struct pci_driver savage4_driver = { + .name = "savage4 smbus", + .id_table = savage4_ids, + .probe = savage4_probe, + .remove = __devexit_p(savage4_remove), +}; +*/ + +static int __init i2c_savage4_init(void) { - int res; + struct pci_dev *dev; + const struct pci_device_id *id; + printk("i2c-savage4.o version %s (%s)\n", LM_VERSION, LM_DATE); - savage4_initialized = 0; - if ((res = savage4_setup())) { - printk - ("i2c-savage4.o: Savage4 not detected, module not inserted.\n"); - savage4_cleanup(); - return res; - } - if ((res = i2c_bit_add_bus(&savage4_i2c_adapter))) { - printk("i2c-savage4.o: I2C adapter registration failed\n"); - } else { - printk("i2c-savage4.o: I2C bus initialized\n"); - savage4_initialized |= INIT2; - } /* - if ((res = i2c_bit_add_bus(&savage4_ddc_adapter))) { - printk("i2c-savage4.o: DDC adapter registration failed\n"); - } else { - printk("i2c-savage4.o: DDC bus initialized\n"); - savage4_initialized |= INIT3; - } + return pci_module_init(&savage4_driver); */ - if(!(savage4_initialized & (INIT2 /* | INIT3 */ ))) { - printk("i2c-savage4.o: Both registrations failed, module not inserted\n"); - savage4_cleanup(); - return res; + pci_for_each_dev(dev) { + id = pci_match_device(savage4_ids, dev); + if(id) + if(savage4_probe(dev, id) >= 0) + return 0; } - return 0; + return -ENODEV; } -int __init savage4_cleanup(void) +static void __exit i2c_savage4_exit(void) { - int res; - - iounmap(mem); /* - if (savage4_initialized & INIT3) { - if ((res = i2c_bit_del_bus(&savage4_ddc_adapter))) { - printk - ("i2c-savage4.o: i2c_bit_del_bus failed, module not removed\n"); - return res; - } - } + pci_unregister_driver(&savage4_driver); */ - if (savage4_initialized & INIT2) { - if ((res = i2c_bit_del_bus(&savage4_i2c_adapter))) { - printk - ("i2c-savage4.o: i2c_bit_del_bus failed, module not removed\n"); - return res; - } - } - return 0; + savage4_remove(NULL); + iounmap(mem); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , Ralph Metzler , and Mark D. Studebaker "); MODULE_DESCRIPTION("Savage4 I2C/SMBus driver"); - -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return i2c_savage4_init(); -} - -int cleanup_module(void) -{ - return savage4_cleanup(); -} -#endif /* MODULE */ +module_init(i2c_savage4_init); +module_exit(i2c_savage4_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-sis5595.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-sis5595.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-sis5595.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-sis5595.c 2003-08-17 21:26:58.000000000 +0200 @@ -40,8 +40,14 @@ 5598 0008 5597/5598 630 0008 0630 645 0008 0645 + 646 0008 0646 + 648 0008 0648 + 650 0008 0650 + 651 0008 0651 730 0008 0730 735 0008 0735 + 745 0008 0745 + 746 0008 0746 */ /* TO DO: @@ -49,38 +55,19 @@ * Add adapter resets */ -#include #include #include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#ifndef PCI_DEVICE_ID_SI_540 -#define PCI_DEVICE_ID_SI_540 0x0540 -#endif -#ifndef PCI_DEVICE_ID_SI_550 -#define PCI_DEVICE_ID_SI_550 0x0550 -#endif -#ifndef PCI_DEVICE_ID_SI_630 -#define PCI_DEVICE_ID_SI_630 0x0630 -#endif -#ifndef PCI_DEVICE_ID_SI_730 -#define PCI_DEVICE_ID_SI_730 0x0730 -#endif -#ifndef PCI_DEVICE_ID_SI_5598 -#define PCI_DEVICE_ID_SI_5598 0x5598 -#endif static int blacklist[] = { PCI_DEVICE_ID_SI_540, @@ -93,8 +80,14 @@ static int blacklist[] = { PCI_DEVICE_ID_SI_5597, PCI_DEVICE_ID_SI_5598, 0x645, + 0x646, + 0x648, + 0x650, + 0x651, 0x735, - 0 }; + 0x745, + 0x746, + 0 }; /* Length of ISA address segment */ #define SIS5595_EXTENT 8 @@ -139,52 +132,9 @@ MODULE_PARM(force_addr, "i"); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_sis5595_init(void); -static int __init sis5595_cleanup(void); -static int sis5595_setup(void); -static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data); static void sis5595_do_pause(unsigned int amount); static int sis5595_transaction(void); -static void sis5595_inc(struct i2c_adapter *adapter); -static void sis5595_dec(struct i2c_adapter *adapter); -static u32 sis5595_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ sis5595_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ sis5595_func, -}; -static struct i2c_adapter sis5595_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS5595, - &smbus_algorithm, - NULL, - sis5595_inc, - sis5595_dec, - NULL, - NULL, -}; - -static int __initdata sis5595_initialized; static unsigned short sis5595_base = 0; static u8 sis5595_read(u8 reg) @@ -204,28 +154,12 @@ static void sis5595_write(u8 reg, u8 dat Note the differences between kernels with the old PCI BIOS interface and newer kernels with the real PCI interface. In compat.h some things are defined to make the transition easier. */ -int sis5595_setup(void) +int sis5595_setup(struct pci_dev *SIS5595_dev) { u16 a; u8 val; - struct pci_dev *SIS5595_dev; int *i; - /* First check whether we can access PCI at all */ - if (pci_present() == 0) { - printk("i2c-sis5595.o: Error: No PCI-bus found!\n"); - return -ENODEV; - } - - /* Look for the SIS5595 */ - SIS5595_dev = NULL; - if (!(SIS5595_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_503, - SIS5595_dev))) { - printk("i2c-sis5595.o: Error: Can't detect SIS5595!\n"); - return -ENODEV; - } - /* Look for imposters */ for(i = blacklist; *i != 0; i++) { if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) { @@ -430,10 +364,16 @@ s32 sis5595_access(struct i2c_adapter * I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA; break; +/* case I2C_SMBUS_BLOCK_DATA: printk("sis5595.o: Block data not yet implemented!\n"); return -1; break; +*/ + default: + printk + (KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size); + return -1; } sis5595_write(SMB_CTL_LO, ((size & 0x0E))); @@ -463,16 +403,6 @@ s32 sis5595_access(struct i2c_adapter * return 0; } -void sis5595_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void sis5595_dec(struct i2c_adapter *adapter) -{ - - MOD_DEC_USE_COUNT; -} u32 sis5595_func(struct i2c_adapter *adapter) { @@ -481,72 +411,79 @@ u32 sis5595_func(struct i2c_adapter *ada I2C_FUNC_SMBUS_PROC_CALL; } -int __init i2c_sis5595_init(void) + +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = sis5595_access, + .functionality = sis5595_func, +}; + +static struct i2c_adapter sis5595_adapter = { + .owner = THIS_MODULE, + .name = "unset", + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS5595, + .algo = &smbus_algorithm, +}; + + +static struct pci_device_id sis5595_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_503, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int res; - printk("i2c-sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (sis5595_initialized) { - printk - ("i2c-sis5595.o: Oops, sis5595_init called a second time!\n"); - return -EBUSY; - } -#endif - sis5595_initialized = 0; - if ((res = sis5595_setup())) { + + if (sis5595_setup(dev)) { printk ("i2c-sis5595.o: SIS5595 not detected, module not inserted.\n"); - sis5595_cleanup(); - return res; + + return -ENODEV; } - sis5595_initialized++; + sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX); - if ((res = i2c_add_adapter(&sis5595_adapter))) { - printk - ("i2c-sis5595.o: Adapter registration failed, module not inserted.\n"); - sis5595_cleanup(); - return res; - } - sis5595_initialized++; - printk("i2c-sis5595.o: SIS5595 bus detected and initialized\n"); + i2c_add_adapter(&sis5595_adapter); + return 0; } -int __init sis5595_cleanup(void) +static void __devexit sis5595_remove(struct pci_dev *dev) { - int res; - if (sis5595_initialized >= 2) { - if ((res = i2c_del_adapter(&sis5595_adapter))) { - printk - ("i2c-sis5595.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - sis5595_initialized--; - } - if (sis5595_initialized >= 1) { - release_region(sis5595_base + SMB_INDEX, 2); - sis5595_initialized--; - } - return 0; + i2c_del_adapter(&sis5595_adapter); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("SIS5595 SMBus driver"); +static struct pci_driver sis5595_driver = { + .name = "sis5595 smbus", + .id_table = sis5595_ids, + .probe = sis5595_probe, + .remove = __devexit_p(sis5595_remove), +}; -int init_module(void) +static int __init i2c_sis5595_init(void) { - return i2c_sis5595_init(); + printk("i2c-sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&sis5595_driver); } -int cleanup_module(void) + +static void __exit i2c_sis5595_exit(void) { - return sis5595_cleanup(); + pci_unregister_driver(&sis5595_driver); + release_region(sis5595_base + SMB_INDEX, 2); } -#endif /* MODULE */ + + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("SIS5595 SMBus driver"); + +module_init(i2c_sis5595_init); +module_exit(i2c_sis5595_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-sis630.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-sis630.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-sis630.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-sis630.c 2003-08-17 21:26:58.000000000 +0200 @@ -48,34 +48,17 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include -#include #include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include - -#ifndef PCI_VENDOR_ID_SI -#define PCI_VENDOR_ID_SI 0x1039 -#endif - -#ifndef PCI_DEVICE_ID_SI_630 -#define PCI_DEVICE_ID_SI_630 0x0630 -#endif - -#ifndef PCI_DEVICE_ID_SI_730 -#define PCI_DEVICE_ID_SI_730 0x0730 -#endif - -#ifndef PCI_DEVICE_ID_SI_503 -#define PCI_DEVICE_ID_SI_503 0x0008 -#endif +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" struct sd { const unsigned short mfr; @@ -84,14 +67,6 @@ struct sd { const char *name; }; -/* supported chips */ -static struct sd supported[] = { - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, 0, "SIS630"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730, 0, "SIS730"}, - {0, 0, 0, NULL} -}; - - /* SIS630 SMBus registers */ #define SMB_STS 0x80 /* status */ #define SMB_EN 0x81 /* status enable */ @@ -131,59 +106,24 @@ static struct sd supported[] = { /* If force is set to anything different from 0, we forcibly enable the SIS630. DANGEROUS! */ -static int force = 0; static int high_clock = 0; +/* +static int force = 0; MODULE_PARM(force, "i"); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); +*/ MODULE_PARM(high_clock, "i"); MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); - -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_sis630_init(void); -static int __init i2c_sis630_cleanup(void); -static int sis630_setup(void); -static s32 sis630_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data); static void sis630_do_pause(unsigned int amount); static int sis630_transaction(int size); -static void sis630_inc(struct i2c_adapter *adapter); -static void sis630_dec(struct i2c_adapter *adapter); -static u32 sis630_func(struct i2c_adapter *adapter); + static u8 sis630_read(u8 reg); static void sis630_write(u8 reg, u8 data); -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ sis630_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ sis630_func, -}; - -static struct i2c_adapter sis630_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS630, - &smbus_algorithm, - NULL, - sis630_inc, - sis630_dec, - NULL, - NULL, -}; - static unsigned short acpi_base = 0; -static int __initdata sis630_initialized; + u8 sis630_read(u8 reg) { return inb(acpi_base + reg); @@ -306,7 +246,8 @@ int sis630_transaction(int size) { /* Return -1 on error. */ s32 sis630_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) { + u8 command, int size, union i2c_smbus_data * data) +{ switch (size) { case I2C_SMBUS_QUICK: @@ -375,55 +316,14 @@ s32 sis630_access(struct i2c_adapter * a return 0; } -void sis630_inc(struct i2c_adapter *adapter) { - MOD_INC_USE_COUNT; -} - -void sis630_dec(struct i2c_adapter *adapter) { - MOD_DEC_USE_COUNT; -} u32 sis630_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL; } -int sis630_setup(void) { +int sis630_setup(struct pci_dev *sis630_dev) { unsigned char b; - struct pci_dev *sis630_dev = NULL,*tmp = NULL; - struct sd *en = supported; - - /* First check whether we can access PCI at all */ - if (pci_present() == 0) { - printk("i2c-sis630.o: Error: No PCI-bus found!\n"); - return -ENODEV; - } - - /* Look for the SIS630 and compatible */ - if (!(sis630_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_503, - sis630_dev))) { - printk(KERN_ERR "i2c-sis630.o: Error: Can't detect 85C503/5513 ISA bridge!\n"); - return -ENODEV; - } - do { - if ((tmp = pci_find_device(en->mfr,en->dev,NULL))) { - if (PCI_FUNC(tmp->devfn) != en->fn) - continue; - - break; - } - en++; - } - while(en->mfr); - if (tmp == NULL && force == 0 ) { - printk(KERN_ERR "i2c-sis630.o: Error: Can't detect SIS630 compatible device!\n"); - return -ENODEV; - } - else if (tmp == NULL && force > 0) { - printk(KERN_NOTICE "i2c-sis630.o: WARNING: Can't detect SIS630 compatible device, but " - "loading because of force option enabled\n"); - } /* Enable ACPI first , so we can accsess reg 74-75 @@ -453,88 +353,94 @@ int sis630_setup(void) { #endif /* Everything is happy, let's grab the memory and set things up. */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,14) if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, "sis630-smbus")){ printk(KERN_ERR "i2c-sis630.o: SMBus registers 0x%04x-0x%04x " "already in use!\n",acpi_base + SMB_STS, acpi_base + SMB_SAA); return -ENODEV; } -#else - if (check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION) < 0){ - printk(KERN_ERR "i2c-sis630.o: SMBus registers 0x%04x-0x%04x " - "already in use!\n",acpi_base + SMB_STS, acpi_base + SMB_SAA); - return -ENODEV; - } - request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, "sis630-smbus"); -#endif return 0; } -int __init i2c_sis630_init(void) { - int res; - printk("i2c-sis630.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (sis630_initialized) { - printk(KERN_ERR "i2c-sis630.o: Oops, sis630_init called a second time!\n"); - return -EBUSY; - } +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = sis630_access, + .functionality = sis630_func, +}; - sis630_initialized = 0; - if ((res = sis630_setup())) { +static struct i2c_adapter sis630_adapter = { + .owner = THIS_MODULE, + .name = "unset", + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS630, + .algo = &smbus_algorithm, +}; + + +static struct pci_device_id sis630_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_630, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_730, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + + if (sis630_setup(dev)) { printk(KERN_ERR "i2c-sis630.o: SIS630 comp. bus not detected, module not inserted.\n"); - i2c_sis630_cleanup(); - return res; + + return -ENODEV; } - sis630_initialized++; + sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS); - if ((res = i2c_add_adapter(&sis630_adapter))) { - printk(KERN_ERR "i2c-sis630.o: Adapter registration failed, " - "module not inserted.\n"); - i2c_sis630_cleanup(); - return res; - } - sis630_initialized++; - printk(KERN_INFO "i2c-sis630.o: SIS630 comp. bus detected and initialized\n"); + return i2c_add_adapter(&sis630_adapter); +} - return 0; +static void __devexit sis630_remove(struct pci_dev *dev) +{ + i2c_del_adapter(&sis630_adapter); } -int __init i2c_sis630_cleanup(void) { - int res; - if (sis630_initialized >= 2) { - if ((res = i2c_del_adapter(&sis630_adapter))) { - printk(KERN_ERR "i2c-sis630.o: i2c_del_adapter failed, module not" - "removed\n"); - return res; - } else - sis630_initialized--; - } - if (sis630_initialized >= 1) { - release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION); - sis630_initialized--; - } - return 0; + +static struct pci_driver sis630_driver = { + .name = "sis630 smbus", + .id_table = sis630_ids, + .probe = sis630_probe, + .remove = __devexit_p(sis630_remove), +}; + +static int __init i2c_sis630_init(void) +{ + printk("i2c-sis630.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&sis630_driver); } -EXPORT_NO_SYMBOLS; +static void __exit i2c_sis630_exit(void) +{ + pci_unregister_driver(&sis630_driver); + release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION); +} + + + -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif -#ifdef MODULE MODULE_AUTHOR("Alexander Malysh "); MODULE_DESCRIPTION("SIS630 SMBus driver"); -int init_module(void) { - return i2c_sis630_init(); -} - -int cleanup_module(void) { - return i2c_sis630_cleanup(); -} - -#endif /* MODULE */ +module_init(i2c_sis630_init); +module_exit(i2c_sis630_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-sis645.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-sis645.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-sis645.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-sis645.c 2003-08-17 21:26:58.000000000 +0200 @@ -2,7 +2,7 @@ sis645.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (c) 2002 Mark M. Hoffman + Copyright (c) 2003 Mark M. Hoffman 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 @@ -34,43 +34,51 @@ Note: we assume there can only be one SiS645 with one SMBus interface */ -#include +/* #define DEBUG 1 */ + #include #include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -/* PCI identifiers */ - -/* SiS645 north bridge */ -#ifndef PCI_DEVICE_ID_SI_645 -#define PCI_DEVICE_ID_SI_645 0x0645 -#endif +#define DRV_NAME "i2c-sis645" -/* SiS645DX north bridge */ +/* SiS645DX north bridge (defined in 2.4.21) */ #ifndef PCI_DEVICE_ID_SI_646 #define PCI_DEVICE_ID_SI_646 0x0646 #endif -/* SiS650 north bridge */ +/* SiS648 north bridge (defined in 2.4.21) */ +#ifndef PCI_DEVICE_ID_SI_648 +#define PCI_DEVICE_ID_SI_648 0x0648 +#endif + +/* SiS650 north bridge (defined in 2.4.19) */ #ifndef PCI_DEVICE_ID_SI_650 #define PCI_DEVICE_ID_SI_650 0x0650 #endif -/* SiS735 combo chipset */ -#ifndef PCI_DEVICE_ID_SI_735 -#define PCI_DEVICE_ID_SI_735 0x0735 +/* SiS651 north bridge (defined in 2.4.21)*/ +#ifndef PCI_DEVICE_ID_SI_651 +#define PCI_DEVICE_ID_SI_651 0x0651 +#endif + +/* SiS746 north bridge (defined in 2.4.21) */ +#ifndef PCI_DEVICE_ID_SI_746 +#define PCI_DEVICE_ID_SI_746 0x0746 +#endif + +/* SiS85C503/5513 (LPC Bridge) */ +#ifndef PCI_DEVICE_ID_SI_LPC +#define PCI_DEVICE_ID_SI_LPC 0x0018 #endif /* SiS961 south bridge */ @@ -78,10 +86,23 @@ MODULE_LICENSE("GPL"); #define PCI_DEVICE_ID_SI_961 0x0961 #endif +/* SiS962 south bridge */ +#ifndef PCI_DEVICE_ID_SI_962 +#define PCI_DEVICE_ID_SI_962 0x0962 +#endif + +/* SiS963 south bridge */ +#ifndef PCI_DEVICE_ID_SI_963 +#define PCI_DEVICE_ID_SI_963 0x0963 +#endif + +/* SMBus ID */ +#ifndef PCI_DEVICE_ID_SI_SMBUS #define PCI_DEVICE_ID_SI_SMBUS 0x16 +#endif /* base address register in PCI config space */ -#define BASE_IO_REG 0x04 +#define SIS645_BAR 0x04 /* SiS645 SMBus registers */ #define SMB_STS 0x00 @@ -112,47 +133,11 @@ MODULE_LICENSE("GPL"); #define SIS645_PROC_CALL 0x04 #define SIS645_BLOCK_DATA 0x05 - -static int __init sis645_init(void); -static void sis645_cleanup(void); - -static int sis645_enable_smbus(struct pci_dev *dev); -static int sis645_build_dev(struct pci_dev **smbus_dev, - struct pci_dev *bridge_dev); -static int sis645_setup(void); -static s32 sis645_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data); static void sis645_do_pause(unsigned int amount); static int sis645_transaction(int size); -static void sis645_inc(struct i2c_adapter *adapter); -static void sis645_dec(struct i2c_adapter *adapter); -static u32 sis645_func(struct i2c_adapter *adapter); -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ sis645_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ sis645_func, -}; - -static struct i2c_adapter sis645_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS645, - &smbus_algorithm, - NULL, - sis645_inc, - sis645_dec, - NULL, - NULL, -}; +static struct i2c_adapter sis645_adapter; -static int sis645_initialized; static unsigned short sis645_smbus_base = 0; static u8 sis645_read(u8 reg) @@ -169,14 +154,14 @@ static void sis645_write(u8 reg, u8 data /* Turns on SMBus device if it is not; return 0 iff successful */ -static int sis645_enable_smbus(struct pci_dev *dev) +static int __devinit sis645_enable_smbus(struct pci_dev *dev) { u8 val = 0; pci_read_config_byte(dev, 0x77, &val); #ifdef DEBUG - printk("i2c-sis645.o: Config byte was 0x%02x.\n", val); + printk(KERN_DEBUG DRV_NAME ": Config byte was 0x%02x.\n", val); #endif pci_write_config_byte(dev, 0x77, val & ~0x10); @@ -185,7 +170,7 @@ static int sis645_enable_smbus(struct pc if (val & 0x10) { #ifdef DEBUG - printk("i2c-sis645.o: Error: Config byte stuck!\n"); + printk(KERN_DEBUG DRV_NAME ": Config byte stuck!\n"); #endif return -1; } @@ -195,7 +180,7 @@ static int sis645_enable_smbus(struct pc /* Builds the basic pci_dev for SiS645 SMBus */ -static int sis645_build_dev(struct pci_dev **smbus_dev, +static int __devinit sis645_build_dev(struct pci_dev **smbus_dev, struct pci_dev *bridge_dev) { struct pci_dev temp_dev; @@ -214,14 +199,14 @@ static int sis645_build_dev(struct pci_d /* query to make sure */ ret = pci_read_config_word(&temp_dev, PCI_VENDOR_ID, &vid); if (ret || PCI_VENDOR_ID_SI != vid) { - printk("i2c-sis645.o: Couldn't find SMBus device!\n"); + printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n"); return ret; } temp_dev.vendor = vid; ret = pci_read_config_word(&temp_dev, PCI_DEVICE_ID, &did); if (ret || PCI_DEVICE_ID_SI_SMBUS != did) { - printk("i2c-sis645.o: Couldn't find SMBus device!\n"); + printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n"); return ret; } temp_dev.device = did; @@ -229,7 +214,7 @@ static int sis645_build_dev(struct pci_d /* ok, we've got it... request some memory and finish it off */ *smbus_dev = kmalloc(sizeof(**smbus_dev), GFP_ATOMIC); if (NULL == *smbus_dev) { - printk("i2c-sis645.o: Error: Out of memory!\n"); + printk(KERN_ERR DRV_NAME ": Out of memory!\n"); return -ENOMEM; } @@ -237,7 +222,7 @@ static int sis645_build_dev(struct pci_d ret = pci_setup_device(*smbus_dev); if (ret) { - printk("i2c-sis645.o: pci_setup_device failed (0x%08x)\n",ret); + printk(KERN_ERR DRV_NAME ": pci_setup_device failed (0x%08x)\n",ret); } return ret; } @@ -246,26 +231,32 @@ static int sis645_build_dev(struct pci_d /* Detect whether a SiS645 can be found, and initialize it, where necessary. */ -static int sis645_setup(void) +static int __devinit sis645_probe(struct pci_dev *dev, const struct pci_device_id *id) { - struct pci_dev *SIS645_ISA_dev; struct pci_dev *SIS645_SMBUS_dev; - int ret; u16 ww = 0; - if (pci_present() == 0) { - printk("i2c-sis645.o: Error: No PCI-bus found!\n"); - return -ENODEV; + if (sis645_smbus_base) { + printk(KERN_ERR DRV_NAME ": Only one device supported.\n"); + return -EBUSY; } - if (SIS645_ISA_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_961, NULL)) { - printk("i2c-sis645.o: Found SiS961 south bridge.\n"); - } + switch (dev->device) { + case PCI_DEVICE_ID_SI_961: + printk(KERN_INFO DRV_NAME ": Found SiS961 south bridge.\n"); + break; - else if (SIS645_ISA_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_503, NULL)) { - printk("i2c-sis645.o: Found SiS south bridge in compatability mode(?)\n"); + case PCI_DEVICE_ID_SI_962: + printk(KERN_INFO DRV_NAME ": Found SiS962 [MuTIOL Media IO].\n"); + break; + + case PCI_DEVICE_ID_SI_963: + printk(KERN_INFO DRV_NAME ": Found SiS963 [MuTIOL Media IO].\n"); + break; + + case PCI_DEVICE_ID_SI_503: + case PCI_DEVICE_ID_SI_LPC: + printk(KERN_INFO DRV_NAME ": Found SiS south bridge in compatability mode(?)\n"); /* look for known compatible north bridges */ if ((NULL == pci_find_device(PCI_VENDOR_ID_SI, @@ -273,41 +264,53 @@ static int sis645_setup(void) && (NULL == pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, NULL)) && (NULL == pci_find_device(PCI_VENDOR_ID_SI, + PCI_DEVICE_ID_SI_648, NULL)) + && (NULL == pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, NULL)) && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_735, NULL))) { - printk("i2c-sis645.o: Error: Can't find suitable host bridge!\n"); + PCI_DEVICE_ID_SI_651, NULL)) + && (NULL == pci_find_device(PCI_VENDOR_ID_SI, + PCI_DEVICE_ID_SI_735, NULL)) + && (NULL == pci_find_device(PCI_VENDOR_ID_SI, + PCI_DEVICE_ID_SI_745, NULL)) + && (NULL == pci_find_device(PCI_VENDOR_ID_SI, + PCI_DEVICE_ID_SI_746, NULL))) { + printk(KERN_ERR DRV_NAME ": Can't find suitable host bridge!\n"); return -ENODEV; } - } + break ; - else { - printk("i2c-sis645.o: Error: Can't find suitable south bridge!\n"); + default: + printk(KERN_ERR DRV_NAME ": Can't find suitable south bridge!\n"); return -ENODEV; } if (!(SIS645_SMBUS_dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS, NULL))) { - printk("i2c-sis645.o: " +#ifdef CONFIG_HOTPLUG + int ret; +#endif + + printk(KERN_INFO DRV_NAME ": " "Attempting to enable SiS645 SMBus device\n"); #ifndef CONFIG_HOTPLUG - printk("i2c-sis645.o: " + printk(KERN_INFO DRV_NAME ": " "Requires kernel >= 2.4 with CONFIG_HOTPLUG, sorry!\n"); return -ENODEV; #else /* CONFIG_HOTPLUG */ - if (ret = sis645_enable_smbus(SIS645_ISA_dev)) { + if ((ret = sis645_enable_smbus(dev))) { return ret; } - if (ret = sis645_build_dev(&SIS645_SMBUS_dev, SIS645_ISA_dev)) { + if ((ret = sis645_build_dev(&SIS645_SMBUS_dev, dev))) { return ret; } - if (ret = pci_enable_device(SIS645_SMBUS_dev)) { - printk("i2c-sis645.o: Can't pci_enable SMBus device!" + if ((ret = pci_enable_device(SIS645_SMBUS_dev))) { + printk(KERN_ERR DRV_NAME ": Can't pci_enable SMBus device!" " (0x%08x)\n", ret); return ret; } @@ -320,44 +323,31 @@ static int sis645_setup(void) pci_read_config_word(SIS645_SMBUS_dev, PCI_CLASS_DEVICE, &ww); if (PCI_CLASS_SERIAL_SMBUS != ww) { - printk("i2c-sis645.o: Error: Unsupported device class 0x%04x!\n", ww); + printk(KERN_ERR DRV_NAME ": Unsupported device class 0x%04x!\n", ww); return -ENODEV; } /* get the IO base address */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) - sis645_smbus_base = SIS645_SMBUS_dev->resource[BASE_IO_REG].start; -#else - sis645_smbus_base = SIS645_SMBUS_dev->base_address[BASE_IO_REG]; -#endif + sis645_smbus_base = pci_resource_start(SIS645_SMBUS_dev, SIS645_BAR); if (!sis645_smbus_base) { - printk("i2c-sis645.o: SiS645 SMBus base address not initialized!\n"); + printk(KERN_ERR DRV_NAME ": SiS645 SMBus base address not initialized!\n"); return -EINVAL; } - printk("i2c-sis645.o: SiS645 SMBus base address: 0x%04x\n", sis645_smbus_base); + printk(KERN_INFO DRV_NAME ": SiS645 SMBus base address: 0x%04x\n", sis645_smbus_base); /* Everything is happy, let's grab the memory and set things up. */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,14) if (!request_region(sis645_smbus_base, SIS645_SMB_IOREGION, "sis645-smbus")) { - printk - ("i2c-sis645.o: SMBus registers 0x%04x-0x%04x already in use!\n", + printk(KERN_ERR DRV_NAME ": SMBus registers 0x%04x-0x%04x already in use!\n", sis645_smbus_base, sis645_smbus_base + SIS645_SMB_IOREGION - 1); return -EINVAL; } -#else - if (check_region(sis645_smbus_base, SIS645_SMB_IOREGION) < 0) { - printk - ("i2c-sis645.o: SMBus registers 0x%04x-0x%04x already in use!\n", - sis645_smbus_base, sis645_smbus_base + SIS645_SMB_IOREGION - 1); - return -EINVAL; - } - request_region(sis645_smbus_base, SIS645_SMB_IOREGION, "sis645-smbus"); -#endif + + sprintf(sis645_adapter.name, "SMBus SiS645 adapter at 0x%04x", sis645_smbus_base); + i2c_add_adapter(&sis645_adapter); return(0); } - /* Internally used pause function */ static void sis645_do_pause(unsigned int amount) { @@ -377,7 +367,7 @@ static int sis645_transaction(int size) /* Make sure the SMBus host is ready to start transmitting */ if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) { #ifdef DEBUG - printk("i2c-sis645.o: SMBus busy (0x%02x). Resetting...\n", + printk(KERN_DEBUG DRV_NAME ": SMBus busy (0x%02x). Resetting...\n", temp); #endif @@ -387,12 +377,12 @@ static int sis645_transaction(int size) /* check it again */ if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) { #ifdef DEBUG - printk("i2c-sis645.o: Failed! (0x%02x)\n", temp); + printk(KERN_DEBUG DRV_NAME ": Failed! (0x%02x)\n", temp); #endif return -1; } else { #ifdef DEBUG - printk("i2c-sis645.o: Successful!\n"); + printk(KERN_DEBUG DRV_NAME ": Successful!\n"); #endif } } @@ -415,14 +405,14 @@ static int sis645_transaction(int size) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { - printk("i2c-sis645.o: SMBus Timeout! (0x%02x)\n",temp); + printk(KERN_DEBUG DRV_NAME ": SMBus Timeout! (0x%02x)\n",temp); result = -1; } /* device error - probably missing ACK */ if (temp & 0x02) { #ifdef DEBUG - printk("i2c-sis645.o: Error: Failed bus transaction!\n"); + printk(KERN_DEBUG DRV_NAME ": Failed bus transaction!\n"); #endif result = -1; } @@ -430,16 +420,16 @@ static int sis645_transaction(int size) /* bus collision */ if (temp & 0x04) { #ifdef DEBUG - printk("i2c-sis645.o: Error: Bus collision!\n"); + printk(KERN_DEBUG DRV_NAME ": Bus collision!\n"); #endif result = -1; } /* Finish up by resetting the bus */ sis645_write(SMB_STS, temp); - if (temp = sis645_read(SMB_STS)) { + if ((temp = sis645_read(SMB_STS))) { #ifdef DEBUG - printk("i2c-sis645.o: Failed reset at end of transaction!" + printk(KERN_DEBUG DRV_NAME ": Failed reset at end of transaction!" " (0x%02x)\n", temp); #endif } @@ -487,12 +477,12 @@ s32 sis645_access(struct i2c_adapter * a case I2C_SMBUS_BLOCK_DATA: /* TO DO: */ - printk("sis645.o: SMBus block not implemented!\n"); + printk(KERN_INFO DRV_NAME ": SMBus block not implemented!\n"); return -1; break; default: - printk("sis645.o: unsupported I2C size\n"); + printk(KERN_INFO DRV_NAME ": Unsupported I2C size\n"); return -1; break; } @@ -519,15 +509,6 @@ s32 sis645_access(struct i2c_adapter * a return 0; } -static void sis645_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -static void sis645_dec(struct i2c_adapter *adapter) -{ - MOD_DEC_USE_COUNT; -} static u32 sis645_func(struct i2c_adapter *adapter) { @@ -536,62 +517,66 @@ static u32 sis645_func(struct i2c_adapte I2C_FUNC_SMBUS_PROC_CALL; } -static int __init sis645_init(void) -{ - int res; - printk("i2c-sis645.o: version %s (%s)\n", LM_VERSION, LM_DATE); - if (sis645_initialized) { - printk("i2c-sis645.o: Oops, sis645_init called a second time!\n"); - return -EBUSY; - } +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = sis645_access, + .functionality = sis645_func, +}; - sis645_initialized = 0; - if ((res = sis645_setup())) { - printk ("i2c-sis645.o: SiS645 not detected, module not inserted.\n"); - sis645_cleanup(); - return res; - } +static struct i2c_adapter sis645_adapter = { + .owner = THIS_MODULE, + .name = "unset", + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS645, + .algo = &smbus_algorithm, +}; - sis645_initialized++; - sprintf(sis645_adapter.name, "SMBus SiS645 adapter at 0x%04x", sis645_smbus_base); - if ((res = i2c_add_adapter(&sis645_adapter))) { - printk ("i2c-sis645.o: Adapter registration failed, module not inserted.\n"); - sis645_cleanup(); - return res; - } - sis645_initialized++; - printk("i2c-sis645.o: SiS645 bus detected and initialized.\n"); - return 0; +static struct pci_device_id sis645_ids[] __devinitdata = { + + /* look for these south bridges */ + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, PCI_ANY_ID, PCI_ANY_ID, }, + + { 0, } +}; + +static void __devexit sis645_remove(struct pci_dev *dev) +{ + i2c_del_adapter(&sis645_adapter); } -static void sis645_cleanup(void) + +static struct pci_driver sis645_driver = { + .name = "sis645 smbus", + .id_table = sis645_ids, + .probe = sis645_probe, + .remove = __devexit_p(sis645_remove), +}; + +static int __init i2c_sis645_init(void) { - int res; - if (sis645_initialized >= 2) { - if ((res = i2c_del_adapter(&sis645_adapter))) { - printk("i2c-sis645.o: i2c_del_adapter failed, module not removed\n"); - return; - } else - sis645_initialized--; - } - if (sis645_initialized >= 1) { - release_region(sis645_smbus_base, SIS645_SMB_IOREGION); - sis645_initialized--; - } - return; + printk(KERN_INFO DRV_NAME ".o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&sis645_driver); } -EXPORT_NO_SYMBOLS; -/* Register initialization functions using helper macros */ -module_init(sis645_init); -module_exit(sis645_cleanup); +static void __exit i2c_sis645_exit(void) +{ + pci_unregister_driver(&sis645_driver); + release_region(sis645_smbus_base, SIS645_SMB_IOREGION); +} + -#ifdef MODULE MODULE_AUTHOR("Mark M. Hoffman "); MODULE_DESCRIPTION("SiS645 SMBus driver"); +MODULE_LICENSE("GPL"); -#endif +/* Register initialization functions using helper macros */ +module_init(i2c_sis645_init); +module_exit(i2c_sis645_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-tsunami.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-tsunami.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-tsunami.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-tsunami.c 2003-08-17 21:26:58.000000000 +0200 @@ -29,20 +29,17 @@ Order Number: DS-0025-TE */ -#include #include -#include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif /* Memory Presence Detect Register (MPD-RW) bits with except of reserved RAZ bits */ @@ -52,28 +49,13 @@ MODULE_LICENSE("GPL"); #define MPD_DS 0x2 /* Data send - Must be a 1 to receive - WO */ #define MPD_CKS 0x1 /* Clock send - WO */ -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_tsunami_init(void); -static int __init i2c_tsunami_cleanup(void); -static void i2c_tsunami_inc(struct i2c_adapter *adapter); -static void i2c_tsunami_dec(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -extern inline void writempd(unsigned long value) +static inline void writempd(unsigned long value) { TSUNAMI_cchip->mpd.csr = value; mb(); } -extern inline unsigned long readmpd(void) +static inline unsigned long readmpd(void) { return TSUNAMI_cchip->mpd.csr; } @@ -119,7 +101,7 @@ static int bit_tsunami_getsda(void *data } static struct i2c_algo_bit_data tsunami_i2c_bit_data = { - NULL, + bit_tsunami_setsda, bit_tsunami_setscl, bit_tsunami_getsda, @@ -128,29 +110,22 @@ static struct i2c_algo_bit_data tsunami_ }; static struct i2c_adapter tsunami_i2c_adapter = { - "I2C Tsunami/Typhoon adapter", - I2C_HW_B_TSUNA, - NULL, - &tsunami_i2c_bit_data, - i2c_tsunami_inc, - i2c_tsunami_dec, - NULL, - NULL, + .owner = THIS_MODULE, + .name = "I2C Tsunami/Typhoon adapter", + .id = I2C_HW_B_TSUNA, + .algo_data = &tsunami_i2c_bit_data, }; -void i2c_tsunami_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} -void i2c_tsunami_dec(struct i2c_adapter *adapter) -{ - MOD_DEC_USE_COUNT; -} +static struct pci_driver tsunami_driver = { + .name = "tsunami smbus", + .id_table = tsunami_ids, + .probe = tsunami_probe, + .remove = __devexit_p(tsunami_remove), +}; -int __init i2c_tsunami_init(void) +static int __init i2c_tsunami_init(void) { - int res; printk("i2c-tsunami.o version %s (%s)\n", LM_VERSION, LM_DATE); if (hwrpb->sys_type != ST_DEC_TSUNAMI) { @@ -159,43 +134,19 @@ int __init i2c_tsunami_init(void) } else { printk("i2c-tsunami.o: using Cchip MPD at 0x%lx.\n", &TSUNAMI_cchip->mpd); } - - if ((res = i2c_bit_add_bus(&tsunami_i2c_adapter))) { - printk("i2c-tsunami.o: I2C adapter registration failed\n"); - } else { - printk("i2c-tsunami.o: I2C bus initialized\n"); - } - - return res; + i2c_bit_add_bus(&tsunami_i2c_adapter); } -int __init i2c_tsunami_cleanup(void) -{ - int res; - if ((res = i2c_bit_del_bus(&tsunami_i2c_adapter))) { - printk("i2c-tsunami.o: i2c_bit_del_bus failed, module not removed\n"); - return res; - } - - return 0; +static void __exit i2c_tsunami_exit(void) +{ + i2c_bit_del_bus(&tsunami_i2c_adapter); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Oleg I. Vdovikin "); MODULE_DESCRIPTION("Tsunami I2C/SMBus driver"); -int init_module(void) -{ - return i2c_tsunami_init(); -} - -int cleanup_module(void) -{ - return i2c_tsunami_cleanup(); -} - -#endif /* MODULE */ +module_init(i2c_tsunami_init); +module_exit(i2c_tsunami_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-velleman.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-velleman.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-velleman.c 2003-08-04 23:06:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-velleman.c 2003-08-17 21:26:58.000000000 +0200 @@ -18,18 +18,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-velleman.c,v 1.25 2002/11/24 05:44:15 mds Exp $ */ +/* $Id: i2c-velleman.c,v 1.26.2.2 2003/01/21 10:00:19 kmalkki Exp $ */ #include #include #include #include +#include #include -#include /* for 2.0 kernels to get NULL */ -#include /* for 2.0 kernels to get ENODEV */ -#include #include #include +#include /* ----- global defines ----------------------------------------------- */ #define DEB(x) /* should be reasonable open, close &c. */ @@ -90,75 +89,38 @@ static int bit_velle_getsda(void *data) static int bit_velle_init(void) { - if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { - DEBE(printk(KERN_DEBUG "i2c-velleman.o: Port %#x already in use.\n", - base)); + if (!request_region(base, (base == 0x3bc) ? 3 : 8, + "i2c (Vellemann adapter)")) return -ENODEV; - } else { - request_region(base, (base == 0x3bc)? 3 : 8, - "i2c (Vellemann adapter)"); - bit_velle_setsda((void*)base,1); - bit_velle_setscl((void*)base,1); - } - return 0; -} - -static void __exit bit_velle_exit(void) -{ - release_region( base , (base == 0x3bc)? 3 : 8 ); -} - - -static int bit_velle_reg(struct i2c_client *client) -{ - return 0; -} -static int bit_velle_unreg(struct i2c_client *client) -{ + bit_velle_setsda((void*)base,1); + bit_velle_setscl((void*)base,1); return 0; } -static void bit_velle_inc_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void bit_velle_dec_use(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. */ static struct i2c_algo_bit_data bit_velle_data = { - NULL, - bit_velle_setsda, - bit_velle_setscl, - bit_velle_getsda, - bit_velle_getscl, - 10, 10, HZ, /* waits, timeout */ + .setsda = bit_velle_setsda, + .setscl = bit_velle_setscl, + .getsda = bit_velle_getsda, + .getscl = bit_velle_getscl, + .udelay = 10, + .mdelay = 10, + .timeout = HZ }; static struct i2c_adapter bit_velle_ops = { - "Velleman K8000", - I2C_HW_B_VELLE, - NULL, - &bit_velle_data, - bit_velle_inc_use, - bit_velle_dec_use, - bit_velle_reg, - bit_velle_unreg, + .owner = THIS_MODULE, + .name = "Velleman K8000", + .id = I2C_HW_B_VELLE, + .algo_data = &bit_velle_data, }; -int __init i2c_bitvelle_init(void) +static int __init i2c_bitvelle_init(void) { printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { @@ -184,24 +146,17 @@ int __init i2c_bitvelle_init(void) return 0; } -EXPORT_NO_SYMBOLS; +static void __exit i2c_bitvelle_exit(void) +{ + i2c_bit_del_bus(&bit_velle_ops); + release_region(base, (base == 0x3bc) ? 3 : 8); +} -#ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); MODULE_LICENSE("GPL"); MODULE_PARM(base, "i"); -int init_module(void) -{ - return i2c_bitvelle_init(); -} - -void cleanup_module(void) -{ - i2c_bit_del_bus(&bit_velle_ops); - bit_velle_exit(); -} - -#endif +module_init(i2c_bitvelle_init); +module_exit(i2c_bitvelle_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-via.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-via.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-via.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-via.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,26 +21,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include #include -#include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -/* PCI device */ -#define VENDOR PCI_VENDOR_ID_VIA -#define DEVICE PCI_DEVICE_ID_VIA_82C586_3 +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* Power management registers */ @@ -58,21 +49,14 @@ MODULE_LICENSE("GPL"); #define IOSPACE 0x06 #define IOTEXT "via-i2c" -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) x /* silicon revision, io addresses */ -#define DEB2(x) x /* line status */ -#define DEBE(x) /* */ - -/* ----- local functions ---------------------------------------------- */ - -static u16 pm_io_base; +static u16 pm_io_base = 0; /* It does not appear from the datasheet that the GPIO pins are open drain. So a we set a low value by setting the direction to output and a high value by setting the direction to input and relying on the required I2C pullup. The data value is initialized - to 0 in i2c_via_init() and never changed. + to 0 in via_init() and never changed. */ static void bit_via_setscl(void *data, int state) @@ -97,59 +81,42 @@ static int bit_via_getsda(void *data) return (0 != (inb(I2C_IN) & I2C_SDA)); } -static void bit_via_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -static void bit_via_dec(struct i2c_adapter *adapter) -{ - MOD_DEC_USE_COUNT; -} - -/* ------------------------------------------------------------------------ */ static struct i2c_algo_bit_data bit_data = { - NULL, - bit_via_setsda, - bit_via_setscl, - bit_via_getsda, - bit_via_getscl, - 5, 5, HZ, /*waits, timeout */ + .setsda = bit_via_setsda, + .setscl = bit_via_setscl, + .getsda = bit_via_getsda, + .getscl = bit_via_getscl, + .udelay = 5, + .mdelay = 5, + .timeout = HZ }; -static struct i2c_adapter bit_via_ops = { - "VIA i2c", - I2C_HW_B_VIA, - NULL, - &bit_data, - bit_via_inc, - bit_via_dec, - NULL, - NULL, +static struct i2c_adapter vt586b_adapter = { + .owner = THIS_MODULE, + .name = "VIA i2c", + .id = I2C_HW_B_VIA, + .algo_data = &bit_data, }; -/* When exactly was the new pci interface introduced? */ -static int find_via(void) +static struct pci_device_id vt586b_ids[] __devinitdata = { + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id) { - struct pci_dev *s_bridge; u16 base; u8 rev; + int res; - if (!pci_present()) - return -ENODEV; - - s_bridge = pci_find_device(VENDOR, DEVICE, NULL); - - if (!s_bridge) { - printk("i2c-via.o: vt82c586b not found\n"); - return -ENODEV; + if (pm_io_base) { + printk(KERN_ERR "i2c-via.o: Will only support one host\n"); + return -EBUSY; } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, PM_CFG_REVID, &rev)) - return -ENODEV; + pci_read_config_byte(dev, PM_CFG_REVID, &rev); switch (rev) { case 0x00: @@ -165,62 +132,75 @@ static int find_via(void) /* later revision */ } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, base, &pm_io_base)) - return -ENODEV; - + pci_read_config_word(dev, base, &pm_io_base); pm_io_base &= (0xff << 8); + + if (! request_region(I2C_DIR, IOSPACE, IOTEXT)) { + printk("i2c-via.o: IO 0x%x-0x%x already in use\n", + I2C_DIR, I2C_DIR + IOSPACE); + return -EBUSY; + } + outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR); + outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT); + + res = i2c_bit_add_bus(&vt586b_adapter); + if ( res < 0 ) { + release_region(I2C_DIR, IOSPACE); + pm_io_base = 0; + return res; + } return 0; } -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_via_init(void) +static void __devexit vt586b_remove(struct pci_dev *dev) +{ + i2c_bit_del_bus(&vt586b_adapter); + release_region(I2C_DIR, IOSPACE); + pm_io_base = 0; +} + + +/* Don't register driver to avoid driver conflicts */ +/* +static struct pci_driver vt586b_driver = { + .name = "vt586b smbus", + .id_table = vt586b_ids, + .probe = vt586b_probe, + .remove = __devexit_p(vt586b_remove), +}; +*/ + +static int __init i2c_vt586b_init(void) { + struct pci_dev *dev; + const struct pci_device_id *id; + printk("i2c-via.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (find_via() < 0) { - printk("i2c-via.o: Error while reading PCI configuration\n"); - return -ENODEV; +/* + return pci_module_init(&vt586b_driver); +*/ + pci_for_each_dev(dev) { + id = pci_match_device(vt586b_ids, dev); + if(id) + if(vt586b_probe(dev, id) >= 0) + return 0; } + return -ENODEV; +} - if (check_region(I2C_DIR, IOSPACE) < 0) { - printk("i2c-via.o: IO 0x%x-0x%x already in use\n", - I2C_DIR, I2C_DIR + IOSPACE); - return -EBUSY; - } else { - request_region(I2C_DIR, IOSPACE, IOTEXT); - outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR); - outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT); - } - if (i2c_bit_add_bus(&bit_via_ops) == 0) { - printk("i2c-via.o: Module succesfully loaded\n"); - return 0; - } else { - release_region(I2C_DIR, IOSPACE); - printk - ("i2c-via.o: Algo-bit error, couldn't register bus\n"); - return -ENODEV; - } +static void __exit i2c_vt586b_exit(void) +{ +/* + pci_unregister_driver(&vt586b_driver); +*/ + vt586b_remove(NULL); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Kyösti Mälkki "); MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge"); +MODULE_LICENSE("GPL"); -int init_module(void) -{ - return i2c_via_init(); -} - -void cleanup_module(void) -{ - i2c_bit_del_bus(&bit_via_ops); - release_region(I2C_DIR, IOSPACE); -} -#endif +module_init(i2c_vt586b_init); +module_exit(i2c_vt586b_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-viapro.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-viapro.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-viapro.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-viapro.c 2003-08-17 21:26:58.000000000 +0200 @@ -32,86 +32,54 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include #include -#include #include #include #include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include - -#ifndef PCI_DEVICE_ID_VIA_82C596_3 -#define PCI_DEVICE_ID_VIA_82C596_3 0x3050 -#endif -#ifndef PCI_DEVICE_ID_VIA_82C596B_3 -#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051 -#endif -#ifndef PCI_DEVICE_ID_VIA_82C686_4 -#define PCI_DEVICE_ID_VIA_82C686_4 0x3057 -#endif -#ifndef PCI_DEVICE_ID_VIA_8233_0 -#define PCI_DEVICE_ID_VIA_8233_0 0x3074 -#endif - -#define SMBBA1 0x90 -#define SMBBA2 0x80 -#define SMBBA3 0xD0 - -struct sd { - const unsigned short dev; - const unsigned char base; - const unsigned char hstcfg; - const char *name; -}; - -static struct sd supported[] = { - {PCI_DEVICE_ID_VIA_82C596_3, SMBBA1, 0xD2, "VT82C596A/B"}, - {PCI_DEVICE_ID_VIA_82C596B_3, SMBBA1, 0xD2, "VT82C596B"}, - {PCI_DEVICE_ID_VIA_82C686_4, SMBBA1, 0xD2, "VT82C686A/B"}, - {PCI_DEVICE_ID_VIA_8233_0, SMBBA3, 0xD2, "VT8233"}, - {0x3147, SMBBA3, 0xD2, "VT8233A"}, - {0x3177, SMBBA3, 0xD2, "VT8233A/8235"}, - {0x8235, SMBBA1, 0xD2, "VT8231"}, - {0, 0, 0, NULL} -}; - -static struct sd *num = supported; +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include + +#define SMBBA1 0x90 +#define SMBBA2 0x80 +#define SMBBA3 0xD0 /* SMBus address offsets */ -#define SMBHSTSTS (0 + vt596_smba) -#define SMBHSLVSTS (1 + vt596_smba) -#define SMBHSTCNT (2 + vt596_smba) -#define SMBHSTCMD (3 + vt596_smba) -#define SMBHSTADD (4 + vt596_smba) -#define SMBHSTDAT0 (5 + vt596_smba) -#define SMBHSTDAT1 (6 + vt596_smba) -#define SMBBLKDAT (7 + vt596_smba) -#define SMBSLVCNT (8 + vt596_smba) -#define SMBSHDWCMD (9 + vt596_smba) -#define SMBSLVEVT (0xA + vt596_smba) -#define SMBSLVDAT (0xC + vt596_smba) +static unsigned short vt596_smba; +#define SMBHSTSTS (vt596_smba + 0) +#define SMBHSLVSTS (vt596_smba + 1) +#define SMBHSTCNT (vt596_smba + 2) +#define SMBHSTCMD (vt596_smba + 3) +#define SMBHSTADD (vt596_smba + 4) +#define SMBHSTDAT0 (vt596_smba + 5) +#define SMBHSTDAT1 (vt596_smba + 6) +#define SMBBLKDAT (vt596_smba + 7) +#define SMBSLVCNT (vt596_smba + 8) +#define SMBSHDWCMD (vt596_smba + 9) +#define SMBSLVEVT (vt596_smba + 0xA) +#define SMBSLVDAT (vt596_smba + 0xC) /* PCI Address Constants */ /* SMBus data in configuration space can be found in two places, We try to select the better one*/ -static unsigned short smb_cf_hstcfg; +static unsigned short smb_cf_hstcfg = 0xD2; #define SMBHSTCFG (smb_cf_hstcfg) -#define SMBSLVC (SMBHSTCFG+1) -#define SMBSHDW1 (SMBHSTCFG+2) -#define SMBSHDW2 (SMBHSTCFG+3) -#define SMBREV (SMBHSTCFG+4) +#define SMBSLVC (smb_cf_hstcfg + 1) +#define SMBSHDW1 (smb_cf_hstcfg + 2) +#define SMBSHDW2 (smb_cf_hstcfg + 3) +#define SMBREV (smb_cf_hstcfg + 4) /* Other settings */ -#define MAX_TIMEOUT 500 -#define ENABLE_INT9 0 +#define MAX_TIMEOUT 500 +#define ENABLE_INT9 0 /* VT82C596 constants */ #define VT596_QUICK 0x00 @@ -120,213 +88,55 @@ static unsigned short smb_cf_hstcfg; #define VT596_WORD_DATA 0x0C #define VT596_BLOCK_DATA 0x14 -/* insmod parameters */ /* If force is set to anything different from 0, we forcibly enable the VT596. DANGEROUS! */ -static int force = 0; +static int force; MODULE_PARM(force, "i"); MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); /* If force_addr is set to anything different from 0, we forcibly enable the VT596 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; +static int force_addr; MODULE_PARM(force_addr, "i"); MODULE_PARM_DESC(force_addr, "Forcibly enable the SMBus at the given address. " "EXTREMELY DANGEROUS!"); -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_vt596_init(void); -static int __init vt596_cleanup(void); -static int vt596_setup(void); -static s32 vt596_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data); -static void vt596_do_pause(unsigned int amount); -static int vt596_transaction(void); -static void vt596_inc(struct i2c_adapter *adapter); -static void vt596_dec(struct i2c_adapter *adapter); -static u32 vt596_func(struct i2c_adapter *adapter); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct i2c_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ I2C_ALGO_SMBUS, - /* master_xfer */ NULL, - /* smbus_access */ vt596_access, - /* slave_send */ NULL, - /* slave_rcv */ NULL, - /* algo_control */ NULL, - /* functionality */ vt596_func, -}; - -static struct i2c_adapter vt596_adapter = { - "unset", - I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2, - &smbus_algorithm, - NULL, - vt596_inc, - vt596_dec, - NULL, - NULL, -}; - -static int __initdata vt596_initialized; -static unsigned short vt596_smba = 0; - - -/* Detect whether a compatible device can be found, and initialize it. */ -int vt596_setup(void) -{ - unsigned char temp; - - struct pci_dev *VT596_dev = NULL; - - /* First check whether we can access PCI at all */ - if (pci_present() == 0) - return(-ENODEV); - - /* Look for a supported device/function */ - do { - if((VT596_dev = pci_find_device(PCI_VENDOR_ID_VIA, num->dev, - VT596_dev))) - break; - } while ((++num)->dev); - - if (VT596_dev == NULL) - return(-ENODEV); - printk("i2c-viapro.o: Found Via %s device\n", num->name); - -/* Determine the address of the SMBus areas */ - smb_cf_hstcfg = num->hstcfg; - if (force_addr) { - vt596_smba = force_addr & 0xfff0; - force = 0; - } else { - if ((pci_read_config_word(VT596_dev, num->base, &vt596_smba)) - || !(vt596_smba & 0x1)) { - /* try 2nd address and config reg. for 596 */ - if((num->dev == PCI_DEVICE_ID_VIA_82C596_3) && - (!pci_read_config_word(VT596_dev, SMBBA2, &vt596_smba)) && - (vt596_smba & 0x1)) { - smb_cf_hstcfg = 0x84; - } else { - /* no matches at all */ - printk("i2c-viapro.o: Cannot configure SMBus " - "I/O Base address\n"); - return(-ENODEV); - } - } - vt596_smba &= 0xfff0; - if(vt596_smba == 0) { - printk(KERN_ERR "i2c-viapro.o: SMBus base address" - "uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - } - - if (check_region(vt596_smba, 8)) { - printk("i2c-viapro.o: SMBus region 0x%x already in use!\n", - vt596_smba); - return(-ENODEV); - } - - pci_read_config_byte(VT596_dev, SMBHSTCFG, &temp); -/* If force_addr is set, we program the new address here. Just to make - sure, we disable the VT596 first. */ - if (force_addr) { - pci_write_config_byte(VT596_dev, SMBHSTCFG, temp & 0xfe); - pci_write_config_word(VT596_dev, num->base, vt596_smba); - pci_write_config_byte(VT596_dev, SMBHSTCFG, temp | 0x01); - printk - ("i2c-viapro.o: WARNING: SMBus interface set to new " - "address 0x%04x!\n", vt596_smba); - } else if ((temp & 1) == 0) { - if (force) { -/* NOTE: This assumes I/O space and other allocations WERE - done by the Bios! Don't complain if your hardware does weird - things after enabling this. :') Check for Bios updates before - resorting to this. */ - pci_write_config_byte(VT596_dev, SMBHSTCFG, - temp | 1); - printk - ("i2c-viapro.o: enabling SMBus device\n"); - } else { - printk - ("SMBUS: Error: Host SMBus controller not enabled! - " - "upgrade BIOS or use force=1\n"); - return(-ENODEV); - } - } - - /* Everything is happy, let's grab the memory and set things up. */ - request_region(vt596_smba, 8, "viapro-smbus"); - -#ifdef DEBUG - if ((temp & 0x0E) == 8) - printk("i2c-viapro.o: using Interrupt 9 for SMBus.\n"); - else if ((temp & 0x0E) == 0) - printk("i2c-viapro.o: using Interrupt SMI# for SMBus.\n"); - else - printk - ("i2c-viapro.o: Illegal Interrupt configuration (or code out " - "of date)!\n"); - - pci_read_config_byte(VT596_dev, SMBREV, &temp); - printk("i2c-viapro.o: SMBREV = 0x%X\n", temp); - printk("i2c-viapro.o: VT596_smba = 0x%X\n", vt596_smba); -#endif /* DEBUG */ - - return(0); -} +static struct i2c_adapter vt596_adapter; /* Internally used pause function */ -void vt596_do_pause(unsigned int amount) +static void vt596_do_pause(unsigned int amount) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(amount); } /* Another internally used function */ -int vt596_transaction(void) +static int vt596_transaction(void) { int temp; int result = 0; int timeout = 0; -#ifdef DEBUG - printk - ("i2c-viapro.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&vt596_adapter, "Transaction (pre): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk("i2c-viapro.o: SMBus busy (0x%02x). Resetting... \n", - temp); -#endif + dev_dbg(&vt596_adapter, "SMBus busy (0x%02x). " + "Resetting...\n", temp); + outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk("i2c-viapro.o: Failed! (0x%02x)\n", temp); -#endif + dev_dbg(&vt596_adapter, "Failed! (0x%02x)\n", temp); + return -1; } else { -#ifdef DEBUG - printk("i2c-viapro.o: Successfull!\n"); -#endif + dev_dbg(&vt596_adapter, "Successfull!\n"); } } @@ -342,65 +152,50 @@ int vt596_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { -#ifdef DEBUG - printk("i2c-viapro.o: SMBus Timeout!\n"); result = -1; -#endif + dev_dbg(&vt596_adapter, "SMBus Timeout!\n"); } if (temp & 0x10) { result = -1; -#ifdef DEBUG - printk("i2c-viapro.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(&vt596_adapter, "Error: Failed bus transaction\n"); } if (temp & 0x08) { result = -1; - printk - ("i2c-viapro.o: Bus collision! SMBus may be locked until next hard\n" - "reset. (sorry!)\n"); + dev_info(&vt596_adapter, "Bus collision! SMBus may be " + "locked until next hard\nreset. (sorry!)\n"); /* Clock stops and slave is stuck in mid-transmission */ } if (temp & 0x04) { result = -1; -#ifdef DEBUG - printk("i2c-viapro.o: Error: no response!\n"); -#endif + dev_dbg(&vt596_adapter, "Error: no response!\n"); } if (inb_p(SMBHSTSTS) != 0x00) outb_p(inb(SMBHSTSTS), SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk - ("i2c-viapro.o: Failed reset at end of transaction (%02x)\n", - temp); -#endif + dev_dbg(&vt596_adapter, "Failed reset at end of " + "transaction (%02x)\n", temp); } -#ifdef DEBUG - printk - ("i2c-viapro.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&vt596_adapter, "Transaction (post): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); + return result; } /* Return -1 on error. */ -s32 vt596_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, - u8 command, int size, union i2c_smbus_data * data) +static s32 vt596_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) { int i, len; switch (size) { - case I2C_SMBUS_PROC_CALL: - printk - ("i2c-viapro.o: I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); @@ -448,22 +243,25 @@ s32 vt596_access(struct i2c_adapter * ad } size = VT596_BLOCK_DATA; break; + default: + dev_warn(&vt596_adapter, "Unsupported transaction %d\n", size); + return -1; } outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - if (vt596_transaction()) /* Error in transaction */ + if (vt596_transaction()) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK)) return 0; - switch (size) { - case VT596_BYTE: /* Where is the result put? I assume here it is in - SMBHSTDAT0 but it might just as well be in the - SMBHSTCMD. No clue in the docs */ - + case VT596_BYTE: + /* Where is the result put? I assume here it is in + * SMBHSTDAT0 but it might just as well be in the + * SMBHSTCMD. No clue in the docs + */ data->byte = inb_p(SMBHSTDAT0); break; case VT596_BYTE_DATA: @@ -482,95 +280,228 @@ s32 vt596_access(struct i2c_adapter * ad return 0; } -void vt596_inc(struct i2c_adapter *adapter) -{ - MOD_INC_USE_COUNT; -} - -void vt596_dec(struct i2c_adapter *adapter) -{ - - MOD_DEC_USE_COUNT; -} - -u32 vt596_func(struct i2c_adapter *adapter) +static u32 vt596_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; } -int __init i2c_vt596_init(void) +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = vt596_access, + .functionality = vt596_func, +}; + +static struct i2c_adapter vt596_adapter = { + .owner = THIS_MODULE, + .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2, + .algo = &smbus_algorithm, + .name = "unset", +}; + +static int __devinit vt596_probe(struct pci_dev *pdev, + const struct pci_device_id *id) { - int res; - printk("i2c-viapro.o version %s (%s)\n", LM_VERSION, LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (vt596_initialized) { - printk - ("i2c-viapro.o: Oops, vt596_init called a second time!\n"); - return -EBUSY; + unsigned char temp; + int error = -ENODEV; + + /* Determine the address of the SMBus areas */ + if (force_addr) { + vt596_smba = force_addr & 0xfff0; + force = 0; + goto found; } -#endif - vt596_initialized = 0; - if ((res = vt596_setup())) { - printk - ("i2c-viapro.o: Can't detect vt82c596 or compatible device, module not inserted.\n"); - vt596_cleanup(); - return res; - } - vt596_initialized++; - sprintf(vt596_adapter.name, "SMBus Via Pro adapter at %04x", - vt596_smba); - if ((res = i2c_add_adapter(&vt596_adapter))) { - printk - ("i2c-viapro.o: Adapter registration failed, module not inserted.\n"); - vt596_cleanup(); - return res; + + if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) || + !(vt596_smba & 0x1)) { + /* try 2nd address and config reg. for 596 */ + if (id->device == PCI_DEVICE_ID_VIA_82C596_3 && + !pci_read_config_word(pdev, SMBBA2, &vt596_smba) && + (vt596_smba & 0x1)) { + smb_cf_hstcfg = 0x84; + } else { + /* no matches at all */ + dev_err(pdev, "Cannot configure " + "SMBus I/O Base address\n"); + return -ENODEV; + } } - vt596_initialized++; - printk("i2c-viapro.o: Via Pro SMBus detected and initialized\n"); - return 0; -} -int __init vt596_cleanup(void) -{ - int res; - if (vt596_initialized >= 2) { - if ((res = i2c_del_adapter(&vt596_adapter))) { - printk - ("i2c-viapro.o: i2c_del_adapter failed, module not removed\n"); - return res; - } else - vt596_initialized--; - } - if (vt596_initialized >= 1) { - release_region(vt596_smba, 8); - vt596_initialized--; + vt596_smba &= 0xfff0; + if (vt596_smba == 0) { + dev_err(pdev, "SMBus base address " + "uninitialized - upgrade BIOS or use " + "force_addr=0xaddr\n"); + return -ENODEV; } - return 0; -} -EXPORT_NO_SYMBOLS; + found: + if (!request_region(vt596_smba, 8, "viapro-smbus")) { + dev_err(pdev, "SMBus region 0x%x already in use!\n", + vt596_smba); + return -ENODEV; + } -#ifdef MODULE + pci_read_config_byte(pdev, SMBHSTCFG, &temp); + /* If force_addr is set, we program the new address here. Just to make + sure, we disable the VT596 first. */ + if (force_addr) { + pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe); + pci_write_config_word(pdev, id->driver_data, vt596_smba); + pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); + dev_warn(pdev, "WARNING: SMBus interface set to new " + "address 0x%04x!\n", vt596_smba); + } else if ((temp & 1) == 0) { + if (force) { + /* NOTE: This assumes I/O space and other allocations + * WERE done by the Bios! Don't complain if your + * hardware does weird things after enabling this. + * :') Check for Bios updates before resorting to + * this. + */ + pci_write_config_byte(pdev, SMBHSTCFG, temp | 1); + dev_info(pdev, "Enabling SMBus device\n"); + } else { + dev_err(pdev, "SMBUS: Error: Host SMBus " + "controller not enabled! - upgrade BIOS or " + "use force=1\n"); + goto release_region; + } + } -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("vt82c596 SMBus driver"); + if ((temp & 0x0E) == 8) + dev_dbg(pdev, "using Interrupt 9 for SMBus.\n"); + else if ((temp & 0x0E) == 0) + dev_dbg(pdev, "using Interrupt SMI# for SMBus.\n"); + else + dev_dbg(pdev, "Illegal Interrupt configuration " + "(or code out of date)!\n"); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif + pci_read_config_byte(pdev, SMBREV, &temp); + dev_dbg(pdev, "SMBREV = 0x%X\n", temp); + dev_dbg(pdev, "VT596_smba = 0x%X\n", vt596_smba); + + snprintf(vt596_adapter.name, 32, + "SMBus Via Pro adapter at %04x", vt596_smba); + + return i2c_add_adapter(&vt596_adapter); + + release_region: + release_region(vt596_smba, 8); + return error; +} + +static void __devexit vt596_remove(struct pci_dev *pdev) +{ + i2c_del_adapter(&vt596_adapter); + release_region(vt596_smba, 8); +} + +/* 8233A is undefined before kernel 2.4.19 */ +#ifndef PCI_DEVICE_ID_VIA_8233A +#define PCI_DEVICE_ID_VIA_8233A 0x3147 +#endif +/* 8235 is undefined before kernel 2.4.20 */ +#ifndef PCI_DEVICE_ID_VIA_8235 +#define PCI_DEVICE_ID_VIA_8235 0x3177 +#endif +static struct pci_device_id vt596_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_82C596_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA1, + }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_82C596B_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA1, + }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_82C686_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA1, + }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_8233_0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA3 + }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_8233A, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA3, + }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_8235, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA3 + }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_8231_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SMBBA1, + }, + { 0, } +}; + +/* Don't register driver to avoid driver conflicts */ +/* +static struct pci_driver vt596_driver = { + .name = "vt596 smbus", + .id_table = vt596_ids, + .probe = vt596_probe, + .remove = __devexit_p(vt596_remove), +}; +*/ -int init_module(void) +static int __init i2c_vt596_init(void) { - return i2c_vt596_init(); + struct pci_dev *dev; + const struct pci_device_id *id; + + printk("i2c-viapro.o version %s (%s)\n", LM_VERSION, LM_DATE); +/* + return pci_module_init(&vt596_driver); +*/ + pci_for_each_dev(dev) { + id = pci_match_device(vt596_ids, dev); + if(id) + if(vt596_probe(dev, id) >= 0) + return 0; + } + return -ENODEV; } -int cleanup_module(void) + +static void __exit i2c_vt596_exit(void) { - return vt596_cleanup(); +/* + pci_unregister_driver(&vt596_driver); +*/ + vt596_remove(NULL); } -#endif /* MODULE */ +MODULE_AUTHOR( + "Frodo Looijaard and " + "Philip Edelbrock "); +MODULE_DESCRIPTION("vt82c596 SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_vt596_init); +module_exit(i2c_vt596_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-voodoo3.c linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-voodoo3.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/i2c/i2c-voodoo3.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/i2c/i2c-voodoo3.c 2003-08-17 21:26:58.000000000 +0200 @@ -27,27 +27,16 @@ /* This interfaces to the I2C bus of the Voodoo3 to gain access to the BT869 and possibly other I2C devices. */ -#include #include #include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -/* 3DFX defines */ -#ifndef PCI_DEVICE_ID_3DFX_VOODOO3 -#define PCI_DEVICE_ID_3DFX_VOODOO3 0x05 -#endif -#ifndef PCI_DEVICE_ID_3DFX_BANSHEE -#define PCI_DEVICE_ID_3DFX_BANSHEE 0x03 -#endif /* the only registers we use */ #define REG 0x78 @@ -73,33 +62,18 @@ MODULE_LICENSE("GPL"); #define CYCLE_DELAY 10 #define TIMEOUT (HZ / 2) -#ifdef MODULE -static -#else -extern -#endif -int __init i2c_voodoo3_init(void); -static int __init voodoo3_cleanup(void); -static int voodoo3_setup(void); -static void config_v3(struct pci_dev *dev); -static void voodoo3_inc(struct i2c_adapter *adapter); -static void voodoo3_dec(struct i2c_adapter *adapter); -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ +static void config_v3(struct pci_dev *dev); -static int __initdata voodoo3_initialized; static unsigned char *mem; -extern inline void outlong(unsigned int dat) +static inline void outlong(unsigned int dat) { *((unsigned int *) (mem + REG)) = dat; } -extern inline unsigned int readlong(void) +static inline unsigned int readlong(void) { return *((unsigned int *) (mem + REG)); } @@ -179,45 +153,6 @@ static int bit_vooddc_getsda(void *data) return (0 != (readlong() & DDC_SDA_IN)); } -static struct i2c_algo_bit_data voo_i2c_bit_data = { - NULL, - bit_vooi2c_setsda, - bit_vooi2c_setscl, - bit_vooi2c_getsda, - bit_vooi2c_getscl, - CYCLE_DELAY, CYCLE_DELAY, TIMEOUT -}; - -static struct i2c_adapter voodoo3_i2c_adapter = { - "I2C Voodoo3/Banshee adapter", - I2C_HW_B_VOO, - NULL, - &voo_i2c_bit_data, - voodoo3_inc, - voodoo3_dec, - NULL, - NULL, -}; - -static struct i2c_algo_bit_data voo_ddc_bit_data = { - NULL, - bit_vooddc_setsda, - bit_vooddc_setscl, - bit_vooddc_getsda, - bit_vooddc_getscl, - CYCLE_DELAY, CYCLE_DELAY, TIMEOUT -}; - -static struct i2c_adapter voodoo3_ddc_adapter = { - "DDC Voodoo3/Banshee adapter", - I2C_HW_B_VOO, - NULL, - &voo_ddc_bit_data, - voodoo3_inc, - voodoo3_dec, - NULL, - NULL, -}; /* Configures the chip */ @@ -226,11 +161,7 @@ void config_v3(struct pci_dev *dev) unsigned int cadr; /* map Voodoo3 memory */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) cadr = dev->resource[0].start; -#else - cadr = dev->base_address[0]; -#endif cadr &= PCI_BASE_ADDRESS_MEM_MASK; mem = ioremap_nocache(cadr, 0x1000); if(mem) { @@ -240,130 +171,121 @@ void config_v3(struct pci_dev *dev) } } -/* Detect whether a Voodoo3 or a Banshee can be found, - and initialize it. */ -static int voodoo3_setup(void) -{ - struct pci_dev *dev; - int v3_num; +static struct i2c_algo_bit_data voo_i2c_bit_data = { + .setsda = bit_vooi2c_setsda, + .setscl = bit_vooi2c_setscl, + .getsda = bit_vooi2c_getsda, + .getscl = bit_vooi2c_getscl, + .udelay = CYCLE_DELAY, + .mdelay = CYCLE_DELAY, + .timeout = TIMEOUT +}; - v3_num = 0; +static struct i2c_adapter voodoo3_i2c_adapter = { + .owner = THIS_MODULE, + .name = "I2C Voodoo3/Banshee adapter", + .id = I2C_HW_B_VOO, + .algo_data = &voo_i2c_bit_data, +}; - dev = NULL; - do { - if ((dev = pci_find_device(PCI_VENDOR_ID_3DFX, - PCI_DEVICE_ID_3DFX_VOODOO3, - dev))) { - if (!v3_num) - config_v3(dev); - v3_num++; - } - } while (dev); - - dev = NULL; - do { - if ((dev = pci_find_device(PCI_VENDOR_ID_3DFX, - PCI_DEVICE_ID_3DFX_BANSHEE, - dev))) { - if (!v3_num) - config_v3(dev); - v3_num++; - } - } while (dev); - - if (v3_num > 0) { - if(!mem) - return -ENOMEM; - printk("i2c-voodoo3: %d Banshee/Voodoo3 found.\n", v3_num); - if (v3_num > 1) - printk("i2c-voodoo3: warning: only 1 supported.\n"); - return 0; - } else { - printk("i2c-voodoo3: No Voodoo3 found.\n"); - return -ENODEV; - } -} +static struct i2c_algo_bit_data voo_ddc_bit_data = { + .setsda = bit_vooddc_setsda, + .setscl = bit_vooddc_setscl, + .getsda = bit_vooddc_getsda, + .getscl = bit_vooddc_getscl, + .udelay = CYCLE_DELAY, + .mdelay = CYCLE_DELAY, + .timeout = TIMEOUT +}; -void voodoo3_inc(struct i2c_adapter *adapter) +static struct i2c_adapter voodoo3_ddc_adapter = { + .owner = THIS_MODULE, + .name = "DDC Voodoo3/Banshee adapter", + .id = I2C_HW_B_VOO, + .algo_data = &voo_ddc_bit_data, +}; + + +static struct pci_device_id voodoo3_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_3DFX, + .device = PCI_DEVICE_ID_3DFX_VOODOO3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_3DFX, + .device = PCI_DEVICE_ID_3DFX_BANSHEE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id) { - MOD_INC_USE_COUNT; + int retval; + + printk("voodoo3: in probe\n"); + config_v3(dev); + retval = i2c_bit_add_bus(&voodoo3_i2c_adapter); + if(retval) + return retval; + retval = i2c_bit_add_bus(&voodoo3_ddc_adapter); + if(retval) + i2c_bit_del_bus(&voodoo3_i2c_adapter); + return retval; } -void voodoo3_dec(struct i2c_adapter *adapter) +static void __devexit voodoo3_remove(struct pci_dev *dev) { - MOD_DEC_USE_COUNT; + i2c_bit_del_bus(&voodoo3_i2c_adapter); + i2c_bit_del_bus(&voodoo3_ddc_adapter); } -int __init i2c_voodoo3_init(void) + +/* Don't register driver to avoid driver conflicts */ +/* +static struct pci_driver voodoo3_driver = { + .name = "voodoo3 smbus", + .id_table = voodoo3_ids, + .probe = voodoo3_probe, + .remove = __devexit_p(voodoo3_remove), +}; +*/ + +static int __init i2c_voodoo3_init(void) { - int res; + struct pci_dev *dev; + const struct pci_device_id *id; + printk("i2c-voodoo3.o version %s (%s)\n", LM_VERSION, LM_DATE); - voodoo3_initialized = 0; - if ((res = voodoo3_setup())) { - printk - ("i2c-voodoo3.o: Voodoo3 not detected, module not inserted.\n"); - voodoo3_cleanup(); - return res; - } - if ((res = i2c_bit_add_bus(&voodoo3_i2c_adapter))) { - printk("i2c-voodoo3.o: I2C adapter registration failed\n"); - } else { - printk("i2c-voodoo3.o: I2C bus initialized\n"); - voodoo3_initialized |= INIT2; - } - if ((res = i2c_bit_add_bus(&voodoo3_ddc_adapter))) { - printk("i2c-voodoo3.o: DDC adapter registration failed\n"); - } else { - printk("i2c-voodoo3.o: DDC bus initialized\n"); - voodoo3_initialized |= INIT3; +/* + return pci_module_init(&voodoo3_driver); +*/ + pci_for_each_dev(dev) { + id = pci_match_device(voodoo3_ids, dev); + if(id) + if(voodoo3_probe(dev, id) >= 0) + return 0; } - if(!(voodoo3_initialized & (INIT2 | INIT3))) { - printk("i2c-voodoo3.o: Both registrations failed, module not inserted\n"); - voodoo3_cleanup(); - return res; - } - return 0; + return -ENODEV; } -int __init voodoo3_cleanup(void) -{ - int res; +static void __exit i2c_voodoo3_exit(void) +{ +/* + pci_unregister_driver(&voodoo3_driver); +*/ + voodoo3_remove(NULL); iounmap(mem); - if (voodoo3_initialized & INIT3) { - if ((res = i2c_bit_del_bus(&voodoo3_ddc_adapter))) { - printk - ("i2c-voodoo3.o: i2c_bit_del_bus failed, module not removed\n"); - return res; - } - } - if (voodoo3_initialized & INIT2) { - if ((res = i2c_bit_del_bus(&voodoo3_i2c_adapter))) { - printk - ("i2c-voodoo3.o: i2c_bit_del_bus failed, module not removed\n"); - return res; - } - } - return 0; } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , Ralph Metzler , and Mark D. Studebaker "); MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver"); - -int init_module(void) -{ - return i2c_voodoo3_init(); -} - -int cleanup_module(void) -{ - return voodoo3_cleanup(); -} - -#endif /* MODULE */ +module_init(i2c_voodoo3_init); +module_exit(i2c_voodoo3_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/ide/pdc202xx.c linux-2.4.20-wolk4.7-fullkernel/drivers/ide/pdc202xx.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/ide/pdc202xx.c 2003-05-03 01:34:36.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/ide/pdc202xx.c 2003-08-17 21:31:44.000000000 +0200 @@ -762,9 +762,9 @@ static int config_chipset_for_dma (ide_d if ((ultra_66) || (ultra_100) || (ultra_133)) { /* * check to make sure drive on same channel - * is u66 capable + * is u66 capable. Ignore empty slots. */ - if (hwif->drives[!(drive->dn%2)].id) { + if (hwif->drives[!(drive->dn%2)].present) { if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) || (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) || diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/isdn/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/isdn/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/isdn/Makefile 2003-05-03 02:10:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/isdn/Makefile 2003-08-17 21:31:46.000000000 +0200 @@ -46,6 +46,15 @@ subdir-$(CONFIG_ISDN_DRV_EICON) += eico subdir-$(CONFIG_HYSDN) += hysdn subdir-$(CONFIG_ISDN_DRV_TPAM) += tpam +ifeq ($(CONFIG_PCMCIA),y) + subdir-y += pcmcia + subdir-m += pcmcia +else + ifeq ($(CONFIG_PCMCIA),m) + subdir-m += pcmcia + endif +endif + obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y)) # The global Rules.make. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/isdn/pcmcia/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/isdn/pcmcia/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/isdn/pcmcia/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/isdn/pcmcia/Makefile 2003-08-17 21:31:46.000000000 +0200 @@ -0,0 +1,20 @@ +# +# Makefile for drivers/isdn/pcmcia +# +# 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). +# + +obj-y := +obj-n := +obj-m := +obj- := + +ifeq ($(CONFIG_ISDN_DRV_HISAX),m) + ifeq ($(CONFIG_HISAX_AVM_A1_PCMCIA),y) + obj-m += avma1_cs.o + endif +endif + +include $(TOPDIR)/Rules.make diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/isdn/pcmcia/avma1_cs.c linux-2.4.20-wolk4.7-fullkernel/drivers/isdn/pcmcia/avma1_cs.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/isdn/pcmcia/avma1_cs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/isdn/pcmcia/avma1_cs.c 2003-08-17 21:31:46.000000000 +0200 @@ -0,0 +1,541 @@ +/*====================================================================== + + A PCMCIA client driver for AVM B1/M1/M2 + + Written by Carsten Paeth, calle@calle.in-berlin.de + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot); +void HiSax_closecard(int cardnr); + + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int default_irq_list[11] = { 15, 13, 12, 11, 10, 9, 7, 5, 4, 3, -1 }; +static int irq_list[11] = { -1 }; +static int isdnprot = 2; + +MODULE_PARM(irq_list, "1-11i"); +MODULE_PARM(isdnprot, "1-4i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the skeleton event + handler. +*/ + +static void avma1cs_config(dev_link_t *link); +static void avma1cs_release(u_long arg); +static int avma1cs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *avma1cs_attach(void); +static void avma1cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "avma1_cs"; + +/* + A linked list of "instances" of the skeleton device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally can't be allocated dynamically. +*/ + +typedef struct local_info_t { + dev_node_t node; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + avma1cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *avma1cs_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "avma1cs_attach()\n"); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &avma1cs_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts2 = 16; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] != -1) { + for (i = 0; i < 10 && irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } else { + for (i = 0; i < 10 && default_irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << default_irq_list[i]; + } + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &avma1cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + avma1cs_detach(link); + return NULL; + } + + return link; +} /* avma1cs_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void avma1cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "avma1cs_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + kfree(link->priv); + } + kfree(link); + +} /* avma1cs_detach */ + +/*====================================================================== + + avma1cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +======================================================================*/ + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) return i; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +static void avma1cs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + local_info_t *dev; + int i; + u_char buf[64]; + char devname[128]; + int busy = 0; + + handle = link->handle; + dev = link->priv; + + DEBUG(0, "avma1cs_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + do { + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if (i != CS_SUCCESS) break; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + i = CardServices(GetTupleData, handle, &tuple); + if (i != CS_SUCCESS) break; + i = CardServices(ParseTuple, handle, &tuple, &parse); + if (i != CS_SUCCESS) break; + link->conf.ConfigBase = parse.config.base; + } while (0); + if (i != CS_SUCCESS) { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + + do { + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 254; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + + devname[0] = 0; + if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { + strncpy(devname,parse.version_1.str + parse.version_1.ofs[1], + sizeof(devname)); + } + /* + * find IO port + */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if (cf->io.nwin > 0) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; + link->io.BasePort2 = 0; + link->io.NumPorts2 = 0; + printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", + link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1); + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + i = next_tuple(handle, &tuple, &parse); + } +found_port: + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * allocate an interrupt line + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + CardServices(ReleaseIO, link->handle, &link->io); + break; + } + + /* + * configure the PCMCIA socket + */ + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + break; + } + + } while (0); + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. */ + + strcpy(dev->node.dev_name, "A1"); + dev->node.major = 45; + dev->node.minor = 0; + link->dev = &dev->node; + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if (i != 0) { + avma1cs_release((u_long)link); + return; + } + + printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n", + link->io.BasePort1, link->irq.AssignedIRQ); + + if (avm_a1_init_pcmcia((void *)(int)link->io.BasePort1, + link->irq.AssignedIRQ, + &busy, isdnprot) != 0) { + printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); + return; + } + + i = 0; /* no returncode for cardnr :-( */ + + dev->node.minor = i; + +} /* avma1cs_config */ + +/*====================================================================== + + After a card is removed, avma1cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void avma1cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + local_info_t *local = link->priv; + + DEBUG(0, "avma1cs_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + DEBUG(1, "avma1_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* no unregister function with hisax */ + HiSax_closecard(local->node.minor); + + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + avma1cs_detach(link); + +} /* avma1cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int avma1cs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "avma1cs_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = (jiffies+(HZ/20)); + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + avma1cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + return 0; +} /* avma1cs_event */ + +/*====================================================================*/ + +int init_module(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "avma1_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &avma1cs_attach, &avma1cs_detach); + return 0; +} + +void cleanup_module(void) +{ + DEBUG(0, "avma1_cs: unloading\n"); + unregister_pcmcia_driver(&dev_info); + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + avma1cs_release((u_long)dev_list); + avma1cs_detach(dev_list); + } +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/md/Config.in linux-2.4.20-wolk4.7-fullkernel/drivers/md/Config.in --- linux-2.4.20-wolk4.6-fullkernel/drivers/md/Config.in 2003-05-03 03:07:39.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/md/Config.in 2003-08-17 21:30:58.000000000 +0200 @@ -16,11 +16,11 @@ dep_tristate ' Multipath I/O support' C dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Device-mapper support (EXPERIMENTAL)' CONFIG_BLK_DEV_DM $CONFIG_MD - dep_tristate ' Bad Block Relocation Device Target' CONFIG_BLK_DEV_DM_BBR $CONFIG_BLK_DEV_DM - dep_tristate ' Sparse Device Target' CONFIG_BLK_DEV_DM_SPARSE $CONFIG_BLK_DEV_DM if [ "$CONFIG_BLK_DEV_DM" = "y" -o "$CONFIG_BLK_DEV_DM" = "m" ]; then define_bool CONFIG_MEMORYPOOL y fi + dep_tristate ' Bad Block Relocation Device Target' CONFIG_BLK_DEV_DM_BBR $CONFIG_BLK_DEV_DM + dep_tristate ' Sparse Device Target' CONFIG_BLK_DEV_DM_SPARSE $CONFIG_BLK_DEV_DM fi endmenu diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/md/dm-snapshot.c linux-2.4.20-wolk4.7-fullkernel/drivers/md/dm-snapshot.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/md/dm-snapshot.c 2003-05-03 03:08:49.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/md/dm-snapshot.c 2003-08-17 21:30:58.000000000 +0200 @@ -768,14 +768,20 @@ static inline void start_copy(struct pen { struct dm_snapshot *s = pe->snap; struct kcopyd_region src, dest; + kdev_t dev = s->origin->dev; + int *sizes = blk_size[major(dev)]; + sector_t dev_size = (sector_t)-1; - src.dev = s->origin->dev; + if (sizes && sizes[minor(dev)]) + dev_size = sizes[minor(dev)] << 1; + + src.dev = dev; src.sector = chunk_to_sector(s, pe->e.old_chunk); - src.count = s->chunk_size; + src.count = min(s->chunk_size, dev_size - src.sector); dest.dev = s->cow->dev; dest.sector = chunk_to_sector(s, pe->e.new_chunk); - dest.count = s->chunk_size; + dest.count = src.count; if (!pe->started) { /* Hand over to kcopyd */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/md/lvm.c linux-2.4.20-wolk4.7-fullkernel/drivers/md/lvm.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/md/lvm.c 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/md/lvm.c 2003-08-17 21:26:01.000000000 +0200 @@ -239,6 +239,9 @@ #endif #define LOCAL_END_REQUEST +/* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */ +/* #define LVM_VFS_ENHANCEMENT */ + #include #include #include @@ -2439,8 +2442,12 @@ static int lvm_do_lv_create(int minor, c if (lv_ptr->lv_access & LV_SNAPSHOT) { lv_t *org = lv_ptr->lv_snapshot_org, *last; + /* sync the original logical volume */ + fsync_dev(org->lv_dev); +#ifdef LVM_VFS_ENHANCEMENT /* VFS function call to sync and lock the filesystem */ fsync_dev_lockfs(org->lv_dev); +#endif down_write(&org->lv_lock); org->lv_access |= LV_SNAPSHOT_ORG; @@ -2477,9 +2484,11 @@ static int lvm_do_lv_create(int minor, c else set_device_ro(lv_ptr->lv_dev, 1); +#ifdef LVM_VFS_ENHANCEMENT /* VFS function call to unlock the filesystem */ if (lv_ptr->lv_access & LV_SNAPSHOT) unlockfs(lv_ptr->lv_snapshot_org->lv_dev); +#endif #if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de = diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/md/multipath.c linux-2.4.20-wolk4.7-fullkernel/drivers/md/multipath.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/md/multipath.c 2002-02-25 20:37:58.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/md/multipath.c 2003-08-17 21:30:59.000000000 +0200 @@ -139,15 +139,16 @@ static void multipath_shrink_mpbh(multip static int multipath_map (mddev_t *mddev, kdev_t *rdev) { multipath_conf_t *conf = mddev_to_conf(mddev); - int i, disks = MD_SB_DISKS; + int i; /* * Later we do read balancing on the read side * now we use the first available disk. */ - for (i = 0; i < disks; i++) { + for (i = 0; i < conf->nr_disks; i++) { if (conf->multipaths[i].operational) { + /* first operational is winner! */ *rdev = conf->multipaths[i].dev; return (0); } @@ -191,6 +192,8 @@ void multipath_end_request (struct buffe { struct multipath_bh * mp_bh = (struct multipath_bh *)(bh->b_private); + atomic_dec(&mp_bh->multipath->nr_pending); + /* * this branch is our 'one multipath IO has finished' event handler: */ @@ -223,19 +226,39 @@ void multipath_end_request (struct buffe } /* - * This routine returns the disk from which the requested read should - * be done. + * Multipath read balance ... + * + * Returns: + * + * If no active paths + * + * - Error ( -1 ) + * + * If active paths == 1 + * + * - 1st active path encountered + * + * If active paths > 1 + * + * - 1st idle active path encountered + * - else ... the active path doing the least amount of work. */ - static int multipath_read_balance (multipath_conf_t *conf) { - int disk; - - for (disk = 0; disk < conf->raid_disks; disk++) - if (conf->multipaths[disk].operational) - return disk; - BUG(); - return 0; + int i, disk=-1, nr_pending, least_pending=0; + + for (i=0; inr_disks; i++) { + if (conf->multipaths[i].operational) { + nr_pending = atomic_read(&conf->multipaths[i].nr_pending); + if (nr_pending==0 || conf->working_disks==1) + return i; + if (least_pending==0 || nr_pendingmultipaths + multipath_read_balance(conf); + disk = multipath_read_balance(conf); + if (disk==-1) { + printk (KERN_ERR "multipath_make_request: no more operational IO paths.\n"); + buffer_IO_error(bh); + return 0; + } + + multipath = conf->multipaths + disk; + mp_bh->multipath = multipath; + atomic_inc(&multipath->nr_pending); bh_req = &mp_bh->bh_req; memcpy(bh_req, bh, sizeof(*bh)); @@ -332,13 +365,14 @@ static int multipath_error (mddev_t *mdd { multipath_conf_t *conf = mddev_to_conf(mddev); struct multipath_info * multipaths = conf->multipaths; - int disks = MD_SB_DISKS; int other_paths = 1; - int i; + int i, first = 1; + mdk_rdev_t *rdev; + struct md_list_head *tmp; if (conf->working_disks == 1) { other_paths = 0; - for (i = 0; i < disks; i++) { + for (i = 0; i < MD_SB_DISKS; i++) { if (multipaths[i].spare) { other_paths = 1; break; @@ -352,16 +386,17 @@ static int multipath_error (mddev_t *mdd * first check if this is a queued request for a device * which has just failed. */ - for (i = 0; i < disks; i++) { + for (i = 0; i < MD_SB_DISKS; i++) { if (multipaths[i].dev==dev && !multipaths[i].operational) return 0; } printk (LAST_DISK); } else { + mdp_super_t *sb = mddev->sb; /* * Mark disk as unusable */ - for (i = 0; i < disks; i++) { + for (i = 0; i < MD_SB_DISKS; i++) { if (multipaths[i].dev==dev && multipaths[i].operational) { mark_disk_bad(mddev, i); break; @@ -370,7 +405,6 @@ static int multipath_error (mddev_t *mdd if (!conf->working_disks) { int err = 1; mdp_disk_t *spare; - mdp_super_t *sb = mddev->sb; spare = get_spare(mddev); if (spare) { @@ -385,6 +419,21 @@ static int multipath_error (mddev_t *mdd sb->spare_disks--; } } + /* prevent unnecessary work in md_do_recovery() */ + if (conf->working_disks) { + conf->raid_disks = conf->working_disks + = sb->raid_disks = sb->active_disks; + } + /* update alias disk info to insure we can do sb commit. */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (first && disk_active(&sb->disks[rdev->desc_nr])) { + rdev->alias_device = 0; + first = 0; + } else { + if (!disk_faulty(&sb->disks[rdev->desc_nr])) + rdev->alias_device = 1; + } + } } return 0; } @@ -678,9 +727,8 @@ abort: /* * This is a kernel thread which: * - * 1. Retries failed read operations on working multipaths. + * 1. Retries failed operations on working multipaths. * 2. Updates the raid superblock when problems encounter. - * 3. Performs writes following reads for array syncronising. */ static void multipathd (void *data) @@ -834,6 +882,7 @@ static int multipath_run (mddev_t *mddev mdk_rdev_t *rdev, *def_rdev = NULL; struct md_list_head *tmp; int num_rdevs = 0; + int active_disks = 0, spare_disks = 0, faulty_disks = 0; MOD_INC_USE_COUNT; @@ -882,9 +931,7 @@ static int multipath_run (mddev_t *mddev printk(NOT_IN_SYNC, partition_name(rdev->dev)); /* - * Mark all disks as spare to start with, then pick our - * active disk. If we have a disk that is marked active - * in the sb, then use it, else use the first rdev. + * Mark all disks as spare to start with. */ disk->number = desc->number; disk->raid_disk = desc->raid_disk; @@ -895,20 +942,21 @@ static int multipath_run (mddev_t *mddev mark_disk_sync(desc); if (disk_active(desc)) { - if(!conf->working_disks) { - printk(OPERATIONAL, partition_name(rdev->dev), - desc->raid_disk); - disk->operational = 1; - disk->spare = 0; - conf->working_disks++; - def_rdev = rdev; - } else { - mark_disk_spare(desc); - } - } else - mark_disk_spare(desc); + printk(OPERATIONAL, partition_name(rdev->dev), + desc->raid_disk); + disk->operational = 1; + disk->spare = 0; + conf->working_disks++; + def_rdev = rdev; + active_disks++; + } else if (disk_faulty(desc)) { + disk->spare = 0; + faulty_disks++; + } else { + spare_disks++; + } - if(!num_rdevs++) def_rdev = rdev; + num_rdevs++; } if(!conf->working_disks && num_rdevs) { desc = &sb->disks[def_rdev->desc_nr]; @@ -919,11 +967,12 @@ static int multipath_run (mddev_t *mddev disk->spare = 0; conf->working_disks++; mark_disk_active(desc); + active_disks++; } /* - * Make sure our active path is in desc spot 0 + * If there is only 1 active path ... make sure it is in desc spot 0 */ - if(def_rdev->desc_nr != 0) { + if (active_disks == 1 && def_rdev->desc_nr != 0) { rdev = find_rdev_nr(mddev, 0); desc = &sb->disks[def_rdev->desc_nr]; desc2 = sb->disks; @@ -941,10 +990,10 @@ static int multipath_run (mddev_t *mddev def_rdev->desc_nr = 0; } } - conf->raid_disks = sb->raid_disks = sb->active_disks = 1; + conf->raid_disks = sb->raid_disks = sb->active_disks = active_disks; conf->nr_disks = sb->nr_disks = sb->working_disks = num_rdevs; - sb->failed_disks = 0; - sb->spare_disks = num_rdevs - 1; + sb->failed_disks = faulty_disks; + sb->spare_disks = spare_disks; mddev->sb_dirty = 1; conf->mddev = mddev; conf->device_lock = MD_SPIN_LOCK_UNLOCKED; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/md/raid5.c linux-2.4.20-wolk4.7-fullkernel/drivers/md/raid5.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/md/raid5.c 2003-08-04 23:06:27.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/md/raid5.c 2003-08-17 21:31:02.000000000 +0200 @@ -282,7 +282,7 @@ static struct stripe_head *get_active_st } 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); shrink_stripe_cache(conf); if (size==0) BUG(); conf->buffer_size = size; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/media/video/v4l1-compat.c linux-2.4.20-wolk4.7-fullkernel/drivers/media/video/v4l1-compat.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/media/video/v4l1-compat.c 2003-05-03 02:00:17.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/media/video/v4l1-compat.c 2003-08-17 21:27:38.000000000 +0200 @@ -203,17 +203,11 @@ static int poll_one(struct file *file) { int retval = 1; poll_table *table; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) - poll_table wait_table; - - poll_initwait(&wait_table); - table = &wait_table; -#else struct poll_wqueues pwq; poll_initwait(&pwq); table = &pwq.pt; -#endif + for (;;) { int mask; set_current_state(TASK_INTERRUPTIBLE); @@ -228,11 +222,7 @@ static int poll_one(struct file *file) schedule(); } current->state = TASK_RUNNING; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) - poll_freewait(&wait_table); -#else poll_freewait(&pwq); -#endif return retval; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/net/pppoe.c linux-2.4.20-wolk4.7-fullkernel/drivers/net/pppoe.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/net/pppoe.c 2003-05-03 01:36:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/net/pppoe.c 2003-08-17 21:25:46.000000000 +0200 @@ -605,7 +605,8 @@ int pppoe_connect(struct socket *sock, s /* Delete the old binding */ delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote); - dev_put(po->pppoe_dev); + if(po->pppoe_dev) + dev_put(po->pppoe_dev); memset(po, 0, sizeof(struct pppox_opt)); po->sk = sk; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/net/sungem.c linux-2.4.20-wolk4.7-fullkernel/drivers/net/sungem.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/net/sungem.c 2002-09-27 23:25:48.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/net/sungem.c 2003-08-17 21:31:40.000000000 +0200 @@ -2853,7 +2853,7 @@ static int __devinit gem_get_device_addr printk(KERN_ERR "%s: can't get mac-address\n", dev->name); return -1; } - memcpy(dev->dev_addr, addr, MAX_ADDR_LEN); + memcpy(dev->dev_addr, addr, 6); #else get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr); #endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/sab82532.c linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/sab82532.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/sab82532.c 2002-09-27 23:25:52.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/sab82532.c 2003-08-17 21:26:24.000000000 +0200 @@ -42,6 +42,28 @@ #include "sunserial.h" +#if defined(CONFIG_KDB) +#include +/* + * 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 char kdb_serial_str[] = "\001"; +static char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ + static DECLARE_TASK_QUEUE(tq_serial); /* This is (one of many) a special gross hack to allow SU and @@ -318,8 +340,12 @@ static void sab82532_sched_event(struct } static void receive_chars(struct sab82532 *info, - union sab82532_irq_status *stat) + union sab82532_irq_status *stat, + struct pt_regs *regs) { +#if defined(CONFIG_KDB) + int need_kdb = 0; +#endif struct tty_struct *tty = info->tty; unsigned char buf[32]; unsigned char status; @@ -373,6 +399,18 @@ static void receive_chars(struct sab8253 break; } +#if defined(CONFIG_KDB) + if (info->is_console && kdb_on) { + if (buf[i] == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + need_kdb = 1; + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ tty->flip.count++; *tty->flip.char_buf_ptr++ = buf[i++]; status = buf[i++]; @@ -392,7 +430,10 @@ static void receive_chars(struct sab8253 else *tty->flip.flag_buf_ptr++ = TTY_NORMAL; } - +#ifdef CONFIG_KDB + if (need_kdb) + kdb(KDB_REASON_KEYBOARD, 0, regs); +#endif queue_task(&tty->flip.tqueue, &tq_timer); } @@ -600,7 +641,7 @@ static void sab82532_interrupt(int irq, if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) - receive_chars(info, &status); + receive_chars(info, &status, regs); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(info, &status); @@ -625,7 +666,7 @@ next: if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) - receive_chars(info, &status); + receive_chars(info, &status, regs); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(info, &status); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/su.c linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/su.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/su.c 2002-09-27 23:25:52.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/su.c 2003-08-17 21:26:24.000000000 +0200 @@ -74,6 +74,30 @@ do { \ #endif #include +#ifdef 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 */ + #include #include #include @@ -400,6 +424,18 @@ receive_serial_chars(struct su_struct *i saw_console_brk = 1; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; +#ifdef CONFIG_KDB + if ((info->line == kdb_serial_line) && kdb_on) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + kdb(KDB_REASON_KEYBOARD, 0, 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++; @@ -2972,6 +3008,16 @@ static int __init serial_console_setup(s info->is_console = 1; +#ifdef 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; + +#endif /* CONFIG_KDB */ + return 0; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/sunkbd.c linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/sunkbd.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/sunkbd.c 2002-09-27 23:25:52.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/sunkbd.c 2003-08-17 21:26:24.000000000 +0200 @@ -44,6 +44,10 @@ #include #endif +#ifdef CONFIG_KDB +#include +#endif + #include "sunkbd.h" #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -138,6 +142,9 @@ typedef void (void_fn)(void); static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, +#ifdef CONFIG_KDB + call_kdb, +#endif SAK, decr_console, incr_console, spawn_console, bare_num; static void_fnp spec_fn_table[] = { @@ -145,7 +152,10 @@ static void_fnp spec_fn_table[] = { show_state, send_intr, lastcons, caps_toggle, num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, SAK, - decr_console, incr_console, spawn_console, bare_num + decr_console, incr_console, spawn_console, bare_num, +#ifdef CONFIG_KDB + call_kdb +#endif }; /* maximum values each key_handler can handle */ @@ -813,6 +823,13 @@ static void do_ignore(unsigned char valu { } +#ifdef CONFIG_KDB +static void call_kdb() +{ + kdb(KDB_REASON_KEYBOARD, 0, pt_regs); +} +#endif + static void do_null() { sun_compute_shiftstate(); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/sunkeymap.c linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/sunkeymap.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sbus/char/sunkeymap.c 1999-12-21 07:06:42.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sbus/char/sunkeymap.c 2003-08-17 21:26:24.000000000 +0200 @@ -9,7 +9,13 @@ u_short plain_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109, 0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf105, 0xf200, - 0xf106, 0xf107, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209, + 0xf106, 0xf107, 0xf108, 0xf703, 0xf603, +#ifdef CONFIG_KDB + /* Pause (keycode 0x15) triggers kdb */ 0xf214, +#else + 0xf11d, +#endif + 0xf200, 0xf209, 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf060, 0xf07f, 0xf115, 0xf03d, 0xf30d, 0xf30c, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/53c8xx_d.h linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/53c8xx_d.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/53c8xx_d.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/53c8xx_d.h 1999-12-09 00:17:55.000000000 +0100 @@ -0,0 +1,2678 @@ +/* DO NOT EDIT - Generated automatically by script_asm.pl */ +static u32 SCRIPT[] = { +/* + + +; NCR 53c810 driver, main script +; Sponsored by +; iX Multiuser Multitasking Magazine +; hm@ix.de +; +; Copyright 1993, 1994, 1995 Drew Eckhardt +; Visionary Computing +; (Unix and Linux consulting and custom programming) +; drew@PoohSticks.ORG +; +1 (303) 786-7975 +; +; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation. +; +; PRE-ALPHA +; +; For more information, please consult +; +; NCR 53C810 +; PCI-SCSI I/O Processor +; Data Manual +; +; NCR 53C710 +; SCSI I/O Processor +; Programmers Guide +; +; NCR Microelectronics +; 1635 Aeroplaza Drive +; Colorado Springs, CO 80916 +; 1+ (719) 578-3400 +; +; Toll free literature number +; +1 (800) 334-5454 +; +; IMPORTANT : This code is self modifying due to the limitations of +; the NCR53c7,8xx series chips. Persons debugging this code with +; the remote debugger should take this into account, and NOT set +; breakpoints in modified instructions. +; +; Design: +; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard +; microcontroller using a simple instruction set. +; +; So, to minimize the effects of interrupt latency, and to maximize +; throughput, this driver offloads the practical maximum amount +; of processing to the SCSI chip while still maintaining a common +; structure. +; +; Where tradeoffs were needed between efficiency on the older +; chips and the newer NCR53c800 series, the NCR53c800 series +; was chosen. +; +; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully +; automate SCSI transfers without host processor intervention, this +; isn't the case with the NCR53c710 and newer chips which allow +; +; - reads and writes to the internal registers from within the SCSI +; scripts, allowing the SCSI SCRIPTS(tm) code to save processor +; state so that multiple threads of execution are possible, and also +; provide an ALU for loop control, etc. +; +; - table indirect addressing for some instructions. This allows +; pointers to be located relative to the DSA ((Data Structure +; Address) register. +; +; These features make it possible to implement a mailbox style interface, +; where the same piece of code is run to handle I/O for multiple threads +; at once minimizing our need to relocate code. Since the NCR53c700/ +; NCR53c800 series have a unique combination of features, making a +; a standard ingoing/outgoing mailbox system, costly, I've modified it. +; +; - Mailboxes are a mixture of code and data. This lets us greatly +; simplify the NCR53c810 code and do things that would otherwise +; not be possible. +; +; The saved data pointer is now implemented as follows : +; +; Control flow has been architected such that if control reaches +; munge_save_data_pointer, on a restore pointers message or +; reconnection, a jump to the address formerly in the TEMP register +; will allow the SCSI command to resume execution. +; + +; +; Note : the DSA structures must be aligned on 32 bit boundaries, +; since the source and destination of MOVE MEMORY instructions +; must share the same alignment and this is the alignment of the +; NCR registers. +; + +ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa +ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa +ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address + ; for current dsa +ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target + ; sync routine +ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa +ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command + ; saved data pointer +ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command + ; current residual code +ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command + ; saved residual code +ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand +ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to +ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value + +; +; Once a device has initiated reselection, we need to compare it +; against the singly linked list of commands which have disconnected +; and are pending reselection. These commands are maintained in +; an unordered singly linked list of DSA structures, through the +; DSA pointers at their 'centers' headed by the reconnect_dsa_head +; pointer. +; +; To avoid complications in removing commands from the list, +; I minimize the amount of expensive (at eight operations per +; addition @ 500-600ns each) pointer operations which must +; be done in the NCR driver by precomputing them on the +; host processor during dsa structure generation. +; +; The fixed-up per DSA code knows how to recognize the nexus +; associated with the corresponding SCSI command, and modifies +; the source and destination pointers for the MOVE MEMORY +; instruction which is executed when reselected_ok is called +; to remove the command from the list. Similarly, DSA is +; loaded with the address of the next DSA structure and +; reselected_check_next is called if a failure occurs. +; +; Perhaps more concisely, the net effect of the mess is +; +; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, +; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) { +; src = &dsa->next; +; if (target_id == dsa->id && target_lun == dsa->lun) { +; *dest = *src; +; break; +; } +; } +; +; if (!dsa) +; error (int_err_unexpected_reselect); +; else +; longjmp (dsa->jump_resume, 0); +; +; + + +; Define DSA structure used for mailboxes +ENTRY dsa_code_template +dsa_code_template: +ENTRY dsa_code_begin +dsa_code_begin: + MOVE dmode_memory_to_ncr TO DMODE + +at 0x00000000 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch + +at 0x00000002 : */ 0xc0000004,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000005 : */ 0x78380000,0x00000000, +/* + CALL scratch_to_dsa + +at 0x00000007 : */ 0x88080000,0x00000980, +/* + CALL select + +at 0x00000009 : */ 0x88080000,0x000001fc, +/* +; Handle the phase mismatch which may have resulted from the +; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN +; may or may not be necessary, and we should update script_asm.pl +; to handle multiple pieces. + CLEAR ATN + +at 0x0000000b : */ 0x60000008,0x00000000, +/* + CLEAR ACK + +at 0x0000000d : */ 0x60000040,0x00000000, +/* + +; Replace second operand with address of JUMP instruction dest operand +; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c. +ENTRY dsa_code_fix_jump +dsa_code_fix_jump: + MOVE MEMORY 4, NOP_insn, 0 + +at 0x0000000f : */ 0xc0000004,0x00000000,0x00000000, +/* + JUMP select_done + +at 0x00000012 : */ 0x80080000,0x00000224, +/* + +; wrong_dsa loads the DSA register with the value of the dsa_next +; field. +; +wrong_dsa: +; Patch the MOVE MEMORY INSTRUCTION such that +; the destination address is the address of the OLD +; next pointer. +; + MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok + 8 + +at 0x00000014 : */ 0xc0000004,0x00000000,0x00000758, +/* + MOVE dmode_memory_to_ncr TO DMODE + +at 0x00000017 : */ 0x78380000,0x00000000, +/* +; +; Move the _contents_ of the next pointer into the DSA register as +; the next I_T_L or I_T_L_Q tupple to check against the established +; nexus. +; + MOVE MEMORY 4, dsa_temp_next, addr_scratch + +at 0x00000019 : */ 0xc0000004,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x0000001c : */ 0x78380000,0x00000000, +/* + CALL scratch_to_dsa + +at 0x0000001e : */ 0x88080000,0x00000980, +/* + JUMP reselected_check_next + +at 0x00000020 : */ 0x80080000,0x000006a4, +/* + +ABSOLUTE dsa_save_data_pointer = 0 +ENTRY dsa_code_save_data_pointer +dsa_code_save_data_pointer: + MOVE dmode_ncr_to_memory TO DMODE + +at 0x00000022 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer + +at 0x00000024 : */ 0xc0000004,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000027 : */ 0x78380000,0x00000000, +/* +; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h + MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual + +at 0x00000029 : */ 0xc0000018,0x00000000,0x00000000, +/* + CLEAR ACK + +at 0x0000002c : */ 0x60000040,0x00000000, +/* + + + + RETURN + +at 0x0000002e : */ 0x90080000,0x00000000, +/* +ABSOLUTE dsa_restore_pointers = 0 +ENTRY dsa_code_restore_pointers +dsa_code_restore_pointers: + MOVE dmode_memory_to_ncr TO DMODE + +at 0x00000030 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp + +at 0x00000032 : */ 0xc0000004,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000035 : */ 0x78380000,0x00000000, +/* +; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h + MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual + +at 0x00000037 : */ 0xc0000018,0x00000000,0x00000000, +/* + CLEAR ACK + +at 0x0000003a : */ 0x60000040,0x00000000, +/* + + + + RETURN + +at 0x0000003c : */ 0x90080000,0x00000000, +/* + +ABSOLUTE dsa_check_reselect = 0 +; dsa_check_reselect determines whether or not the current target and +; lun match the current DSA +ENTRY dsa_code_check_reselect +dsa_code_check_reselect: + MOVE SSID TO SFBR ; SSID contains 3 bit target ID + +at 0x0000003e : */ 0x720a0000,0x00000000, +/* +; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips + JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8 + +at 0x00000040 : */ 0x8084f800,0x00ffff48, +/* +; +; Hack - move to scratch first, since SFBR is not writeable +; via the CPU and hence a MOVE MEMORY instruction. +; + MOVE dmode_memory_to_ncr TO DMODE + +at 0x00000042 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 1, reselected_identify, addr_scratch + +at 0x00000044 : */ 0xc0000001,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000047 : */ 0x78380000,0x00000000, +/* + MOVE SCRATCH0 TO SFBR + +at 0x00000049 : */ 0x72340000,0x00000000, +/* +; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips + JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8 + +at 0x0000004b : */ 0x8084f800,0x00ffff1c, +/* +; Patch the MOVE MEMORY INSTRUCTION such that +; the source address is the address of this dsa's +; next pointer. + MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok + 4 + +at 0x0000004d : */ 0xc0000004,0x00000000,0x00000754, +/* + CALL reselected_ok + +at 0x00000050 : */ 0x88080000,0x00000750, +/* + CALL dsa_temp_sync + +at 0x00000052 : */ 0x88080000,0x00000000, +/* +; Release ACK on the IDENTIFY message _after_ we've set the synchronous +; transfer parameters! + CLEAR ACK + +at 0x00000054 : */ 0x60000040,0x00000000, +/* +; Implicitly restore pointers on reselection, so a RETURN +; will transfer control back to the right spot. + CALL REL (dsa_code_restore_pointers) + +at 0x00000056 : */ 0x88880000,0x00ffff60, +/* + RETURN + +at 0x00000058 : */ 0x90080000,0x00000000, +/* +ENTRY dsa_zero +dsa_zero: +ENTRY dsa_code_template_end +dsa_code_template_end: + +; Perform sanity check for dsa_fields_start == dsa_code_template_end - +; dsa_zero, puke. + +ABSOLUTE dsa_fields_start = 0 ; Sanity marker + ; pad 48 bytes (fix this RSN) +ABSOLUTE dsa_next = 48 ; len 4 Next DSA + ; del 4 Previous DSA address +ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread. +ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for + ; table indirect select +ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for + ; select message +ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for + ; command +ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout +ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain +ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin +ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte +ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out + ; (Synchronous transfer negotiation, etc). +ABSOLUTE dsa_end = 112 + +ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next), + ; terminated by a call to JUMP wait_reselect + +; Linked lists of DSA structures +ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect +ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing + ; address of reconnect_dsa_head + +; These select the source and destination of a MOVE MEMORY instruction +ABSOLUTE dmode_memory_to_memory = 0x0 +ABSOLUTE dmode_memory_to_ncr = 0x0 +ABSOLUTE dmode_ncr_to_memory = 0x0 + +ABSOLUTE addr_scratch = 0x0 +ABSOLUTE addr_temp = 0x0 + + +; Interrupts - +; MSB indicates type +; 0 handle error condition +; 1 handle message +; 2 handle normal condition +; 3 debugging interrupt +; 4 testing interrupt +; Next byte indicates specific error + +; XXX not yet implemented, I'm not sure if I want to - +; Next byte indicates the routine the error occurred in +; The LSB indicates the specific place the error occurred + +ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered +ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED) +ABSOLUTE int_err_unexpected_reselect = 0x00020000 +ABSOLUTE int_err_check_condition = 0x00030000 +ABSOLUTE int_err_no_phase = 0x00040000 +ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received +ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received +ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message + ; received + +ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram + ; registers. +ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established +ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete +ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected +ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa +ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset. +ABSOLUTE int_debug_break = 0x03000000 ; Break point + +ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver + + +ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete +ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete +ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete + + +; These should start with 0x05000000, with low bits incrementing for +; each one. + + + +ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message +ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message +ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source +ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in +ABSOLUTE NOP_insn = 0 ; NOP instruction + +; Pointer to message, potentially multi-byte +ABSOLUTE msg_buf = 0 + +; Pointer to holding area for reselection information +ABSOLUTE reselected_identify = 0 +ABSOLUTE reselected_tag = 0 + +; Request sense command pointer, it's a 6 byte command, should +; be constant for all commands since we always want 16 bytes of +; sense and we don't need to change any fields as we did under +; SCSI-I when we actually cared about the LUN field. +;EXTERNAL NCR53c7xx_sense ; Request sense command + + +; dsa_schedule +; PURPOSE : after a DISCONNECT message has been received, and pointers +; saved, insert the current DSA structure at the head of the +; disconnected queue and fall through to the scheduler. +; +; CALLS : OK +; +; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list +; of disconnected commands +; +; MODIFIES : SCRATCH, reconnect_dsa_head +; +; EXITS : always passes control to schedule + +ENTRY dsa_schedule +dsa_schedule: + + + + +; +; Calculate the address of the next pointer within the DSA +; structure of the command that is currently disconnecting +; + CALL dsa_to_scratch + +at 0x0000005a : */ 0x88080000,0x00000938, +/* + MOVE SCRATCH0 + dsa_next TO SCRATCH0 + +at 0x0000005c : */ 0x7e343000,0x00000000, +/* + MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY + +at 0x0000005e : */ 0x7f350000,0x00000000, +/* + MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY + +at 0x00000060 : */ 0x7f360000,0x00000000, +/* + MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY + +at 0x00000062 : */ 0x7f370000,0x00000000, +/* + +; Point the next field of this DSA structure at the current disconnected +; list + MOVE dmode_ncr_to_memory TO DMODE + +at 0x00000064 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8 + +at 0x00000066 : */ 0xc0000004,0x00000000,0x000001b4, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000069 : */ 0x78380000,0x00000000, +/* +dsa_schedule_insert: + MOVE MEMORY 4, reconnect_dsa_head, 0 + +at 0x0000006b : */ 0xc0000004,0x00000000,0x00000000, +/* + +; And update the head pointer. + CALL dsa_to_scratch + +at 0x0000006e : */ 0x88080000,0x00000938, +/* + MOVE dmode_ncr_to_memory TO DMODE + +at 0x00000070 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, reconnect_dsa_head + +at 0x00000072 : */ 0xc0000004,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000075 : */ 0x78380000,0x00000000, +/* + + + MOVE SCNTL2 & 0x7f TO SCNTL2 + +at 0x00000077 : */ 0x7c027f00,0x00000000, +/* + CLEAR ACK + +at 0x00000079 : */ 0x60000040,0x00000000, +/* + + WAIT DISCONNECT + +at 0x0000007b : */ 0x48000000,0x00000000, +/* + + + + + + + JUMP schedule + +at 0x0000007d : */ 0x80080000,0x00000000, +/* + + +; +; select +; +; PURPOSE : establish a nexus for the SCSI command referenced by DSA. +; On success, the current DSA structure is removed from the issue +; queue. Usually, this is entered as a fall-through from schedule, +; although the contingent allegiance handling code will write +; the select entry address to the DSP to restart a command as a +; REQUEST SENSE. A message is sent (usually IDENTIFY, although +; additional SDTR or WDTR messages may be sent). COMMAND OUT +; is handled. +; +; INPUTS : DSA - SCSI command, issue_dsa_head +; +; CALLS : NOT OK +; +; MODIFIES : SCRATCH, issue_dsa_head +; +; EXITS : on reselection or selection, go to select_failed +; otherwise, RETURN so control is passed back to +; dsa_begin. +; + +ENTRY select +select: + + + + + + + + + + + + + CLEAR TARGET + +at 0x0000007f : */ 0x60000200,0x00000000, +/* + +; XXX +; +; In effect, SELECTION operations are backgrounded, with execution +; continuing until code which waits for REQ or a fatal interrupt is +; encountered. +; +; So, for more performance, we could overlap the code which removes +; the command from the NCRs issue queue with the selection, but +; at this point I don't want to deal with the error recovery. +; + + + SELECT ATN FROM dsa_select, select_failed + +at 0x00000081 : */ 0x4300003c,0x000007a4, +/* + JUMP select_msgout, WHEN MSG_OUT + +at 0x00000083 : */ 0x860b0000,0x00000214, +/* +ENTRY select_msgout +select_msgout: + MOVE FROM dsa_msgout, WHEN MSG_OUT + +at 0x00000085 : */ 0x1e000000,0x00000040, +/* + + + + + + + + + + + RETURN + +at 0x00000087 : */ 0x90080000,0x00000000, +/* + +; +; select_done +; +; PURPOSE: continue on to normal data transfer; called as the exit +; point from dsa_begin. +; +; INPUTS: dsa +; +; CALLS: OK +; +; + +select_done: + + + + + + + +; After a successful selection, we should get either a CMD phase or +; some transfer request negotiation message. + + JUMP cmdout, WHEN CMD + +at 0x00000089 : */ 0x820b0000,0x00000244, +/* + INT int_err_unexpected_phase, WHEN NOT MSG_IN + +at 0x0000008b : */ 0x9f030000,0x00000000, +/* + +select_msg_in: + CALL msg_in, WHEN MSG_IN + +at 0x0000008d : */ 0x8f0b0000,0x00000404, +/* + JUMP select_msg_in, WHEN MSG_IN + +at 0x0000008f : */ 0x870b0000,0x00000234, +/* + +cmdout: + INT int_err_unexpected_phase, WHEN NOT CMD + +at 0x00000091 : */ 0x9a030000,0x00000000, +/* + + + +ENTRY cmdout_cmdout +cmdout_cmdout: + + MOVE FROM dsa_cmdout, WHEN CMD + +at 0x00000093 : */ 0x1a000000,0x00000048, +/* + + + + +; +; data_transfer +; other_out +; other_in +; other_transfer +; +; PURPOSE : handle the main data transfer for a SCSI command in +; several parts. In the first part, data_transfer, DATA_IN +; and DATA_OUT phases are allowed, with the user provided +; code (usually dynamically generated based on the scatter/gather +; list associated with a SCSI command) called to handle these +; phases. +; +; After control has passed to one of the user provided +; DATA_IN or DATA_OUT routines, back calls are made to +; other_transfer_in or other_transfer_out to handle non-DATA IN +; and DATA OUT phases respectively, with the state of the active +; data pointer being preserved in TEMP. +; +; On completion, the user code passes control to other_transfer +; which causes DATA_IN and DATA_OUT to result in unexpected_phase +; interrupts so that data overruns may be trapped. +; +; INPUTS : DSA - SCSI command +; +; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in +; other_transfer +; +; MODIFIES : SCRATCH +; +; EXITS : if STATUS IN is detected, signifying command completion, +; the NCR jumps to command_complete. If MSG IN occurs, a +; CALL is made to msg_in. Otherwise, other_transfer runs in +; an infinite loop. +; + +ENTRY data_transfer +data_transfer: + JUMP cmdout_cmdout, WHEN CMD + +at 0x00000095 : */ 0x820b0000,0x0000024c, +/* + CALL msg_in, WHEN MSG_IN + +at 0x00000097 : */ 0x8f0b0000,0x00000404, +/* + INT int_err_unexpected_phase, WHEN MSG_OUT + +at 0x00000099 : */ 0x9e0b0000,0x00000000, +/* + JUMP do_dataout, WHEN DATA_OUT + +at 0x0000009b : */ 0x800b0000,0x0000028c, +/* + JUMP do_datain, WHEN DATA_IN + +at 0x0000009d : */ 0x810b0000,0x000002e4, +/* + JUMP command_complete, WHEN STATUS + +at 0x0000009f : */ 0x830b0000,0x0000060c, +/* + JUMP data_transfer + +at 0x000000a1 : */ 0x80080000,0x00000254, +/* +ENTRY end_data_transfer +end_data_transfer: + +; +; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain +; should be fixed up whenever the nexus changes so it can point to the +; correct routine for that command. +; + + +; Nasty jump to dsa->dataout +do_dataout: + CALL dsa_to_scratch + +at 0x000000a3 : */ 0x88080000,0x00000938, +/* + MOVE SCRATCH0 + dsa_dataout TO SCRATCH0 + +at 0x000000a5 : */ 0x7e345000,0x00000000, +/* + MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY + +at 0x000000a7 : */ 0x7f350000,0x00000000, +/* + MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY + +at 0x000000a9 : */ 0x7f360000,0x00000000, +/* + MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY + +at 0x000000ab : */ 0x7f370000,0x00000000, +/* + MOVE dmode_ncr_to_memory TO DMODE + +at 0x000000ad : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4 + +at 0x000000af : */ 0xc0000004,0x00000000,0x000002d4, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x000000b2 : */ 0x78380000,0x00000000, +/* +dataout_to_jump: + MOVE MEMORY 4, 0, dataout_jump + 4 + +at 0x000000b4 : */ 0xc0000004,0x00000000,0x000002e0, +/* +dataout_jump: + JUMP 0 + +at 0x000000b7 : */ 0x80080000,0x00000000, +/* + +; Nasty jump to dsa->dsain +do_datain: + CALL dsa_to_scratch + +at 0x000000b9 : */ 0x88080000,0x00000938, +/* + MOVE SCRATCH0 + dsa_datain TO SCRATCH0 + +at 0x000000bb : */ 0x7e345400,0x00000000, +/* + MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY + +at 0x000000bd : */ 0x7f350000,0x00000000, +/* + MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY + +at 0x000000bf : */ 0x7f360000,0x00000000, +/* + MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY + +at 0x000000c1 : */ 0x7f370000,0x00000000, +/* + MOVE dmode_ncr_to_memory TO DMODE + +at 0x000000c3 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, datain_to_jump + 4 + +at 0x000000c5 : */ 0xc0000004,0x00000000,0x0000032c, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x000000c8 : */ 0x78380000,0x00000000, +/* +ENTRY datain_to_jump +datain_to_jump: + MOVE MEMORY 4, 0, datain_jump + 4 + +at 0x000000ca : */ 0xc0000004,0x00000000,0x00000338, +/* + + + +datain_jump: + JUMP 0 + +at 0x000000cd : */ 0x80080000,0x00000000, +/* + + + +; Note that other_out and other_in loop until a non-data phase +; is discovered, so we only execute return statements when we +; can go on to the next data phase block move statement. + +ENTRY other_out +other_out: + + + + INT int_err_unexpected_phase, WHEN CMD + +at 0x000000cf : */ 0x9a0b0000,0x00000000, +/* + JUMP msg_in_restart, WHEN MSG_IN + +at 0x000000d1 : */ 0x870b0000,0x000003e4, +/* + INT int_err_unexpected_phase, WHEN MSG_OUT + +at 0x000000d3 : */ 0x9e0b0000,0x00000000, +/* + INT int_err_unexpected_phase, WHEN DATA_IN + +at 0x000000d5 : */ 0x990b0000,0x00000000, +/* + JUMP command_complete, WHEN STATUS + +at 0x000000d7 : */ 0x830b0000,0x0000060c, +/* + JUMP other_out, WHEN NOT DATA_OUT + +at 0x000000d9 : */ 0x80030000,0x0000033c, +/* + RETURN + +at 0x000000db : */ 0x90080000,0x00000000, +/* + +ENTRY other_in +other_in: + + + + INT int_err_unexpected_phase, WHEN CMD + +at 0x000000dd : */ 0x9a0b0000,0x00000000, +/* + JUMP msg_in_restart, WHEN MSG_IN + +at 0x000000df : */ 0x870b0000,0x000003e4, +/* + INT int_err_unexpected_phase, WHEN MSG_OUT + +at 0x000000e1 : */ 0x9e0b0000,0x00000000, +/* + INT int_err_unexpected_phase, WHEN DATA_OUT + +at 0x000000e3 : */ 0x980b0000,0x00000000, +/* + JUMP command_complete, WHEN STATUS + +at 0x000000e5 : */ 0x830b0000,0x0000060c, +/* + JUMP other_in, WHEN NOT DATA_IN + +at 0x000000e7 : */ 0x81030000,0x00000374, +/* + RETURN + +at 0x000000e9 : */ 0x90080000,0x00000000, +/* + + +ENTRY other_transfer +other_transfer: + INT int_err_unexpected_phase, WHEN CMD + +at 0x000000eb : */ 0x9a0b0000,0x00000000, +/* + CALL msg_in, WHEN MSG_IN + +at 0x000000ed : */ 0x8f0b0000,0x00000404, +/* + INT int_err_unexpected_phase, WHEN MSG_OUT + +at 0x000000ef : */ 0x9e0b0000,0x00000000, +/* + INT int_err_unexpected_phase, WHEN DATA_OUT + +at 0x000000f1 : */ 0x980b0000,0x00000000, +/* + INT int_err_unexpected_phase, WHEN DATA_IN + +at 0x000000f3 : */ 0x990b0000,0x00000000, +/* + JUMP command_complete, WHEN STATUS + +at 0x000000f5 : */ 0x830b0000,0x0000060c, +/* + JUMP other_transfer + +at 0x000000f7 : */ 0x80080000,0x000003ac, +/* + +; +; msg_in_restart +; msg_in +; munge_msg +; +; PURPOSE : process messages from a target. msg_in is called when the +; caller hasn't read the first byte of the message. munge_message +; is called when the caller has read the first byte of the message, +; and left it in SFBR. msg_in_restart is called when the caller +; hasn't read the first byte of the message, and wishes RETURN +; to transfer control back to the address of the conditional +; CALL instruction rather than to the instruction after it. +; +; Various int_* interrupts are generated when the host system +; needs to intervene, as is the case with SDTR, WDTR, and +; INITIATE RECOVERY messages. +; +; When the host system handles one of these interrupts, +; it can respond by reentering at reject_message, +; which rejects the message and returns control to +; the caller of msg_in or munge_msg, accept_message +; which clears ACK and returns control, or reply_message +; which sends the message pointed to by the DSA +; msgout_other table indirect field. +; +; DISCONNECT messages are handled by moving the command +; to the reconnect_dsa_queue. +; +; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg +; only) +; +; CALLS : NO. The TEMP register isn't backed up to allow nested calls. +; +; MODIFIES : SCRATCH, DSA on DISCONNECT +; +; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS, +; and normal return from message handlers running under +; Linux, control is returned to the caller. Receipt +; of DISCONNECT messages pass control to dsa_schedule. +; +ENTRY msg_in_restart +msg_in_restart: +; XXX - hackish +; +; Since it's easier to debug changes to the statically +; compiled code, rather than the dynamically generated +; stuff, such as +; +; MOVE x, y, WHEN data_phase +; CALL other_z, WHEN NOT data_phase +; MOVE x, y, WHEN data_phase +; +; I'd like to have certain routines (notably the message handler) +; restart on the conditional call rather than the next instruction. +; +; So, subtract 8 from the return address + + MOVE TEMP0 + 0xf8 TO TEMP0 + +at 0x000000f9 : */ 0x7e1cf800,0x00000000, +/* + MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY + +at 0x000000fb : */ 0x7f1dff00,0x00000000, +/* + MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY + +at 0x000000fd : */ 0x7f1eff00,0x00000000, +/* + MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY + +at 0x000000ff : */ 0x7f1fff00,0x00000000, +/* + +ENTRY msg_in +msg_in: + MOVE 1, msg_buf, WHEN MSG_IN + +at 0x00000101 : */ 0x0f000001,0x00000000, +/* + +munge_msg: + JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE + +at 0x00000103 : */ 0x800c0001,0x00000524, +/* + JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message + +at 0x00000105 : */ 0x800cdf20,0x0000044c, +/* +; +; XXX - I've seen a handful of broken SCSI devices which fail to issue +; a SAVE POINTERS message before disconnecting in the middle of +; a transfer, assuming that the DATA POINTER will be implicitly +; restored. +; +; Historically, I've often done an implicit save when the DISCONNECT +; message is processed. We may want to consider having the option of +; doing that here. +; + JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER + +at 0x00000107 : */ 0x800c0002,0x00000454, +/* + JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS + +at 0x00000109 : */ 0x800c0003,0x000004b8, +/* + JUMP munge_disconnect, IF 0x04 ; DISCONNECT + +at 0x0000010b : */ 0x800c0004,0x0000051c, +/* + INT int_msg_1, IF 0x07 ; MESSAGE REJECT + +at 0x0000010d : */ 0x980c0007,0x01020000, +/* + INT int_msg_1, IF 0x0f ; INITIATE RECOVERY + +at 0x0000010f : */ 0x980c000f,0x01020000, +/* + + + + JUMP reject_message + +at 0x00000111 : */ 0x80080000,0x000005b4, +/* + +munge_2: + JUMP reject_message + +at 0x00000113 : */ 0x80080000,0x000005b4, +/* +; +; The SCSI standard allows targets to recover from transient +; error conditions by backing up the data pointer with a +; RESTORE POINTERS message. +; +; So, we must save and restore the _residual_ code as well as +; the current instruction pointer. Because of this messiness, +; it is simpler to put dynamic code in the dsa for this and to +; just do a simple jump down there. +; + +munge_save_data_pointer: + MOVE DSA0 + dsa_save_data_pointer TO SFBR + +at 0x00000115 : */ 0x76100000,0x00000000, +/* + MOVE SFBR TO SCRATCH0 + +at 0x00000117 : */ 0x6a340000,0x00000000, +/* + MOVE DSA1 + 0xff TO SFBR WITH CARRY + +at 0x00000119 : */ 0x7711ff00,0x00000000, +/* + MOVE SFBR TO SCRATCH1 + +at 0x0000011b : */ 0x6a350000,0x00000000, +/* + MOVE DSA2 + 0xff TO SFBR WITH CARRY + +at 0x0000011d : */ 0x7712ff00,0x00000000, +/* + MOVE SFBR TO SCRATCH2 + +at 0x0000011f : */ 0x6a360000,0x00000000, +/* + MOVE DSA3 + 0xff TO SFBR WITH CARRY + +at 0x00000121 : */ 0x7713ff00,0x00000000, +/* + MOVE SFBR TO SCRATCH3 + +at 0x00000123 : */ 0x6a370000,0x00000000, +/* + + MOVE dmode_ncr_to_memory TO DMODE + +at 0x00000125 : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4 + +at 0x00000127 : */ 0xc0000004,0x00000000,0x000004b4, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x0000012a : */ 0x78380000,0x00000000, +/* +jump_dsa_save: + JUMP 0 + +at 0x0000012c : */ 0x80080000,0x00000000, +/* + +munge_restore_pointers: + MOVE DSA0 + dsa_restore_pointers TO SFBR + +at 0x0000012e : */ 0x76100000,0x00000000, +/* + MOVE SFBR TO SCRATCH0 + +at 0x00000130 : */ 0x6a340000,0x00000000, +/* + MOVE DSA1 + 0xff TO SFBR WITH CARRY + +at 0x00000132 : */ 0x7711ff00,0x00000000, +/* + MOVE SFBR TO SCRATCH1 + +at 0x00000134 : */ 0x6a350000,0x00000000, +/* + MOVE DSA2 + 0xff TO SFBR WITH CARRY + +at 0x00000136 : */ 0x7712ff00,0x00000000, +/* + MOVE SFBR TO SCRATCH2 + +at 0x00000138 : */ 0x6a360000,0x00000000, +/* + MOVE DSA3 + 0xff TO SFBR WITH CARRY + +at 0x0000013a : */ 0x7713ff00,0x00000000, +/* + MOVE SFBR TO SCRATCH3 + +at 0x0000013c : */ 0x6a370000,0x00000000, +/* + + MOVE dmode_ncr_to_memory TO DMODE + +at 0x0000013e : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4 + +at 0x00000140 : */ 0xc0000004,0x00000000,0x00000518, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000143 : */ 0x78380000,0x00000000, +/* +jump_dsa_restore: + JUMP 0 + +at 0x00000145 : */ 0x80080000,0x00000000, +/* + + +munge_disconnect: + + + + + + + + + + + + + + + + + JUMP dsa_schedule + +at 0x00000147 : */ 0x80080000,0x00000168, +/* + + + + + +munge_extended: + CLEAR ACK + +at 0x00000149 : */ 0x60000040,0x00000000, +/* + INT int_err_unexpected_phase, WHEN NOT MSG_IN + +at 0x0000014b : */ 0x9f030000,0x00000000, +/* + MOVE 1, msg_buf + 1, WHEN MSG_IN + +at 0x0000014d : */ 0x0f000001,0x00000001, +/* + JUMP munge_extended_2, IF 0x02 + +at 0x0000014f : */ 0x800c0002,0x00000554, +/* + JUMP munge_extended_3, IF 0x03 + +at 0x00000151 : */ 0x800c0003,0x00000584, +/* + JUMP reject_message + +at 0x00000153 : */ 0x80080000,0x000005b4, +/* + +munge_extended_2: + CLEAR ACK + +at 0x00000155 : */ 0x60000040,0x00000000, +/* + MOVE 1, msg_buf + 2, WHEN MSG_IN + +at 0x00000157 : */ 0x0f000001,0x00000002, +/* + JUMP reject_message, IF NOT 0x02 ; Must be WDTR + +at 0x00000159 : */ 0x80040002,0x000005b4, +/* + CLEAR ACK + +at 0x0000015b : */ 0x60000040,0x00000000, +/* + MOVE 1, msg_buf + 3, WHEN MSG_IN + +at 0x0000015d : */ 0x0f000001,0x00000003, +/* + INT int_msg_wdtr + +at 0x0000015f : */ 0x98080000,0x01000000, +/* + +munge_extended_3: + CLEAR ACK + +at 0x00000161 : */ 0x60000040,0x00000000, +/* + MOVE 1, msg_buf + 2, WHEN MSG_IN + +at 0x00000163 : */ 0x0f000001,0x00000002, +/* + JUMP reject_message, IF NOT 0x01 ; Must be SDTR + +at 0x00000165 : */ 0x80040001,0x000005b4, +/* + CLEAR ACK + +at 0x00000167 : */ 0x60000040,0x00000000, +/* + MOVE 2, msg_buf + 3, WHEN MSG_IN + +at 0x00000169 : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr + +at 0x0000016b : */ 0x98080000,0x01010000, +/* + +ENTRY reject_message +reject_message: + SET ATN + +at 0x0000016d : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x0000016f : */ 0x60000040,0x00000000, +/* + MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT + +at 0x00000171 : */ 0x0e000001,0x00000000, +/* + RETURN + +at 0x00000173 : */ 0x90080000,0x00000000, +/* + +ENTRY accept_message +accept_message: + CLEAR ATN + +at 0x00000175 : */ 0x60000008,0x00000000, +/* + CLEAR ACK + +at 0x00000177 : */ 0x60000040,0x00000000, +/* + RETURN + +at 0x00000179 : */ 0x90080000,0x00000000, +/* + +ENTRY respond_message +respond_message: + SET ATN + +at 0x0000017b : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x0000017d : */ 0x60000040,0x00000000, +/* + MOVE FROM dsa_msgout_other, WHEN MSG_OUT + +at 0x0000017f : */ 0x1e000000,0x00000068, +/* + RETURN + +at 0x00000181 : */ 0x90080000,0x00000000, +/* + +; +; command_complete +; +; PURPOSE : handle command termination when STATUS IN is detected by reading +; a status byte followed by a command termination message. +; +; Normal termination results in an INTFLY instruction, and +; the host system can pick out which command terminated by +; examining the MESSAGE and STATUS buffers of all currently +; executing commands; +; +; Abnormal (CHECK_CONDITION) termination results in an +; int_err_check_condition interrupt so that a REQUEST SENSE +; command can be issued out-of-order so that no other command +; clears the contingent allegiance condition. +; +; +; INPUTS : DSA - command +; +; CALLS : OK +; +; EXITS : On successful termination, control is passed to schedule. +; On abnormal termination, the user will usually modify the +; DSA fields and corresponding buffers and return control +; to select. +; + +ENTRY command_complete +command_complete: + MOVE FROM dsa_status, WHEN STATUS + +at 0x00000183 : */ 0x1b000000,0x00000060, +/* + + MOVE SFBR TO SCRATCH0 ; Save status + +at 0x00000185 : */ 0x6a340000,0x00000000, +/* + +ENTRY command_complete_msgin +command_complete_msgin: + MOVE FROM dsa_msgin, WHEN MSG_IN + +at 0x00000187 : */ 0x1f000000,0x00000058, +/* +; Indicate that we should be expecting a disconnect + MOVE SCNTL2 & 0x7f TO SCNTL2 + +at 0x00000189 : */ 0x7c027f00,0x00000000, +/* + CLEAR ACK + +at 0x0000018b : */ 0x60000040,0x00000000, +/* + + WAIT DISCONNECT + +at 0x0000018d : */ 0x48000000,0x00000000, +/* + +; +; The SCSI specification states that when a UNIT ATTENTION condition +; is pending, as indicated by a CHECK CONDITION status message, +; the target shall revert to asynchronous transfers. Since +; synchronous transfers parameters are maintained on a per INITIATOR/TARGET +; basis, and returning control to our scheduler could work on a command +; running on another lun on that target using the old parameters, we must +; interrupt the host processor to get them changed, or change them ourselves. +; +; Once SCSI-II tagged queueing is implemented, things will be even more +; hairy, since contingent allegiance conditions exist on a per-target/lun +; basis, and issuing a new command with a different tag would clear it. +; In these cases, we must interrupt the host processor to get a request +; added to the HEAD of the queue with the request sense command, or we +; must automatically issue the request sense command. + + + + + + INTFLY + +at 0x0000018f : */ 0x98180000,0x00000000, +/* + + + + + + JUMP schedule + +at 0x00000191 : */ 0x80080000,0x00000000, +/* +command_failed: + INT int_err_check_condition + +at 0x00000193 : */ 0x98080000,0x00030000, +/* + + + + +; +; wait_reselect +; +; PURPOSE : This is essentially the idle routine, where control lands +; when there are no new processes to schedule. wait_reselect +; waits for reselection, selection, and new commands. +; +; When a successful reselection occurs, with the aid +; of fixed up code in each DSA, wait_reselect walks the +; reconnect_dsa_queue, asking each dsa if the target ID +; and LUN match its. +; +; If a match is found, a call is made back to reselected_ok, +; which through the miracles of self modifying code, extracts +; the found DSA from the reconnect_dsa_queue and then +; returns control to the DSAs thread of execution. +; +; INPUTS : NONE +; +; CALLS : OK +; +; MODIFIES : DSA, +; +; EXITS : On successful reselection, control is returned to the +; DSA which called reselected_ok. If the WAIT RESELECT +; was interrupted by a new commands arrival signaled by +; SIG_P, control is passed to schedule. If the NCR is +; selected, the host system is interrupted with an +; int_err_selected which is usually responded to by +; setting DSP to the target_abort address. + +ENTRY wait_reselect +wait_reselect: + + + + + + + WAIT RESELECT wait_reselect_failed + +at 0x00000195 : */ 0x50000000,0x0000076c, +/* + +reselected: + + + + CLEAR TARGET + +at 0x00000197 : */ 0x60000200,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x00000199 : */ 0x78380000,0x00000000, +/* + ; Read all data needed to reestablish the nexus - + MOVE 1, reselected_identify, WHEN MSG_IN + +at 0x0000019b : */ 0x0f000001,0x00000000, +/* + ; We used to CLEAR ACK here. + + + + + + ; Point DSA at the current head of the disconnected queue. + MOVE dmode_memory_to_ncr TO DMODE + +at 0x0000019d : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, reconnect_dsa_head, addr_scratch + +at 0x0000019f : */ 0xc0000004,0x00000000,0x00000000, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x000001a2 : */ 0x78380000,0x00000000, +/* + CALL scratch_to_dsa + +at 0x000001a4 : */ 0x88080000,0x00000980, +/* + + ; Fix the update-next pointer so that the reconnect_dsa_head + ; pointer is the one that will be updated if this DSA is a hit + ; and we remove it from the queue. + + MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok + 8 + +at 0x000001a6 : */ 0xc0000004,0x00000000,0x00000758, +/* + +ENTRY reselected_check_next +reselected_check_next: + + + + ; Check for a NULL pointer. + MOVE DSA0 TO SFBR + +at 0x000001a9 : */ 0x72100000,0x00000000, +/* + JUMP reselected_not_end, IF NOT 0 + +at 0x000001ab : */ 0x80040000,0x000006ec, +/* + MOVE DSA1 TO SFBR + +at 0x000001ad : */ 0x72110000,0x00000000, +/* + JUMP reselected_not_end, IF NOT 0 + +at 0x000001af : */ 0x80040000,0x000006ec, +/* + MOVE DSA2 TO SFBR + +at 0x000001b1 : */ 0x72120000,0x00000000, +/* + JUMP reselected_not_end, IF NOT 0 + +at 0x000001b3 : */ 0x80040000,0x000006ec, +/* + MOVE DSA3 TO SFBR + +at 0x000001b5 : */ 0x72130000,0x00000000, +/* + JUMP reselected_not_end, IF NOT 0 + +at 0x000001b7 : */ 0x80040000,0x000006ec, +/* + INT int_err_unexpected_reselect + +at 0x000001b9 : */ 0x98080000,0x00020000, +/* + +reselected_not_end: + ; + ; XXX the ALU is only eight bits wide, and the assembler + ; wont do the dirt work for us. As long as dsa_check_reselect + ; is negative, we need to sign extend with 1 bits to the full + ; 32 bit width of the address. + ; + ; A potential work around would be to have a known alignment + ; of the DSA structure such that the base address plus + ; dsa_check_reselect doesn't require carrying from bytes + ; higher than the LSB. + ; + + MOVE DSA0 TO SFBR + +at 0x000001bb : */ 0x72100000,0x00000000, +/* + MOVE SFBR + dsa_check_reselect TO SCRATCH0 + +at 0x000001bd : */ 0x6e340000,0x00000000, +/* + MOVE DSA1 TO SFBR + +at 0x000001bf : */ 0x72110000,0x00000000, +/* + MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY + +at 0x000001c1 : */ 0x6f35ff00,0x00000000, +/* + MOVE DSA2 TO SFBR + +at 0x000001c3 : */ 0x72120000,0x00000000, +/* + MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY + +at 0x000001c5 : */ 0x6f36ff00,0x00000000, +/* + MOVE DSA3 TO SFBR + +at 0x000001c7 : */ 0x72130000,0x00000000, +/* + MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY + +at 0x000001c9 : */ 0x6f37ff00,0x00000000, +/* + + MOVE dmode_ncr_to_memory TO DMODE + +at 0x000001cb : */ 0x78380000,0x00000000, +/* + MOVE MEMORY 4, addr_scratch, reselected_check + 4 + +at 0x000001cd : */ 0xc0000004,0x00000000,0x0000074c, +/* + MOVE dmode_memory_to_memory TO DMODE + +at 0x000001d0 : */ 0x78380000,0x00000000, +/* +reselected_check: + JUMP 0 + +at 0x000001d2 : */ 0x80080000,0x00000000, +/* + + +; +; +ENTRY reselected_ok +reselected_ok: + MOVE MEMORY 4, 0, 0 ; Patched : first word + +at 0x000001d4 : */ 0xc0000004,0x00000000,0x00000000, +/* + ; is address of + ; successful dsa_next + ; Second word is last + ; unsuccessful dsa_next, + ; starting with + ; dsa_reconnect_head + ; We used to CLEAR ACK here. + + + + + + + RETURN ; Return control to where + +at 0x000001d7 : */ 0x90080000,0x00000000, +/* + + + + +selected: + INT int_err_selected; + +at 0x000001d9 : */ 0x98080000,0x00010000, +/* + +; +; A select or reselect failure can be caused by one of two conditions : +; 1. SIG_P was set. This will be the case if the user has written +; a new value to a previously NULL head of the issue queue. +; +; 2. The NCR53c810 was selected or reselected by another device. +; +; 3. The bus was already busy since we were selected or reselected +; before starting the command. + +wait_reselect_failed: + + + +; Check selected bit. + MOVE SIST0 & 0x20 TO SFBR + +at 0x000001db : */ 0x74422000,0x00000000, +/* + JUMP selected, IF 0x20 + +at 0x000001dd : */ 0x800c0020,0x00000764, +/* +; Reading CTEST2 clears the SIG_P bit in the ISTAT register. + MOVE CTEST2 & 0x40 TO SFBR + +at 0x000001df : */ 0x741a4000,0x00000000, +/* + JUMP schedule, IF 0x40 + +at 0x000001e1 : */ 0x800c0040,0x00000000, +/* +; Check connected bit. +; FIXME: this needs to change if we support target mode + MOVE ISTAT & 0x08 TO SFBR + +at 0x000001e3 : */ 0x74140800,0x00000000, +/* + JUMP reselected, IF 0x08 + +at 0x000001e5 : */ 0x800c0008,0x0000065c, +/* +; FIXME : Something bogus happened, and we shouldn't fail silently. + + + + INT int_debug_panic + +at 0x000001e7 : */ 0x98080000,0x030b0000, +/* + + + +select_failed: + + + +; Otherwise, mask the selected and reselected bits off SIST0 + MOVE SIST0 & 0x30 TO SFBR + +at 0x000001e9 : */ 0x74423000,0x00000000, +/* + JUMP selected, IF 0x20 + +at 0x000001eb : */ 0x800c0020,0x00000764, +/* + JUMP reselected, IF 0x10 + +at 0x000001ed : */ 0x800c0010,0x0000065c, +/* +; If SIGP is set, the user just gave us another command, and +; we should restart or return to the scheduler. +; Reading CTEST2 clears the SIG_P bit in the ISTAT register. + MOVE CTEST2 & 0x40 TO SFBR + +at 0x000001ef : */ 0x741a4000,0x00000000, +/* + JUMP select, IF 0x40 + +at 0x000001f1 : */ 0x800c0040,0x000001fc, +/* +; Check connected bit. +; FIXME: this needs to change if we support target mode +; FIXME: is this really necessary? + MOVE ISTAT & 0x08 TO SFBR + +at 0x000001f3 : */ 0x74140800,0x00000000, +/* + JUMP reselected, IF 0x08 + +at 0x000001f5 : */ 0x800c0008,0x0000065c, +/* +; FIXME : Something bogus happened, and we shouldn't fail silently. + + + + INT int_debug_panic + +at 0x000001f7 : */ 0x98080000,0x030b0000, +/* + + +; +; test_1 +; test_2 +; +; PURPOSE : run some verification tests on the NCR. test_1 +; copies test_src to test_dest and interrupts the host +; processor, testing for cache coherency and interrupt +; problems in the processes. +; +; test_2 runs a command with offsets relative to the +; DSA on entry, and is useful for miscellaneous experimentation. +; + +; Verify that interrupts are working correctly and that we don't +; have a cache invalidation problem. + +ABSOLUTE test_src = 0, test_dest = 0 +ENTRY test_1 +test_1: + MOVE MEMORY 4, test_src, test_dest + +at 0x000001f9 : */ 0xc0000004,0x00000000,0x00000000, +/* + INT int_test_1 + +at 0x000001fc : */ 0x98080000,0x04000000, +/* + +; +; Run arbitrary commands, with test code establishing a DSA +; + +ENTRY test_2 +test_2: + CLEAR TARGET + +at 0x000001fe : */ 0x60000200,0x00000000, +/* + SELECT ATN FROM 0, test_2_fail + +at 0x00000200 : */ 0x43000000,0x00000850, +/* + JUMP test_2_msgout, WHEN MSG_OUT + +at 0x00000202 : */ 0x860b0000,0x00000810, +/* +ENTRY test_2_msgout +test_2_msgout: + MOVE FROM 8, WHEN MSG_OUT + +at 0x00000204 : */ 0x1e000000,0x00000008, +/* + MOVE FROM 16, WHEN CMD + +at 0x00000206 : */ 0x1a000000,0x00000010, +/* + MOVE FROM 24, WHEN DATA_IN + +at 0x00000208 : */ 0x19000000,0x00000018, +/* + MOVE FROM 32, WHEN STATUS + +at 0x0000020a : */ 0x1b000000,0x00000020, +/* + MOVE FROM 40, WHEN MSG_IN + +at 0x0000020c : */ 0x1f000000,0x00000028, +/* + MOVE SCNTL2 & 0x7f TO SCNTL2 + +at 0x0000020e : */ 0x7c027f00,0x00000000, +/* + CLEAR ACK + +at 0x00000210 : */ 0x60000040,0x00000000, +/* + WAIT DISCONNECT + +at 0x00000212 : */ 0x48000000,0x00000000, +/* +test_2_fail: + INT int_test_2 + +at 0x00000214 : */ 0x98080000,0x04010000, +/* + +ENTRY debug_break +debug_break: + INT int_debug_break + +at 0x00000216 : */ 0x98080000,0x03000000, +/* + +; +; initiator_abort +; target_abort +; +; PURPOSE : Abort the currently established nexus from with initiator +; or target mode. +; +; + +ENTRY target_abort +target_abort: + SET TARGET + +at 0x00000218 : */ 0x58000200,0x00000000, +/* + DISCONNECT + +at 0x0000021a : */ 0x48000000,0x00000000, +/* + CLEAR TARGET + +at 0x0000021c : */ 0x60000200,0x00000000, +/* + JUMP schedule + +at 0x0000021e : */ 0x80080000,0x00000000, +/* + +ENTRY initiator_abort +initiator_abort: + SET ATN + +at 0x00000220 : */ 0x58000008,0x00000000, +/* +; +; The SCSI-I specification says that targets may go into MSG out at +; their leisure upon receipt of the ATN single. On all versions of the +; specification, we can't change phases until REQ transitions true->false, +; so we need to sink/source one byte of data to allow the transition. +; +; For the sake of safety, we'll only source one byte of data in all +; cases, but to accommodate the SCSI-I dain bramage, we'll sink an +; arbitrary number of bytes. + JUMP spew_cmd, WHEN CMD + +at 0x00000222 : */ 0x820b0000,0x000008b8, +/* + JUMP eat_msgin, WHEN MSG_IN + +at 0x00000224 : */ 0x870b0000,0x000008c8, +/* + JUMP eat_datain, WHEN DATA_IN + +at 0x00000226 : */ 0x810b0000,0x000008f8, +/* + JUMP eat_status, WHEN STATUS + +at 0x00000228 : */ 0x830b0000,0x000008e0, +/* + JUMP spew_dataout, WHEN DATA_OUT + +at 0x0000022a : */ 0x800b0000,0x00000910, +/* + JUMP sated + +at 0x0000022c : */ 0x80080000,0x00000918, +/* +spew_cmd: + MOVE 1, NCR53c7xx_zero, WHEN CMD + +at 0x0000022e : */ 0x0a000001,0x00000000, +/* + JUMP sated + +at 0x00000230 : */ 0x80080000,0x00000918, +/* +eat_msgin: + MOVE 1, NCR53c7xx_sink, WHEN MSG_IN + +at 0x00000232 : */ 0x0f000001,0x00000000, +/* + JUMP eat_msgin, WHEN MSG_IN + +at 0x00000234 : */ 0x870b0000,0x000008c8, +/* + JUMP sated + +at 0x00000236 : */ 0x80080000,0x00000918, +/* +eat_status: + MOVE 1, NCR53c7xx_sink, WHEN STATUS + +at 0x00000238 : */ 0x0b000001,0x00000000, +/* + JUMP eat_status, WHEN STATUS + +at 0x0000023a : */ 0x830b0000,0x000008e0, +/* + JUMP sated + +at 0x0000023c : */ 0x80080000,0x00000918, +/* +eat_datain: + MOVE 1, NCR53c7xx_sink, WHEN DATA_IN + +at 0x0000023e : */ 0x09000001,0x00000000, +/* + JUMP eat_datain, WHEN DATA_IN + +at 0x00000240 : */ 0x810b0000,0x000008f8, +/* + JUMP sated + +at 0x00000242 : */ 0x80080000,0x00000918, +/* +spew_dataout: + MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT + +at 0x00000244 : */ 0x08000001,0x00000000, +/* +sated: + MOVE SCNTL2 & 0x7f TO SCNTL2 + +at 0x00000246 : */ 0x7c027f00,0x00000000, +/* + MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT + +at 0x00000248 : */ 0x0e000001,0x00000000, +/* + WAIT DISCONNECT + +at 0x0000024a : */ 0x48000000,0x00000000, +/* + INT int_norm_aborted + +at 0x0000024c : */ 0x98080000,0x02040000, +/* + +; +; dsa_to_scratch +; scratch_to_dsa +; +; PURPOSE : +; The NCR chips cannot do a move memory instruction with the DSA register +; as the source or destination. So, we provide a couple of subroutines +; that let us switch between the DSA register and scratch register. +; +; Memory moves to/from the DSPS register also don't work, but we +; don't use them. +; +; + + +dsa_to_scratch: + MOVE DSA0 TO SFBR + +at 0x0000024e : */ 0x72100000,0x00000000, +/* + MOVE SFBR TO SCRATCH0 + +at 0x00000250 : */ 0x6a340000,0x00000000, +/* + MOVE DSA1 TO SFBR + +at 0x00000252 : */ 0x72110000,0x00000000, +/* + MOVE SFBR TO SCRATCH1 + +at 0x00000254 : */ 0x6a350000,0x00000000, +/* + MOVE DSA2 TO SFBR + +at 0x00000256 : */ 0x72120000,0x00000000, +/* + MOVE SFBR TO SCRATCH2 + +at 0x00000258 : */ 0x6a360000,0x00000000, +/* + MOVE DSA3 TO SFBR + +at 0x0000025a : */ 0x72130000,0x00000000, +/* + MOVE SFBR TO SCRATCH3 + +at 0x0000025c : */ 0x6a370000,0x00000000, +/* + RETURN + +at 0x0000025e : */ 0x90080000,0x00000000, +/* + +scratch_to_dsa: + MOVE SCRATCH0 TO SFBR + +at 0x00000260 : */ 0x72340000,0x00000000, +/* + MOVE SFBR TO DSA0 + +at 0x00000262 : */ 0x6a100000,0x00000000, +/* + MOVE SCRATCH1 TO SFBR + +at 0x00000264 : */ 0x72350000,0x00000000, +/* + MOVE SFBR TO DSA1 + +at 0x00000266 : */ 0x6a110000,0x00000000, +/* + MOVE SCRATCH2 TO SFBR + +at 0x00000268 : */ 0x72360000,0x00000000, +/* + MOVE SFBR TO DSA2 + +at 0x0000026a : */ 0x6a120000,0x00000000, +/* + MOVE SCRATCH3 TO SFBR + +at 0x0000026c : */ 0x72370000,0x00000000, +/* + MOVE SFBR TO DSA3 + +at 0x0000026e : */ 0x6a130000,0x00000000, +/* + RETURN + +at 0x00000270 : */ 0x90080000,0x00000000, +}; + +#define A_NCR53c7xx_msg_abort 0x00000000 +static u32 A_NCR53c7xx_msg_abort_used[] __attribute((unused)) = { + 0x00000249, +}; + +#define A_NCR53c7xx_msg_reject 0x00000000 +static u32 A_NCR53c7xx_msg_reject_used[] __attribute((unused)) = { + 0x00000172, +}; + +#define A_NCR53c7xx_sink 0x00000000 +static u32 A_NCR53c7xx_sink_used[] __attribute((unused)) = { + 0x00000233, + 0x00000239, + 0x0000023f, +}; + +#define A_NCR53c7xx_zero 0x00000000 +static u32 A_NCR53c7xx_zero_used[] __attribute((unused)) = { + 0x0000022f, + 0x00000245, +}; + +#define A_NOP_insn 0x00000000 +static u32 A_NOP_insn_used[] __attribute((unused)) = { + 0x00000010, +}; + +#define A_addr_reconnect_dsa_head 0x00000000 +static u32 A_addr_reconnect_dsa_head_used[] __attribute((unused)) = { + 0x000001a7, +}; + +#define A_addr_scratch 0x00000000 +static u32 A_addr_scratch_used[] __attribute((unused)) = { + 0x00000004, + 0x0000001b, + 0x00000046, + 0x00000067, + 0x00000073, + 0x000000b0, + 0x000000c6, + 0x00000128, + 0x00000141, + 0x000001a1, + 0x000001ce, +}; + +#define A_addr_temp 0x00000000 +static u32 A_addr_temp_used[] __attribute((unused)) = { + 0x00000025, + 0x00000034, +}; + +#define A_dmode_memory_to_memory 0x00000000 +static u32 A_dmode_memory_to_memory_used[] __attribute((unused)) = { + 0x00000005, + 0x0000001c, + 0x00000027, + 0x00000035, + 0x00000047, + 0x00000069, + 0x00000075, + 0x000000b2, + 0x000000c8, + 0x0000012a, + 0x00000143, + 0x00000199, + 0x000001a2, + 0x000001d0, +}; + +#define A_dmode_memory_to_ncr 0x00000000 +static u32 A_dmode_memory_to_ncr_used[] __attribute((unused)) = { + 0x00000000, + 0x00000017, + 0x00000030, + 0x00000042, + 0x0000019d, +}; + +#define A_dmode_ncr_to_memory 0x00000000 +static u32 A_dmode_ncr_to_memory_used[] __attribute((unused)) = { + 0x00000022, + 0x00000064, + 0x00000070, + 0x000000ad, + 0x000000c3, + 0x00000125, + 0x0000013e, + 0x000001cb, +}; + +#define A_dsa_check_reselect 0x00000000 +static u32 A_dsa_check_reselect_used[] __attribute((unused)) = { + 0x000001bd, +}; + +#define A_dsa_cmdout 0x00000048 +static u32 A_dsa_cmdout_used[] __attribute((unused)) = { + 0x00000094, +}; + +#define A_dsa_cmnd 0x00000038 +static u32 A_dsa_cmnd_used[] __attribute((unused)) = { +}; + +#define A_dsa_datain 0x00000054 +static u32 A_dsa_datain_used[] __attribute((unused)) = { + 0x000000bb, +}; + +#define A_dsa_dataout 0x00000050 +static u32 A_dsa_dataout_used[] __attribute((unused)) = { + 0x000000a5, +}; + +#define A_dsa_end 0x00000070 +static u32 A_dsa_end_used[] __attribute((unused)) = { +}; + +#define A_dsa_fields_start 0x00000000 +static u32 A_dsa_fields_start_used[] __attribute((unused)) = { +}; + +#define A_dsa_msgin 0x00000058 +static u32 A_dsa_msgin_used[] __attribute((unused)) = { + 0x00000188, +}; + +#define A_dsa_msgout 0x00000040 +static u32 A_dsa_msgout_used[] __attribute((unused)) = { + 0x00000086, +}; + +#define A_dsa_msgout_other 0x00000068 +static u32 A_dsa_msgout_other_used[] __attribute((unused)) = { + 0x00000180, +}; + +#define A_dsa_next 0x00000030 +static u32 A_dsa_next_used[] __attribute((unused)) = { + 0x0000005c, +}; + +#define A_dsa_restore_pointers 0x00000000 +static u32 A_dsa_restore_pointers_used[] __attribute((unused)) = { + 0x0000012e, +}; + +#define A_dsa_save_data_pointer 0x00000000 +static u32 A_dsa_save_data_pointer_used[] __attribute((unused)) = { + 0x00000115, +}; + +#define A_dsa_select 0x0000003c +static u32 A_dsa_select_used[] __attribute((unused)) = { + 0x00000081, +}; + +#define A_dsa_status 0x00000060 +static u32 A_dsa_status_used[] __attribute((unused)) = { + 0x00000184, +}; + +#define A_dsa_temp_addr_array_value 0x00000000 +static u32 A_dsa_temp_addr_array_value_used[] __attribute((unused)) = { +}; + +#define A_dsa_temp_addr_dsa_value 0x00000000 +static u32 A_dsa_temp_addr_dsa_value_used[] __attribute((unused)) = { + 0x00000003, +}; + +#define A_dsa_temp_addr_new_value 0x00000000 +static u32 A_dsa_temp_addr_new_value_used[] __attribute((unused)) = { +}; + +#define A_dsa_temp_addr_next 0x00000000 +static u32 A_dsa_temp_addr_next_used[] __attribute((unused)) = { + 0x00000015, + 0x0000004e, +}; + +#define A_dsa_temp_addr_residual 0x00000000 +static u32 A_dsa_temp_addr_residual_used[] __attribute((unused)) = { + 0x0000002a, + 0x00000039, +}; + +#define A_dsa_temp_addr_saved_pointer 0x00000000 +static u32 A_dsa_temp_addr_saved_pointer_used[] __attribute((unused)) = { + 0x00000026, + 0x00000033, +}; + +#define A_dsa_temp_addr_saved_residual 0x00000000 +static u32 A_dsa_temp_addr_saved_residual_used[] __attribute((unused)) = { + 0x0000002b, + 0x00000038, +}; + +#define A_dsa_temp_lun 0x00000000 +static u32 A_dsa_temp_lun_used[] __attribute((unused)) = { + 0x0000004b, +}; + +#define A_dsa_temp_next 0x00000000 +static u32 A_dsa_temp_next_used[] __attribute((unused)) = { + 0x0000001a, +}; + +#define A_dsa_temp_sync 0x00000000 +static u32 A_dsa_temp_sync_used[] __attribute((unused)) = { + 0x00000053, +}; + +#define A_dsa_temp_target 0x00000000 +static u32 A_dsa_temp_target_used[] __attribute((unused)) = { + 0x00000040, +}; + +#define A_int_debug_break 0x03000000 +static u32 A_int_debug_break_used[] __attribute((unused)) = { + 0x00000217, +}; + +#define A_int_debug_panic 0x030b0000 +static u32 A_int_debug_panic_used[] __attribute((unused)) = { + 0x000001e8, + 0x000001f8, +}; + +#define A_int_err_check_condition 0x00030000 +static u32 A_int_err_check_condition_used[] __attribute((unused)) = { + 0x00000194, +}; + +#define A_int_err_no_phase 0x00040000 +static u32 A_int_err_no_phase_used[] __attribute((unused)) = { +}; + +#define A_int_err_selected 0x00010000 +static u32 A_int_err_selected_used[] __attribute((unused)) = { + 0x000001da, +}; + +#define A_int_err_unexpected_phase 0x00000000 +static u32 A_int_err_unexpected_phase_used[] __attribute((unused)) = { + 0x0000008c, + 0x00000092, + 0x0000009a, + 0x000000d0, + 0x000000d4, + 0x000000d6, + 0x000000de, + 0x000000e2, + 0x000000e4, + 0x000000ec, + 0x000000f0, + 0x000000f2, + 0x000000f4, + 0x0000014c, +}; + +#define A_int_err_unexpected_reselect 0x00020000 +static u32 A_int_err_unexpected_reselect_used[] __attribute((unused)) = { + 0x000001ba, +}; + +#define A_int_msg_1 0x01020000 +static u32 A_int_msg_1_used[] __attribute((unused)) = { + 0x0000010e, + 0x00000110, +}; + +#define A_int_msg_sdtr 0x01010000 +static u32 A_int_msg_sdtr_used[] __attribute((unused)) = { + 0x0000016c, +}; + +#define A_int_msg_wdtr 0x01000000 +static u32 A_int_msg_wdtr_used[] __attribute((unused)) = { + 0x00000160, +}; + +#define A_int_norm_aborted 0x02040000 +static u32 A_int_norm_aborted_used[] __attribute((unused)) = { + 0x0000024d, +}; + +#define A_int_norm_command_complete 0x02020000 +static u32 A_int_norm_command_complete_used[] __attribute((unused)) = { +}; + +#define A_int_norm_disconnected 0x02030000 +static u32 A_int_norm_disconnected_used[] __attribute((unused)) = { +}; + +#define A_int_norm_reselect_complete 0x02010000 +static u32 A_int_norm_reselect_complete_used[] __attribute((unused)) = { +}; + +#define A_int_norm_reset 0x02050000 +static u32 A_int_norm_reset_used[] __attribute((unused)) = { +}; + +#define A_int_norm_select_complete 0x02000000 +static u32 A_int_norm_select_complete_used[] __attribute((unused)) = { +}; + +#define A_int_test_1 0x04000000 +static u32 A_int_test_1_used[] __attribute((unused)) = { + 0x000001fd, +}; + +#define A_int_test_2 0x04010000 +static u32 A_int_test_2_used[] __attribute((unused)) = { + 0x00000215, +}; + +#define A_int_test_3 0x04020000 +static u32 A_int_test_3_used[] __attribute((unused)) = { +}; + +#define A_msg_buf 0x00000000 +static u32 A_msg_buf_used[] __attribute((unused)) = { + 0x00000102, + 0x0000014e, + 0x00000158, + 0x0000015e, + 0x00000164, + 0x0000016a, +}; + +#define A_reconnect_dsa_head 0x00000000 +static u32 A_reconnect_dsa_head_used[] __attribute((unused)) = { + 0x0000006c, + 0x00000074, + 0x000001a0, +}; + +#define A_reselected_identify 0x00000000 +static u32 A_reselected_identify_used[] __attribute((unused)) = { + 0x00000045, + 0x0000019c, +}; + +#define A_reselected_tag 0x00000000 +static u32 A_reselected_tag_used[] __attribute((unused)) = { +}; + +#define A_schedule 0x00000000 +static u32 A_schedule_used[] __attribute((unused)) = { + 0x0000007e, + 0x00000192, + 0x000001e2, + 0x0000021f, +}; + +#define A_test_dest 0x00000000 +static u32 A_test_dest_used[] __attribute((unused)) = { + 0x000001fb, +}; + +#define A_test_src 0x00000000 +static u32 A_test_src_used[] __attribute((unused)) = { + 0x000001fa, +}; + +#define Ent_accept_message 0x000005d4 +#define Ent_cmdout_cmdout 0x0000024c +#define Ent_command_complete 0x0000060c +#define Ent_command_complete_msgin 0x0000061c +#define Ent_data_transfer 0x00000254 +#define Ent_datain_to_jump 0x00000328 +#define Ent_debug_break 0x00000858 +#define Ent_dsa_code_begin 0x00000000 +#define Ent_dsa_code_check_reselect 0x000000f8 +#define Ent_dsa_code_fix_jump 0x0000003c +#define Ent_dsa_code_restore_pointers 0x000000c0 +#define Ent_dsa_code_save_data_pointer 0x00000088 +#define Ent_dsa_code_template 0x00000000 +#define Ent_dsa_code_template_end 0x00000168 +#define Ent_dsa_schedule 0x00000168 +#define Ent_dsa_zero 0x00000168 +#define Ent_end_data_transfer 0x0000028c +#define Ent_initiator_abort 0x00000880 +#define Ent_msg_in 0x00000404 +#define Ent_msg_in_restart 0x000003e4 +#define Ent_other_in 0x00000374 +#define Ent_other_out 0x0000033c +#define Ent_other_transfer 0x000003ac +#define Ent_reject_message 0x000005b4 +#define Ent_reselected_check_next 0x000006a4 +#define Ent_reselected_ok 0x00000750 +#define Ent_respond_message 0x000005ec +#define Ent_select 0x000001fc +#define Ent_select_msgout 0x00000214 +#define Ent_target_abort 0x00000860 +#define Ent_test_1 0x000007e4 +#define Ent_test_2 0x000007f8 +#define Ent_test_2_msgout 0x00000810 +#define Ent_wait_reselect 0x00000654 +static u32 LABELPATCHES[] __attribute((unused)) = { + 0x00000008, + 0x0000000a, + 0x00000013, + 0x00000016, + 0x0000001f, + 0x00000021, + 0x0000004f, + 0x00000051, + 0x0000005b, + 0x00000068, + 0x0000006f, + 0x00000082, + 0x00000084, + 0x0000008a, + 0x0000008e, + 0x00000090, + 0x00000096, + 0x00000098, + 0x0000009c, + 0x0000009e, + 0x000000a0, + 0x000000a2, + 0x000000a4, + 0x000000b1, + 0x000000b6, + 0x000000ba, + 0x000000c7, + 0x000000cc, + 0x000000d2, + 0x000000d8, + 0x000000da, + 0x000000e0, + 0x000000e6, + 0x000000e8, + 0x000000ee, + 0x000000f6, + 0x000000f8, + 0x00000104, + 0x00000106, + 0x00000108, + 0x0000010a, + 0x0000010c, + 0x00000112, + 0x00000114, + 0x00000129, + 0x00000142, + 0x00000148, + 0x00000150, + 0x00000152, + 0x00000154, + 0x0000015a, + 0x00000166, + 0x00000196, + 0x000001a5, + 0x000001a8, + 0x000001ac, + 0x000001b0, + 0x000001b4, + 0x000001b8, + 0x000001cf, + 0x000001de, + 0x000001e6, + 0x000001ec, + 0x000001ee, + 0x000001f2, + 0x000001f6, + 0x00000201, + 0x00000203, + 0x00000223, + 0x00000225, + 0x00000227, + 0x00000229, + 0x0000022b, + 0x0000022d, + 0x00000231, + 0x00000235, + 0x00000237, + 0x0000023b, + 0x0000023d, + 0x00000241, + 0x00000243, +}; + +static struct { + u32 offset; + void *address; +} EXTERNAL_PATCHES[] __attribute((unused)) = { +}; + +static u32 INSTRUCTIONS __attribute((unused)) = 301; +static u32 PATCHES __attribute((unused)) = 81; +static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/53c8xx_u.h linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/53c8xx_u.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/53c8xx_u.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/53c8xx_u.h 1998-05-11 21:49:02.000000000 +0200 @@ -0,0 +1,97 @@ +#undef A_NCR53c7xx_msg_abort +#undef A_NCR53c7xx_msg_reject +#undef A_NCR53c7xx_sink +#undef A_NCR53c7xx_zero +#undef A_NOP_insn +#undef A_addr_reconnect_dsa_head +#undef A_addr_scratch +#undef A_addr_temp +#undef A_dmode_memory_to_memory +#undef A_dmode_memory_to_ncr +#undef A_dmode_ncr_to_memory +#undef A_dsa_check_reselect +#undef A_dsa_cmdout +#undef A_dsa_cmnd +#undef A_dsa_datain +#undef A_dsa_dataout +#undef A_dsa_end +#undef A_dsa_fields_start +#undef A_dsa_msgin +#undef A_dsa_msgout +#undef A_dsa_msgout_other +#undef A_dsa_next +#undef A_dsa_restore_pointers +#undef A_dsa_save_data_pointer +#undef A_dsa_select +#undef A_dsa_status +#undef A_dsa_temp_addr_array_value +#undef A_dsa_temp_addr_dsa_value +#undef A_dsa_temp_addr_new_value +#undef A_dsa_temp_addr_next +#undef A_dsa_temp_addr_residual +#undef A_dsa_temp_addr_saved_pointer +#undef A_dsa_temp_addr_saved_residual +#undef A_dsa_temp_lun +#undef A_dsa_temp_next +#undef A_dsa_temp_sync +#undef A_dsa_temp_target +#undef A_int_debug_break +#undef A_int_debug_panic +#undef A_int_err_check_condition +#undef A_int_err_no_phase +#undef A_int_err_selected +#undef A_int_err_unexpected_phase +#undef A_int_err_unexpected_reselect +#undef A_int_msg_1 +#undef A_int_msg_sdtr +#undef A_int_msg_wdtr +#undef A_int_norm_aborted +#undef A_int_norm_command_complete +#undef A_int_norm_disconnected +#undef A_int_norm_reselect_complete +#undef A_int_norm_reset +#undef A_int_norm_select_complete +#undef A_int_test_1 +#undef A_int_test_2 +#undef A_int_test_3 +#undef A_msg_buf +#undef A_reconnect_dsa_head +#undef A_reselected_identify +#undef A_reselected_tag +#undef A_schedule +#undef A_test_dest +#undef A_test_src +#undef Ent_accept_message +#undef Ent_cmdout_cmdout +#undef Ent_command_complete +#undef Ent_command_complete_msgin +#undef Ent_data_transfer +#undef Ent_datain_to_jump +#undef Ent_debug_break +#undef Ent_dsa_code_begin +#undef Ent_dsa_code_check_reselect +#undef Ent_dsa_code_fix_jump +#undef Ent_dsa_code_restore_pointers +#undef Ent_dsa_code_save_data_pointer +#undef Ent_dsa_code_template +#undef Ent_dsa_code_template_end +#undef Ent_dsa_schedule +#undef Ent_dsa_zero +#undef Ent_end_data_transfer +#undef Ent_initiator_abort +#undef Ent_msg_in +#undef Ent_msg_in_restart +#undef Ent_other_in +#undef Ent_other_out +#undef Ent_other_transfer +#undef Ent_reject_message +#undef Ent_reselected_check_next +#undef Ent_reselected_ok +#undef Ent_respond_message +#undef Ent_select +#undef Ent_select_msgout +#undef Ent_target_abort +#undef Ent_test_1 +#undef Ent_test_2 +#undef Ent_test_2_msgout +#undef Ent_wait_reselect diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/aic7xxx/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/aic7xxx/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/aic7xxx/Makefile 2003-08-04 23:06:38.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/aic7xxx/Makefile 2003-08-17 21:28:38.000000000 +0200 @@ -13,8 +13,7 @@ ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_SCSI_AIC79XX) += aic79xx.o endif -EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi -#EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi -Werror +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi -Werror #EXTRA_CFLAGS += -g # Platform Specific Files diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/sim710_d.h linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/sim710_d.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/sim710_d.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/sim710_d.h 1999-12-09 00:17:55.000000000 +0100 @@ -0,0 +1,2361 @@ +/* DO NOT EDIT - Generated automatically by script_asm.pl */ +static u32 SCRIPT[] = { +/* + + + + + + +ABSOLUTE dsa_select = 0 +ABSOLUTE dsa_msgout = 8 +ABSOLUTE dsa_cmnd = 16 +ABSOLUTE dsa_status = 24 +ABSOLUTE dsa_msgin = 32 +ABSOLUTE dsa_datain = 40 +ABSOLUTE dsa_dataout = 1064 +ABSOLUTE dsa_size = 2088 + +ABSOLUTE reselected_identify = 0 +ABSOLUTE msgin_buf = 0 + + + +ABSOLUTE int_bad_extmsg1a = 0xab930000 +ABSOLUTE int_bad_extmsg1b = 0xab930001 +ABSOLUTE int_bad_extmsg2a = 0xab930002 +ABSOLUTE int_bad_extmsg2b = 0xab930003 +ABSOLUTE int_bad_extmsg3a = 0xab930004 +ABSOLUTE int_bad_extmsg3b = 0xab930005 +ABSOLUTE int_bad_msg1 = 0xab930006 +ABSOLUTE int_bad_msg2 = 0xab930007 +ABSOLUTE int_bad_msg3 = 0xab930008 +ABSOLUTE int_cmd_bad_phase = 0xab930009 +ABSOLUTE int_cmd_complete = 0xab93000a +ABSOLUTE int_data_bad_phase = 0xab93000b +ABSOLUTE int_msg_sdtr1 = 0xab93000c +ABSOLUTE int_msg_sdtr2 = 0xab93000d +ABSOLUTE int_msg_sdtr3 = 0xab93000e +ABSOLUTE int_no_msgout1 = 0xab93000f +ABSOLUTE int_no_msgout2 = 0xab930010 +ABSOLUTE int_no_msgout3 = 0xab930011 +ABSOLUTE int_not_cmd_complete = 0xab930012 +ABSOLUTE int_sel_no_ident = 0xab930013 +ABSOLUTE int_sel_not_cmd = 0xab930014 +ABSOLUTE int_status_not_msgin = 0xab930015 +ABSOLUTE int_resel_not_msgin = 0xab930016 +ABSOLUTE int_reselected = 0xab930017 +ABSOLUTE int_selected = 0xab930018 +ABSOLUTE int_disc1 = 0xab930019 +ABSOLUTE int_disc2 = 0xab93001a +ABSOLUTE int_disc3 = 0xab93001b +ABSOLUTE int_not_rej = 0xab93001c + + + + +ABSOLUTE had_select = 0x01 +ABSOLUTE had_msgout = 0x02 +ABSOLUTE had_cmdout = 0x04 +ABSOLUTE had_datain = 0x08 +ABSOLUTE had_dataout = 0x10 +ABSOLUTE had_status = 0x20 +ABSOLUTE had_msgin = 0x40 +ABSOLUTE had_extmsg = 0x80 + + + + + + +ENTRY do_select +do_select: + CLEAR TARGET + +at 0x00000000 : */ 0x60000200,0x00000000, +/* + MOVE SCRATCH0 & 0 TO SCRATCH0 + +at 0x00000002 : */ 0x7c340000,0x00000000, +/* + ; Enable selection timer + MOVE CTEST7 & 0xef TO CTEST7 + +at 0x00000004 : */ 0x7c1bef00,0x00000000, +/* + SELECT ATN FROM dsa_select, reselect + +at 0x00000006 : */ 0x43000000,0x00000c48, +/* + JUMP get_status, WHEN STATUS + +at 0x00000008 : */ 0x830b0000,0x000000a0, +/* + ; Disable selection timer + MOVE CTEST7 | 0x10 TO CTEST7 + +at 0x0000000a : */ 0x7a1b1000,0x00000000, +/* + MOVE SCRATCH0 | had_select TO SCRATCH0 + +at 0x0000000c : */ 0x7a340100,0x00000000, +/* + INT int_sel_no_ident, IF NOT MSG_OUT + +at 0x0000000e : */ 0x9e020000,0xab930013, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x00000010 : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x00000012 : */ 0x1e000000,0x00000008, +/* +ENTRY done_ident +done_ident: + JUMP get_status, IF STATUS + +at 0x00000014 : */ 0x830a0000,0x000000a0, +/* +redo_msgin1: + JUMP get_msgin1, WHEN MSG_IN + +at 0x00000016 : */ 0x870b0000,0x00000920, +/* + INT int_sel_not_cmd, IF NOT CMD + +at 0x00000018 : */ 0x9a020000,0xab930014, +/* +ENTRY resume_cmd +resume_cmd: + MOVE SCRATCH0 | had_cmdout TO SCRATCH0 + +at 0x0000001a : */ 0x7a340400,0x00000000, +/* + MOVE FROM dsa_cmnd, WHEN CMD + +at 0x0000001c : */ 0x1a000000,0x00000010, +/* +ENTRY resume_pmm +resume_pmm: +redo_msgin2: + JUMP get_msgin2, WHEN MSG_IN + +at 0x0000001e : */ 0x870b0000,0x00000a20, +/* + JUMP get_status, IF STATUS + +at 0x00000020 : */ 0x830a0000,0x000000a0, +/* + JUMP input_data, IF DATA_IN + +at 0x00000022 : */ 0x810a0000,0x000000e0, +/* + JUMP output_data, IF DATA_OUT + +at 0x00000024 : */ 0x800a0000,0x000004f8, +/* + INT int_cmd_bad_phase + +at 0x00000026 : */ 0x98080000,0xab930009, +/* + +get_status: + ; Disable selection timer + MOVE CTEST7 | 0x10 TO CTEST7 + +at 0x00000028 : */ 0x7a1b1000,0x00000000, +/* + MOVE FROM dsa_status, WHEN STATUS + +at 0x0000002a : */ 0x1b000000,0x00000018, +/* + INT int_status_not_msgin, WHEN NOT MSG_IN + +at 0x0000002c : */ 0x9f030000,0xab930015, +/* + MOVE FROM dsa_msgin, WHEN MSG_IN + +at 0x0000002e : */ 0x1f000000,0x00000020, +/* + INT int_not_cmd_complete, IF NOT 0x00 + +at 0x00000030 : */ 0x98040000,0xab930012, +/* + CLEAR ACK + +at 0x00000032 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc_complete +wait_disc_complete: + WAIT DISCONNECT + +at 0x00000034 : */ 0x48000000,0x00000000, +/* + INT int_cmd_complete + +at 0x00000036 : */ 0x98080000,0xab93000a, +/* + +input_data: + MOVE SCRATCH0 | had_datain TO SCRATCH0 + +at 0x00000038 : */ 0x7a340800,0x00000000, +/* +ENTRY patch_input_data +patch_input_data: + JUMP 0 + +at 0x0000003a : */ 0x80080000,0x00000000, +/* + MOVE FROM dsa_datain+0x0000, WHEN DATA_IN + +at 0x0000003c : */ 0x19000000,0x00000028, +/* + MOVE FROM dsa_datain+0x0008, WHEN DATA_IN + +at 0x0000003e : */ 0x19000000,0x00000030, +/* + MOVE FROM dsa_datain+0x0010, WHEN DATA_IN + +at 0x00000040 : */ 0x19000000,0x00000038, +/* + MOVE FROM dsa_datain+0x0018, WHEN DATA_IN + +at 0x00000042 : */ 0x19000000,0x00000040, +/* + MOVE FROM dsa_datain+0x0020, WHEN DATA_IN + +at 0x00000044 : */ 0x19000000,0x00000048, +/* + MOVE FROM dsa_datain+0x0028, WHEN DATA_IN + +at 0x00000046 : */ 0x19000000,0x00000050, +/* + MOVE FROM dsa_datain+0x0030, WHEN DATA_IN + +at 0x00000048 : */ 0x19000000,0x00000058, +/* + MOVE FROM dsa_datain+0x0038, WHEN DATA_IN + +at 0x0000004a : */ 0x19000000,0x00000060, +/* + MOVE FROM dsa_datain+0x0040, WHEN DATA_IN + +at 0x0000004c : */ 0x19000000,0x00000068, +/* + MOVE FROM dsa_datain+0x0048, WHEN DATA_IN + +at 0x0000004e : */ 0x19000000,0x00000070, +/* + MOVE FROM dsa_datain+0x0050, WHEN DATA_IN + +at 0x00000050 : */ 0x19000000,0x00000078, +/* + MOVE FROM dsa_datain+0x0058, WHEN DATA_IN + +at 0x00000052 : */ 0x19000000,0x00000080, +/* + MOVE FROM dsa_datain+0x0060, WHEN DATA_IN + +at 0x00000054 : */ 0x19000000,0x00000088, +/* + MOVE FROM dsa_datain+0x0068, WHEN DATA_IN + +at 0x00000056 : */ 0x19000000,0x00000090, +/* + MOVE FROM dsa_datain+0x0070, WHEN DATA_IN + +at 0x00000058 : */ 0x19000000,0x00000098, +/* + MOVE FROM dsa_datain+0x0078, WHEN DATA_IN + +at 0x0000005a : */ 0x19000000,0x000000a0, +/* + MOVE FROM dsa_datain+0x0080, WHEN DATA_IN + +at 0x0000005c : */ 0x19000000,0x000000a8, +/* + MOVE FROM dsa_datain+0x0088, WHEN DATA_IN + +at 0x0000005e : */ 0x19000000,0x000000b0, +/* + MOVE FROM dsa_datain+0x0090, WHEN DATA_IN + +at 0x00000060 : */ 0x19000000,0x000000b8, +/* + MOVE FROM dsa_datain+0x0098, WHEN DATA_IN + +at 0x00000062 : */ 0x19000000,0x000000c0, +/* + MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN + +at 0x00000064 : */ 0x19000000,0x000000c8, +/* + MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN + +at 0x00000066 : */ 0x19000000,0x000000d0, +/* + MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN + +at 0x00000068 : */ 0x19000000,0x000000d8, +/* + MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN + +at 0x0000006a : */ 0x19000000,0x000000e0, +/* + MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN + +at 0x0000006c : */ 0x19000000,0x000000e8, +/* + MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN + +at 0x0000006e : */ 0x19000000,0x000000f0, +/* + MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN + +at 0x00000070 : */ 0x19000000,0x000000f8, +/* + MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN + +at 0x00000072 : */ 0x19000000,0x00000100, +/* + MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN + +at 0x00000074 : */ 0x19000000,0x00000108, +/* + MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN + +at 0x00000076 : */ 0x19000000,0x00000110, +/* + MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN + +at 0x00000078 : */ 0x19000000,0x00000118, +/* + MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN + +at 0x0000007a : */ 0x19000000,0x00000120, +/* + MOVE FROM dsa_datain+0x0100, WHEN DATA_IN + +at 0x0000007c : */ 0x19000000,0x00000128, +/* + MOVE FROM dsa_datain+0x0108, WHEN DATA_IN + +at 0x0000007e : */ 0x19000000,0x00000130, +/* + MOVE FROM dsa_datain+0x0110, WHEN DATA_IN + +at 0x00000080 : */ 0x19000000,0x00000138, +/* + MOVE FROM dsa_datain+0x0118, WHEN DATA_IN + +at 0x00000082 : */ 0x19000000,0x00000140, +/* + MOVE FROM dsa_datain+0x0120, WHEN DATA_IN + +at 0x00000084 : */ 0x19000000,0x00000148, +/* + MOVE FROM dsa_datain+0x0128, WHEN DATA_IN + +at 0x00000086 : */ 0x19000000,0x00000150, +/* + MOVE FROM dsa_datain+0x0130, WHEN DATA_IN + +at 0x00000088 : */ 0x19000000,0x00000158, +/* + MOVE FROM dsa_datain+0x0138, WHEN DATA_IN + +at 0x0000008a : */ 0x19000000,0x00000160, +/* + MOVE FROM dsa_datain+0x0140, WHEN DATA_IN + +at 0x0000008c : */ 0x19000000,0x00000168, +/* + MOVE FROM dsa_datain+0x0148, WHEN DATA_IN + +at 0x0000008e : */ 0x19000000,0x00000170, +/* + MOVE FROM dsa_datain+0x0150, WHEN DATA_IN + +at 0x00000090 : */ 0x19000000,0x00000178, +/* + MOVE FROM dsa_datain+0x0158, WHEN DATA_IN + +at 0x00000092 : */ 0x19000000,0x00000180, +/* + MOVE FROM dsa_datain+0x0160, WHEN DATA_IN + +at 0x00000094 : */ 0x19000000,0x00000188, +/* + MOVE FROM dsa_datain+0x0168, WHEN DATA_IN + +at 0x00000096 : */ 0x19000000,0x00000190, +/* + MOVE FROM dsa_datain+0x0170, WHEN DATA_IN + +at 0x00000098 : */ 0x19000000,0x00000198, +/* + MOVE FROM dsa_datain+0x0178, WHEN DATA_IN + +at 0x0000009a : */ 0x19000000,0x000001a0, +/* + MOVE FROM dsa_datain+0x0180, WHEN DATA_IN + +at 0x0000009c : */ 0x19000000,0x000001a8, +/* + MOVE FROM dsa_datain+0x0188, WHEN DATA_IN + +at 0x0000009e : */ 0x19000000,0x000001b0, +/* + MOVE FROM dsa_datain+0x0190, WHEN DATA_IN + +at 0x000000a0 : */ 0x19000000,0x000001b8, +/* + MOVE FROM dsa_datain+0x0198, WHEN DATA_IN + +at 0x000000a2 : */ 0x19000000,0x000001c0, +/* + MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN + +at 0x000000a4 : */ 0x19000000,0x000001c8, +/* + MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN + +at 0x000000a6 : */ 0x19000000,0x000001d0, +/* + MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN + +at 0x000000a8 : */ 0x19000000,0x000001d8, +/* + MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN + +at 0x000000aa : */ 0x19000000,0x000001e0, +/* + MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN + +at 0x000000ac : */ 0x19000000,0x000001e8, +/* + MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN + +at 0x000000ae : */ 0x19000000,0x000001f0, +/* + MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN + +at 0x000000b0 : */ 0x19000000,0x000001f8, +/* + MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN + +at 0x000000b2 : */ 0x19000000,0x00000200, +/* + MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN + +at 0x000000b4 : */ 0x19000000,0x00000208, +/* + MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN + +at 0x000000b6 : */ 0x19000000,0x00000210, +/* + MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN + +at 0x000000b8 : */ 0x19000000,0x00000218, +/* + MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN + +at 0x000000ba : */ 0x19000000,0x00000220, +/* + MOVE FROM dsa_datain+0x0200, WHEN DATA_IN + +at 0x000000bc : */ 0x19000000,0x00000228, +/* + MOVE FROM dsa_datain+0x0208, WHEN DATA_IN + +at 0x000000be : */ 0x19000000,0x00000230, +/* + MOVE FROM dsa_datain+0x0210, WHEN DATA_IN + +at 0x000000c0 : */ 0x19000000,0x00000238, +/* + MOVE FROM dsa_datain+0x0218, WHEN DATA_IN + +at 0x000000c2 : */ 0x19000000,0x00000240, +/* + MOVE FROM dsa_datain+0x0220, WHEN DATA_IN + +at 0x000000c4 : */ 0x19000000,0x00000248, +/* + MOVE FROM dsa_datain+0x0228, WHEN DATA_IN + +at 0x000000c6 : */ 0x19000000,0x00000250, +/* + MOVE FROM dsa_datain+0x0230, WHEN DATA_IN + +at 0x000000c8 : */ 0x19000000,0x00000258, +/* + MOVE FROM dsa_datain+0x0238, WHEN DATA_IN + +at 0x000000ca : */ 0x19000000,0x00000260, +/* + MOVE FROM dsa_datain+0x0240, WHEN DATA_IN + +at 0x000000cc : */ 0x19000000,0x00000268, +/* + MOVE FROM dsa_datain+0x0248, WHEN DATA_IN + +at 0x000000ce : */ 0x19000000,0x00000270, +/* + MOVE FROM dsa_datain+0x0250, WHEN DATA_IN + +at 0x000000d0 : */ 0x19000000,0x00000278, +/* + MOVE FROM dsa_datain+0x0258, WHEN DATA_IN + +at 0x000000d2 : */ 0x19000000,0x00000280, +/* + MOVE FROM dsa_datain+0x0260, WHEN DATA_IN + +at 0x000000d4 : */ 0x19000000,0x00000288, +/* + MOVE FROM dsa_datain+0x0268, WHEN DATA_IN + +at 0x000000d6 : */ 0x19000000,0x00000290, +/* + MOVE FROM dsa_datain+0x0270, WHEN DATA_IN + +at 0x000000d8 : */ 0x19000000,0x00000298, +/* + MOVE FROM dsa_datain+0x0278, WHEN DATA_IN + +at 0x000000da : */ 0x19000000,0x000002a0, +/* + MOVE FROM dsa_datain+0x0280, WHEN DATA_IN + +at 0x000000dc : */ 0x19000000,0x000002a8, +/* + MOVE FROM dsa_datain+0x0288, WHEN DATA_IN + +at 0x000000de : */ 0x19000000,0x000002b0, +/* + MOVE FROM dsa_datain+0x0290, WHEN DATA_IN + +at 0x000000e0 : */ 0x19000000,0x000002b8, +/* + MOVE FROM dsa_datain+0x0298, WHEN DATA_IN + +at 0x000000e2 : */ 0x19000000,0x000002c0, +/* + MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN + +at 0x000000e4 : */ 0x19000000,0x000002c8, +/* + MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN + +at 0x000000e6 : */ 0x19000000,0x000002d0, +/* + MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN + +at 0x000000e8 : */ 0x19000000,0x000002d8, +/* + MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN + +at 0x000000ea : */ 0x19000000,0x000002e0, +/* + MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN + +at 0x000000ec : */ 0x19000000,0x000002e8, +/* + MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN + +at 0x000000ee : */ 0x19000000,0x000002f0, +/* + MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN + +at 0x000000f0 : */ 0x19000000,0x000002f8, +/* + MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN + +at 0x000000f2 : */ 0x19000000,0x00000300, +/* + MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN + +at 0x000000f4 : */ 0x19000000,0x00000308, +/* + MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN + +at 0x000000f6 : */ 0x19000000,0x00000310, +/* + MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN + +at 0x000000f8 : */ 0x19000000,0x00000318, +/* + MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN + +at 0x000000fa : */ 0x19000000,0x00000320, +/* + MOVE FROM dsa_datain+0x0300, WHEN DATA_IN + +at 0x000000fc : */ 0x19000000,0x00000328, +/* + MOVE FROM dsa_datain+0x0308, WHEN DATA_IN + +at 0x000000fe : */ 0x19000000,0x00000330, +/* + MOVE FROM dsa_datain+0x0310, WHEN DATA_IN + +at 0x00000100 : */ 0x19000000,0x00000338, +/* + MOVE FROM dsa_datain+0x0318, WHEN DATA_IN + +at 0x00000102 : */ 0x19000000,0x00000340, +/* + MOVE FROM dsa_datain+0x0320, WHEN DATA_IN + +at 0x00000104 : */ 0x19000000,0x00000348, +/* + MOVE FROM dsa_datain+0x0328, WHEN DATA_IN + +at 0x00000106 : */ 0x19000000,0x00000350, +/* + MOVE FROM dsa_datain+0x0330, WHEN DATA_IN + +at 0x00000108 : */ 0x19000000,0x00000358, +/* + MOVE FROM dsa_datain+0x0338, WHEN DATA_IN + +at 0x0000010a : */ 0x19000000,0x00000360, +/* + MOVE FROM dsa_datain+0x0340, WHEN DATA_IN + +at 0x0000010c : */ 0x19000000,0x00000368, +/* + MOVE FROM dsa_datain+0x0348, WHEN DATA_IN + +at 0x0000010e : */ 0x19000000,0x00000370, +/* + MOVE FROM dsa_datain+0x0350, WHEN DATA_IN + +at 0x00000110 : */ 0x19000000,0x00000378, +/* + MOVE FROM dsa_datain+0x0358, WHEN DATA_IN + +at 0x00000112 : */ 0x19000000,0x00000380, +/* + MOVE FROM dsa_datain+0x0360, WHEN DATA_IN + +at 0x00000114 : */ 0x19000000,0x00000388, +/* + MOVE FROM dsa_datain+0x0368, WHEN DATA_IN + +at 0x00000116 : */ 0x19000000,0x00000390, +/* + MOVE FROM dsa_datain+0x0370, WHEN DATA_IN + +at 0x00000118 : */ 0x19000000,0x00000398, +/* + MOVE FROM dsa_datain+0x0378, WHEN DATA_IN + +at 0x0000011a : */ 0x19000000,0x000003a0, +/* + MOVE FROM dsa_datain+0x0380, WHEN DATA_IN + +at 0x0000011c : */ 0x19000000,0x000003a8, +/* + MOVE FROM dsa_datain+0x0388, WHEN DATA_IN + +at 0x0000011e : */ 0x19000000,0x000003b0, +/* + MOVE FROM dsa_datain+0x0390, WHEN DATA_IN + +at 0x00000120 : */ 0x19000000,0x000003b8, +/* + MOVE FROM dsa_datain+0x0398, WHEN DATA_IN + +at 0x00000122 : */ 0x19000000,0x000003c0, +/* + MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN + +at 0x00000124 : */ 0x19000000,0x000003c8, +/* + MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN + +at 0x00000126 : */ 0x19000000,0x000003d0, +/* + MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN + +at 0x00000128 : */ 0x19000000,0x000003d8, +/* + MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN + +at 0x0000012a : */ 0x19000000,0x000003e0, +/* + MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN + +at 0x0000012c : */ 0x19000000,0x000003e8, +/* + MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN + +at 0x0000012e : */ 0x19000000,0x000003f0, +/* + MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN + +at 0x00000130 : */ 0x19000000,0x000003f8, +/* + MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN + +at 0x00000132 : */ 0x19000000,0x00000400, +/* + MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN + +at 0x00000134 : */ 0x19000000,0x00000408, +/* + MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN + +at 0x00000136 : */ 0x19000000,0x00000410, +/* + MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN + +at 0x00000138 : */ 0x19000000,0x00000418, +/* + MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN + +at 0x0000013a : */ 0x19000000,0x00000420, +/* + JUMP end_data_trans + +at 0x0000013c : */ 0x80080000,0x00000908, +/* + +output_data: + MOVE SCRATCH0 | had_dataout TO SCRATCH0 + +at 0x0000013e : */ 0x7a341000,0x00000000, +/* +ENTRY patch_output_data +patch_output_data: + JUMP 0 + +at 0x00000140 : */ 0x80080000,0x00000000, +/* + MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT + +at 0x00000142 : */ 0x18000000,0x00000428, +/* + MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT + +at 0x00000144 : */ 0x18000000,0x00000430, +/* + MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT + +at 0x00000146 : */ 0x18000000,0x00000438, +/* + MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT + +at 0x00000148 : */ 0x18000000,0x00000440, +/* + MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT + +at 0x0000014a : */ 0x18000000,0x00000448, +/* + MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT + +at 0x0000014c : */ 0x18000000,0x00000450, +/* + MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT + +at 0x0000014e : */ 0x18000000,0x00000458, +/* + MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT + +at 0x00000150 : */ 0x18000000,0x00000460, +/* + MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT + +at 0x00000152 : */ 0x18000000,0x00000468, +/* + MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT + +at 0x00000154 : */ 0x18000000,0x00000470, +/* + MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT + +at 0x00000156 : */ 0x18000000,0x00000478, +/* + MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT + +at 0x00000158 : */ 0x18000000,0x00000480, +/* + MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT + +at 0x0000015a : */ 0x18000000,0x00000488, +/* + MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT + +at 0x0000015c : */ 0x18000000,0x00000490, +/* + MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT + +at 0x0000015e : */ 0x18000000,0x00000498, +/* + MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT + +at 0x00000160 : */ 0x18000000,0x000004a0, +/* + MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT + +at 0x00000162 : */ 0x18000000,0x000004a8, +/* + MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT + +at 0x00000164 : */ 0x18000000,0x000004b0, +/* + MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT + +at 0x00000166 : */ 0x18000000,0x000004b8, +/* + MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT + +at 0x00000168 : */ 0x18000000,0x000004c0, +/* + MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT + +at 0x0000016a : */ 0x18000000,0x000004c8, +/* + MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT + +at 0x0000016c : */ 0x18000000,0x000004d0, +/* + MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT + +at 0x0000016e : */ 0x18000000,0x000004d8, +/* + MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT + +at 0x00000170 : */ 0x18000000,0x000004e0, +/* + MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT + +at 0x00000172 : */ 0x18000000,0x000004e8, +/* + MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT + +at 0x00000174 : */ 0x18000000,0x000004f0, +/* + MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT + +at 0x00000176 : */ 0x18000000,0x000004f8, +/* + MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT + +at 0x00000178 : */ 0x18000000,0x00000500, +/* + MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT + +at 0x0000017a : */ 0x18000000,0x00000508, +/* + MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT + +at 0x0000017c : */ 0x18000000,0x00000510, +/* + MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT + +at 0x0000017e : */ 0x18000000,0x00000518, +/* + MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT + +at 0x00000180 : */ 0x18000000,0x00000520, +/* + MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT + +at 0x00000182 : */ 0x18000000,0x00000528, +/* + MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT + +at 0x00000184 : */ 0x18000000,0x00000530, +/* + MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT + +at 0x00000186 : */ 0x18000000,0x00000538, +/* + MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT + +at 0x00000188 : */ 0x18000000,0x00000540, +/* + MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT + +at 0x0000018a : */ 0x18000000,0x00000548, +/* + MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT + +at 0x0000018c : */ 0x18000000,0x00000550, +/* + MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT + +at 0x0000018e : */ 0x18000000,0x00000558, +/* + MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT + +at 0x00000190 : */ 0x18000000,0x00000560, +/* + MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT + +at 0x00000192 : */ 0x18000000,0x00000568, +/* + MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT + +at 0x00000194 : */ 0x18000000,0x00000570, +/* + MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT + +at 0x00000196 : */ 0x18000000,0x00000578, +/* + MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT + +at 0x00000198 : */ 0x18000000,0x00000580, +/* + MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT + +at 0x0000019a : */ 0x18000000,0x00000588, +/* + MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT + +at 0x0000019c : */ 0x18000000,0x00000590, +/* + MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT + +at 0x0000019e : */ 0x18000000,0x00000598, +/* + MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT + +at 0x000001a0 : */ 0x18000000,0x000005a0, +/* + MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT + +at 0x000001a2 : */ 0x18000000,0x000005a8, +/* + MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT + +at 0x000001a4 : */ 0x18000000,0x000005b0, +/* + MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT + +at 0x000001a6 : */ 0x18000000,0x000005b8, +/* + MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT + +at 0x000001a8 : */ 0x18000000,0x000005c0, +/* + MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT + +at 0x000001aa : */ 0x18000000,0x000005c8, +/* + MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT + +at 0x000001ac : */ 0x18000000,0x000005d0, +/* + MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT + +at 0x000001ae : */ 0x18000000,0x000005d8, +/* + MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT + +at 0x000001b0 : */ 0x18000000,0x000005e0, +/* + MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT + +at 0x000001b2 : */ 0x18000000,0x000005e8, +/* + MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT + +at 0x000001b4 : */ 0x18000000,0x000005f0, +/* + MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT + +at 0x000001b6 : */ 0x18000000,0x000005f8, +/* + MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT + +at 0x000001b8 : */ 0x18000000,0x00000600, +/* + MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT + +at 0x000001ba : */ 0x18000000,0x00000608, +/* + MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT + +at 0x000001bc : */ 0x18000000,0x00000610, +/* + MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT + +at 0x000001be : */ 0x18000000,0x00000618, +/* + MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT + +at 0x000001c0 : */ 0x18000000,0x00000620, +/* + MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT + +at 0x000001c2 : */ 0x18000000,0x00000628, +/* + MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT + +at 0x000001c4 : */ 0x18000000,0x00000630, +/* + MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT + +at 0x000001c6 : */ 0x18000000,0x00000638, +/* + MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT + +at 0x000001c8 : */ 0x18000000,0x00000640, +/* + MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT + +at 0x000001ca : */ 0x18000000,0x00000648, +/* + MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT + +at 0x000001cc : */ 0x18000000,0x00000650, +/* + MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT + +at 0x000001ce : */ 0x18000000,0x00000658, +/* + MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT + +at 0x000001d0 : */ 0x18000000,0x00000660, +/* + MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT + +at 0x000001d2 : */ 0x18000000,0x00000668, +/* + MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT + +at 0x000001d4 : */ 0x18000000,0x00000670, +/* + MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT + +at 0x000001d6 : */ 0x18000000,0x00000678, +/* + MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT + +at 0x000001d8 : */ 0x18000000,0x00000680, +/* + MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT + +at 0x000001da : */ 0x18000000,0x00000688, +/* + MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT + +at 0x000001dc : */ 0x18000000,0x00000690, +/* + MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT + +at 0x000001de : */ 0x18000000,0x00000698, +/* + MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT + +at 0x000001e0 : */ 0x18000000,0x000006a0, +/* + MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT + +at 0x000001e2 : */ 0x18000000,0x000006a8, +/* + MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT + +at 0x000001e4 : */ 0x18000000,0x000006b0, +/* + MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT + +at 0x000001e6 : */ 0x18000000,0x000006b8, +/* + MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT + +at 0x000001e8 : */ 0x18000000,0x000006c0, +/* + MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT + +at 0x000001ea : */ 0x18000000,0x000006c8, +/* + MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT + +at 0x000001ec : */ 0x18000000,0x000006d0, +/* + MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT + +at 0x000001ee : */ 0x18000000,0x000006d8, +/* + MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT + +at 0x000001f0 : */ 0x18000000,0x000006e0, +/* + MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT + +at 0x000001f2 : */ 0x18000000,0x000006e8, +/* + MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT + +at 0x000001f4 : */ 0x18000000,0x000006f0, +/* + MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT + +at 0x000001f6 : */ 0x18000000,0x000006f8, +/* + MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT + +at 0x000001f8 : */ 0x18000000,0x00000700, +/* + MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT + +at 0x000001fa : */ 0x18000000,0x00000708, +/* + MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT + +at 0x000001fc : */ 0x18000000,0x00000710, +/* + MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT + +at 0x000001fe : */ 0x18000000,0x00000718, +/* + MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT + +at 0x00000200 : */ 0x18000000,0x00000720, +/* + MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT + +at 0x00000202 : */ 0x18000000,0x00000728, +/* + MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT + +at 0x00000204 : */ 0x18000000,0x00000730, +/* + MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT + +at 0x00000206 : */ 0x18000000,0x00000738, +/* + MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT + +at 0x00000208 : */ 0x18000000,0x00000740, +/* + MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT + +at 0x0000020a : */ 0x18000000,0x00000748, +/* + MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT + +at 0x0000020c : */ 0x18000000,0x00000750, +/* + MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT + +at 0x0000020e : */ 0x18000000,0x00000758, +/* + MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT + +at 0x00000210 : */ 0x18000000,0x00000760, +/* + MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT + +at 0x00000212 : */ 0x18000000,0x00000768, +/* + MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT + +at 0x00000214 : */ 0x18000000,0x00000770, +/* + MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT + +at 0x00000216 : */ 0x18000000,0x00000778, +/* + MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT + +at 0x00000218 : */ 0x18000000,0x00000780, +/* + MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT + +at 0x0000021a : */ 0x18000000,0x00000788, +/* + MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT + +at 0x0000021c : */ 0x18000000,0x00000790, +/* + MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT + +at 0x0000021e : */ 0x18000000,0x00000798, +/* + MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT + +at 0x00000220 : */ 0x18000000,0x000007a0, +/* + MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT + +at 0x00000222 : */ 0x18000000,0x000007a8, +/* + MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT + +at 0x00000224 : */ 0x18000000,0x000007b0, +/* + MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT + +at 0x00000226 : */ 0x18000000,0x000007b8, +/* + MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT + +at 0x00000228 : */ 0x18000000,0x000007c0, +/* + MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT + +at 0x0000022a : */ 0x18000000,0x000007c8, +/* + MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT + +at 0x0000022c : */ 0x18000000,0x000007d0, +/* + MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT + +at 0x0000022e : */ 0x18000000,0x000007d8, +/* + MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT + +at 0x00000230 : */ 0x18000000,0x000007e0, +/* + MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT + +at 0x00000232 : */ 0x18000000,0x000007e8, +/* + MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT + +at 0x00000234 : */ 0x18000000,0x000007f0, +/* + MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT + +at 0x00000236 : */ 0x18000000,0x000007f8, +/* + MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT + +at 0x00000238 : */ 0x18000000,0x00000800, +/* + MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT + +at 0x0000023a : */ 0x18000000,0x00000808, +/* + MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT + +at 0x0000023c : */ 0x18000000,0x00000810, +/* + MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT + +at 0x0000023e : */ 0x18000000,0x00000818, +/* + MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT + +at 0x00000240 : */ 0x18000000,0x00000820, +/* +ENTRY end_data_trans +end_data_trans: +redo_msgin3: + JUMP get_status, WHEN STATUS + +at 0x00000242 : */ 0x830b0000,0x000000a0, +/* + JUMP get_msgin3, WHEN MSG_IN + +at 0x00000244 : */ 0x870b0000,0x00000b20, +/* + INT int_data_bad_phase + +at 0x00000246 : */ 0x98080000,0xab93000b, +/* + +get_msgin1: + MOVE SCRATCH0 | had_msgin TO SCRATCH0 + +at 0x00000248 : */ 0x7a344000,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x0000024a : */ 0x0f000001,0x00000000, +/* + JUMP ext_msg1, IF 0x01 ; Extended Message + +at 0x0000024c : */ 0x800c0001,0x00000968, +/* + JUMP ignore_msg1, IF 0x02 ; Save Data Pointers + +at 0x0000024e : */ 0x800c0002,0x00000958, +/* + JUMP ignore_msg1, IF 0x03 ; Save Restore Pointers + +at 0x00000250 : */ 0x800c0003,0x00000958, +/* + JUMP disc1, IF 0x04 ; Disconnect + +at 0x00000252 : */ 0x800c0004,0x000009c8, +/* + INT int_bad_msg1 + +at 0x00000254 : */ 0x98080000,0xab930006, +/* +ignore_msg1: + CLEAR ACK + +at 0x00000256 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin1 + +at 0x00000258 : */ 0x80080000,0x00000058, +/* +ext_msg1: + MOVE SCRATCH0 | had_extmsg TO SCRATCH0 + +at 0x0000025a : */ 0x7a348000,0x00000000, +/* + CLEAR ACK + +at 0x0000025c : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 1, WHEN MSG_IN + +at 0x0000025e : */ 0x0f000001,0x00000001, +/* + JUMP ext_msg1a, IF 0x03 + +at 0x00000260 : */ 0x800c0003,0x00000990, +/* + INT int_bad_extmsg1a + +at 0x00000262 : */ 0x98080000,0xab930000, +/* +ext_msg1a: + CLEAR ACK + +at 0x00000264 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x00000266 : */ 0x0f000001,0x00000002, +/* + JUMP ext_msg1b, IF 0x01 ; Must be SDTR + +at 0x00000268 : */ 0x800c0001,0x000009b0, +/* + INT int_bad_extmsg1b + +at 0x0000026a : */ 0x98080000,0xab930001, +/* +ext_msg1b: + CLEAR ACK + +at 0x0000026c : */ 0x60000040,0x00000000, +/* + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x0000026e : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr1 + +at 0x00000270 : */ 0x98080000,0xab93000c, +/* +disc1: + CLEAR ACK + +at 0x00000272 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc1 +wait_disc1: + WAIT DISCONNECT + +at 0x00000274 : */ 0x48000000,0x00000000, +/* + INT int_disc1 + +at 0x00000276 : */ 0x98080000,0xab930019, +/* +ENTRY resume_msgin1a +resume_msgin1a: + CLEAR ACK + +at 0x00000278 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin1 + +at 0x0000027a : */ 0x80080000,0x00000058, +/* +ENTRY resume_msgin1b +resume_msgin1b: + SET ATN + +at 0x0000027c : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x0000027e : */ 0x60000040,0x00000000, +/* + INT int_no_msgout1, WHEN NOT MSG_OUT + +at 0x00000280 : */ 0x9e030000,0xab93000f, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x00000282 : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x00000284 : */ 0x1e000000,0x00000008, +/* + JUMP redo_msgin1 + +at 0x00000286 : */ 0x80080000,0x00000058, +/* + +get_msgin2: + MOVE SCRATCH0 | had_msgin TO SCRATCH0 + +at 0x00000288 : */ 0x7a344000,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x0000028a : */ 0x0f000001,0x00000000, +/* + JUMP ext_msg2, IF 0x01 ; Extended Message + +at 0x0000028c : */ 0x800c0001,0x00000a68, +/* + JUMP ignore_msg2, IF 0x02 ; Save Data Pointers + +at 0x0000028e : */ 0x800c0002,0x00000a58, +/* + JUMP ignore_msg2, IF 0x03 ; Save Restore Pointers + +at 0x00000290 : */ 0x800c0003,0x00000a58, +/* + JUMP disc2, IF 0x04 ; Disconnect + +at 0x00000292 : */ 0x800c0004,0x00000ac8, +/* + INT int_bad_msg2 + +at 0x00000294 : */ 0x98080000,0xab930007, +/* +ignore_msg2: + CLEAR ACK + +at 0x00000296 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin2 + +at 0x00000298 : */ 0x80080000,0x00000078, +/* +ext_msg2: + MOVE SCRATCH0 | had_extmsg TO SCRATCH0 + +at 0x0000029a : */ 0x7a348000,0x00000000, +/* + CLEAR ACK + +at 0x0000029c : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 1, WHEN MSG_IN + +at 0x0000029e : */ 0x0f000001,0x00000001, +/* + JUMP ext_msg2a, IF 0x03 + +at 0x000002a0 : */ 0x800c0003,0x00000a90, +/* + INT int_bad_extmsg2a + +at 0x000002a2 : */ 0x98080000,0xab930002, +/* +ext_msg2a: + CLEAR ACK + +at 0x000002a4 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x000002a6 : */ 0x0f000001,0x00000002, +/* + JUMP ext_msg2b, IF 0x01 ; Must be SDTR + +at 0x000002a8 : */ 0x800c0001,0x00000ab0, +/* + INT int_bad_extmsg2b + +at 0x000002aa : */ 0x98080000,0xab930003, +/* +ext_msg2b: + CLEAR ACK + +at 0x000002ac : */ 0x60000040,0x00000000, +/* + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x000002ae : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr2 + +at 0x000002b0 : */ 0x98080000,0xab93000d, +/* +disc2: + CLEAR ACK + +at 0x000002b2 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc2 +wait_disc2: + WAIT DISCONNECT + +at 0x000002b4 : */ 0x48000000,0x00000000, +/* + INT int_disc2 + +at 0x000002b6 : */ 0x98080000,0xab93001a, +/* +ENTRY resume_msgin2a +resume_msgin2a: + CLEAR ACK + +at 0x000002b8 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin2 + +at 0x000002ba : */ 0x80080000,0x00000078, +/* +ENTRY resume_msgin2b +resume_msgin2b: + SET ATN + +at 0x000002bc : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x000002be : */ 0x60000040,0x00000000, +/* + INT int_no_msgout2, WHEN NOT MSG_OUT + +at 0x000002c0 : */ 0x9e030000,0xab930010, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x000002c2 : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x000002c4 : */ 0x1e000000,0x00000008, +/* + JUMP redo_msgin2 + +at 0x000002c6 : */ 0x80080000,0x00000078, +/* + +get_msgin3: + MOVE SCRATCH0 | had_msgin TO SCRATCH0 + +at 0x000002c8 : */ 0x7a344000,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x000002ca : */ 0x0f000001,0x00000000, +/* + JUMP ext_msg3, IF 0x01 ; Extended Message + +at 0x000002cc : */ 0x800c0001,0x00000b68, +/* + JUMP ignore_msg3, IF 0x02 ; Save Data Pointers + +at 0x000002ce : */ 0x800c0002,0x00000b58, +/* + JUMP ignore_msg3, IF 0x03 ; Save Restore Pointers + +at 0x000002d0 : */ 0x800c0003,0x00000b58, +/* + JUMP disc3, IF 0x04 ; Disconnect + +at 0x000002d2 : */ 0x800c0004,0x00000bc8, +/* + INT int_bad_msg3 + +at 0x000002d4 : */ 0x98080000,0xab930008, +/* +ignore_msg3: + CLEAR ACK + +at 0x000002d6 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin3 + +at 0x000002d8 : */ 0x80080000,0x00000908, +/* +ext_msg3: + MOVE SCRATCH0 | had_extmsg TO SCRATCH0 + +at 0x000002da : */ 0x7a348000,0x00000000, +/* + CLEAR ACK + +at 0x000002dc : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 1, WHEN MSG_IN + +at 0x000002de : */ 0x0f000001,0x00000001, +/* + JUMP ext_msg3a, IF 0x03 + +at 0x000002e0 : */ 0x800c0003,0x00000b90, +/* + INT int_bad_extmsg3a + +at 0x000002e2 : */ 0x98080000,0xab930004, +/* +ext_msg3a: + CLEAR ACK + +at 0x000002e4 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x000002e6 : */ 0x0f000001,0x00000002, +/* + JUMP ext_msg3b, IF 0x01 ; Must be SDTR + +at 0x000002e8 : */ 0x800c0001,0x00000bb0, +/* + INT int_bad_extmsg3b + +at 0x000002ea : */ 0x98080000,0xab930005, +/* +ext_msg3b: + CLEAR ACK + +at 0x000002ec : */ 0x60000040,0x00000000, +/* + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x000002ee : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr3 + +at 0x000002f0 : */ 0x98080000,0xab93000e, +/* +disc3: + CLEAR ACK + +at 0x000002f2 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc3 +wait_disc3: + WAIT DISCONNECT + +at 0x000002f4 : */ 0x48000000,0x00000000, +/* + INT int_disc3 + +at 0x000002f6 : */ 0x98080000,0xab93001b, +/* +ENTRY resume_msgin3a +resume_msgin3a: + CLEAR ACK + +at 0x000002f8 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin3 + +at 0x000002fa : */ 0x80080000,0x00000908, +/* +ENTRY resume_msgin3b +resume_msgin3b: + SET ATN + +at 0x000002fc : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x000002fe : */ 0x60000040,0x00000000, +/* + INT int_no_msgout3, WHEN NOT MSG_OUT + +at 0x00000300 : */ 0x9e030000,0xab930011, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x00000302 : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x00000304 : */ 0x1e000000,0x00000008, +/* + JUMP redo_msgin3 + +at 0x00000306 : */ 0x80080000,0x00000908, +/* + +ENTRY resume_rej_ident +resume_rej_ident: + CLEAR ATN + +at 0x00000308 : */ 0x60000008,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x0000030a : */ 0x0f000001,0x00000000, +/* + INT int_not_rej, IF NOT 0x07 ; Reject + +at 0x0000030c : */ 0x98040007,0xab93001c, +/* + CLEAR ACK + +at 0x0000030e : */ 0x60000040,0x00000000, +/* + JUMP done_ident + +at 0x00000310 : */ 0x80080000,0x00000050, +/* + +ENTRY reselect +reselect: + ; Disable selection timer + MOVE CTEST7 | 0x10 TO CTEST7 + +at 0x00000312 : */ 0x7a1b1000,0x00000000, +/* + WAIT RESELECT resel_err + +at 0x00000314 : */ 0x50000000,0x00000c70, +/* + INT int_resel_not_msgin, WHEN NOT MSG_IN + +at 0x00000316 : */ 0x9f030000,0xab930016, +/* + MOVE 1, reselected_identify, WHEN MSG_IN + +at 0x00000318 : */ 0x0f000001,0x00000000, +/* + INT int_reselected + +at 0x0000031a : */ 0x98080000,0xab930017, +/* +resel_err: + MOVE CTEST2 & 0x40 TO SFBR + +at 0x0000031c : */ 0x74164000,0x00000000, +/* + JUMP selected, IF 0x00 + +at 0x0000031e : */ 0x800c0000,0x00000cb0, +/* + MOVE SFBR & 0 TO SFBR + +at 0x00000320 : */ 0x7c080000,0x00000000, +/* +ENTRY patch_new_dsa +patch_new_dsa: + MOVE SFBR | 0x11 TO DSA0 + +at 0x00000322 : */ 0x6a101100,0x00000000, +/* + MOVE SFBR | 0x22 TO DSA1 + +at 0x00000324 : */ 0x6a112200,0x00000000, +/* + MOVE SFBR | 0x33 TO DSA2 + +at 0x00000326 : */ 0x6a123300,0x00000000, +/* + MOVE SFBR | 0x44 TO DSA3 + +at 0x00000328 : */ 0x6a134400,0x00000000, +/* + JUMP do_select + +at 0x0000032a : */ 0x80080000,0x00000000, +/* + +selected: + INT int_selected + +at 0x0000032c : */ 0x98080000,0xab930018, +}; + +#define A_dsa_cmnd 0x00000010 +static u32 A_dsa_cmnd_used[] __attribute((unused)) = { + 0x0000001d, +}; + +#define A_dsa_datain 0x00000028 +static u32 A_dsa_datain_used[] __attribute((unused)) = { + 0x0000003d, + 0x0000003f, + 0x00000041, + 0x00000043, + 0x00000045, + 0x00000047, + 0x00000049, + 0x0000004b, + 0x0000004d, + 0x0000004f, + 0x00000051, + 0x00000053, + 0x00000055, + 0x00000057, + 0x00000059, + 0x0000005b, + 0x0000005d, + 0x0000005f, + 0x00000061, + 0x00000063, + 0x00000065, + 0x00000067, + 0x00000069, + 0x0000006b, + 0x0000006d, + 0x0000006f, + 0x00000071, + 0x00000073, + 0x00000075, + 0x00000077, + 0x00000079, + 0x0000007b, + 0x0000007d, + 0x0000007f, + 0x00000081, + 0x00000083, + 0x00000085, + 0x00000087, + 0x00000089, + 0x0000008b, + 0x0000008d, + 0x0000008f, + 0x00000091, + 0x00000093, + 0x00000095, + 0x00000097, + 0x00000099, + 0x0000009b, + 0x0000009d, + 0x0000009f, + 0x000000a1, + 0x000000a3, + 0x000000a5, + 0x000000a7, + 0x000000a9, + 0x000000ab, + 0x000000ad, + 0x000000af, + 0x000000b1, + 0x000000b3, + 0x000000b5, + 0x000000b7, + 0x000000b9, + 0x000000bb, + 0x000000bd, + 0x000000bf, + 0x000000c1, + 0x000000c3, + 0x000000c5, + 0x000000c7, + 0x000000c9, + 0x000000cb, + 0x000000cd, + 0x000000cf, + 0x000000d1, + 0x000000d3, + 0x000000d5, + 0x000000d7, + 0x000000d9, + 0x000000db, + 0x000000dd, + 0x000000df, + 0x000000e1, + 0x000000e3, + 0x000000e5, + 0x000000e7, + 0x000000e9, + 0x000000eb, + 0x000000ed, + 0x000000ef, + 0x000000f1, + 0x000000f3, + 0x000000f5, + 0x000000f7, + 0x000000f9, + 0x000000fb, + 0x000000fd, + 0x000000ff, + 0x00000101, + 0x00000103, + 0x00000105, + 0x00000107, + 0x00000109, + 0x0000010b, + 0x0000010d, + 0x0000010f, + 0x00000111, + 0x00000113, + 0x00000115, + 0x00000117, + 0x00000119, + 0x0000011b, + 0x0000011d, + 0x0000011f, + 0x00000121, + 0x00000123, + 0x00000125, + 0x00000127, + 0x00000129, + 0x0000012b, + 0x0000012d, + 0x0000012f, + 0x00000131, + 0x00000133, + 0x00000135, + 0x00000137, + 0x00000139, + 0x0000013b, +}; + +#define A_dsa_dataout 0x00000428 +static u32 A_dsa_dataout_used[] __attribute((unused)) = { + 0x00000143, + 0x00000145, + 0x00000147, + 0x00000149, + 0x0000014b, + 0x0000014d, + 0x0000014f, + 0x00000151, + 0x00000153, + 0x00000155, + 0x00000157, + 0x00000159, + 0x0000015b, + 0x0000015d, + 0x0000015f, + 0x00000161, + 0x00000163, + 0x00000165, + 0x00000167, + 0x00000169, + 0x0000016b, + 0x0000016d, + 0x0000016f, + 0x00000171, + 0x00000173, + 0x00000175, + 0x00000177, + 0x00000179, + 0x0000017b, + 0x0000017d, + 0x0000017f, + 0x00000181, + 0x00000183, + 0x00000185, + 0x00000187, + 0x00000189, + 0x0000018b, + 0x0000018d, + 0x0000018f, + 0x00000191, + 0x00000193, + 0x00000195, + 0x00000197, + 0x00000199, + 0x0000019b, + 0x0000019d, + 0x0000019f, + 0x000001a1, + 0x000001a3, + 0x000001a5, + 0x000001a7, + 0x000001a9, + 0x000001ab, + 0x000001ad, + 0x000001af, + 0x000001b1, + 0x000001b3, + 0x000001b5, + 0x000001b7, + 0x000001b9, + 0x000001bb, + 0x000001bd, + 0x000001bf, + 0x000001c1, + 0x000001c3, + 0x000001c5, + 0x000001c7, + 0x000001c9, + 0x000001cb, + 0x000001cd, + 0x000001cf, + 0x000001d1, + 0x000001d3, + 0x000001d5, + 0x000001d7, + 0x000001d9, + 0x000001db, + 0x000001dd, + 0x000001df, + 0x000001e1, + 0x000001e3, + 0x000001e5, + 0x000001e7, + 0x000001e9, + 0x000001eb, + 0x000001ed, + 0x000001ef, + 0x000001f1, + 0x000001f3, + 0x000001f5, + 0x000001f7, + 0x000001f9, + 0x000001fb, + 0x000001fd, + 0x000001ff, + 0x00000201, + 0x00000203, + 0x00000205, + 0x00000207, + 0x00000209, + 0x0000020b, + 0x0000020d, + 0x0000020f, + 0x00000211, + 0x00000213, + 0x00000215, + 0x00000217, + 0x00000219, + 0x0000021b, + 0x0000021d, + 0x0000021f, + 0x00000221, + 0x00000223, + 0x00000225, + 0x00000227, + 0x00000229, + 0x0000022b, + 0x0000022d, + 0x0000022f, + 0x00000231, + 0x00000233, + 0x00000235, + 0x00000237, + 0x00000239, + 0x0000023b, + 0x0000023d, + 0x0000023f, + 0x00000241, +}; + +#define A_dsa_msgin 0x00000020 +static u32 A_dsa_msgin_used[] __attribute((unused)) = { + 0x0000002f, +}; + +#define A_dsa_msgout 0x00000008 +static u32 A_dsa_msgout_used[] __attribute((unused)) = { + 0x00000013, + 0x00000285, + 0x000002c5, + 0x00000305, +}; + +#define A_dsa_select 0x00000000 +static u32 A_dsa_select_used[] __attribute((unused)) = { + 0x00000006, +}; + +#define A_dsa_size 0x00000828 +static u32 A_dsa_size_used[] __attribute((unused)) = { +}; + +#define A_dsa_status 0x00000018 +static u32 A_dsa_status_used[] __attribute((unused)) = { + 0x0000002b, +}; + +#define A_had_cmdout 0x00000004 +static u32 A_had_cmdout_used[] __attribute((unused)) = { + 0x0000001a, +}; + +#define A_had_datain 0x00000008 +static u32 A_had_datain_used[] __attribute((unused)) = { + 0x00000038, +}; + +#define A_had_dataout 0x00000010 +static u32 A_had_dataout_used[] __attribute((unused)) = { + 0x0000013e, +}; + +#define A_had_extmsg 0x00000080 +static u32 A_had_extmsg_used[] __attribute((unused)) = { + 0x0000025a, + 0x0000029a, + 0x000002da, +}; + +#define A_had_msgin 0x00000040 +static u32 A_had_msgin_used[] __attribute((unused)) = { + 0x00000248, + 0x00000288, + 0x000002c8, +}; + +#define A_had_msgout 0x00000002 +static u32 A_had_msgout_used[] __attribute((unused)) = { + 0x00000010, + 0x00000282, + 0x000002c2, + 0x00000302, +}; + +#define A_had_select 0x00000001 +static u32 A_had_select_used[] __attribute((unused)) = { + 0x0000000c, +}; + +#define A_had_status 0x00000020 +static u32 A_had_status_used[] __attribute((unused)) = { +}; + +#define A_int_bad_extmsg1a 0xab930000 +static u32 A_int_bad_extmsg1a_used[] __attribute((unused)) = { + 0x00000263, +}; + +#define A_int_bad_extmsg1b 0xab930001 +static u32 A_int_bad_extmsg1b_used[] __attribute((unused)) = { + 0x0000026b, +}; + +#define A_int_bad_extmsg2a 0xab930002 +static u32 A_int_bad_extmsg2a_used[] __attribute((unused)) = { + 0x000002a3, +}; + +#define A_int_bad_extmsg2b 0xab930003 +static u32 A_int_bad_extmsg2b_used[] __attribute((unused)) = { + 0x000002ab, +}; + +#define A_int_bad_extmsg3a 0xab930004 +static u32 A_int_bad_extmsg3a_used[] __attribute((unused)) = { + 0x000002e3, +}; + +#define A_int_bad_extmsg3b 0xab930005 +static u32 A_int_bad_extmsg3b_used[] __attribute((unused)) = { + 0x000002eb, +}; + +#define A_int_bad_msg1 0xab930006 +static u32 A_int_bad_msg1_used[] __attribute((unused)) = { + 0x00000255, +}; + +#define A_int_bad_msg2 0xab930007 +static u32 A_int_bad_msg2_used[] __attribute((unused)) = { + 0x00000295, +}; + +#define A_int_bad_msg3 0xab930008 +static u32 A_int_bad_msg3_used[] __attribute((unused)) = { + 0x000002d5, +}; + +#define A_int_cmd_bad_phase 0xab930009 +static u32 A_int_cmd_bad_phase_used[] __attribute((unused)) = { + 0x00000027, +}; + +#define A_int_cmd_complete 0xab93000a +static u32 A_int_cmd_complete_used[] __attribute((unused)) = { + 0x00000037, +}; + +#define A_int_data_bad_phase 0xab93000b +static u32 A_int_data_bad_phase_used[] __attribute((unused)) = { + 0x00000247, +}; + +#define A_int_disc1 0xab930019 +static u32 A_int_disc1_used[] __attribute((unused)) = { + 0x00000277, +}; + +#define A_int_disc2 0xab93001a +static u32 A_int_disc2_used[] __attribute((unused)) = { + 0x000002b7, +}; + +#define A_int_disc3 0xab93001b +static u32 A_int_disc3_used[] __attribute((unused)) = { + 0x000002f7, +}; + +#define A_int_msg_sdtr1 0xab93000c +static u32 A_int_msg_sdtr1_used[] __attribute((unused)) = { + 0x00000271, +}; + +#define A_int_msg_sdtr2 0xab93000d +static u32 A_int_msg_sdtr2_used[] __attribute((unused)) = { + 0x000002b1, +}; + +#define A_int_msg_sdtr3 0xab93000e +static u32 A_int_msg_sdtr3_used[] __attribute((unused)) = { + 0x000002f1, +}; + +#define A_int_no_msgout1 0xab93000f +static u32 A_int_no_msgout1_used[] __attribute((unused)) = { + 0x00000281, +}; + +#define A_int_no_msgout2 0xab930010 +static u32 A_int_no_msgout2_used[] __attribute((unused)) = { + 0x000002c1, +}; + +#define A_int_no_msgout3 0xab930011 +static u32 A_int_no_msgout3_used[] __attribute((unused)) = { + 0x00000301, +}; + +#define A_int_not_cmd_complete 0xab930012 +static u32 A_int_not_cmd_complete_used[] __attribute((unused)) = { + 0x00000031, +}; + +#define A_int_not_rej 0xab93001c +static u32 A_int_not_rej_used[] __attribute((unused)) = { + 0x0000030d, +}; + +#define A_int_resel_not_msgin 0xab930016 +static u32 A_int_resel_not_msgin_used[] __attribute((unused)) = { + 0x00000317, +}; + +#define A_int_reselected 0xab930017 +static u32 A_int_reselected_used[] __attribute((unused)) = { + 0x0000031b, +}; + +#define A_int_sel_no_ident 0xab930013 +static u32 A_int_sel_no_ident_used[] __attribute((unused)) = { + 0x0000000f, +}; + +#define A_int_sel_not_cmd 0xab930014 +static u32 A_int_sel_not_cmd_used[] __attribute((unused)) = { + 0x00000019, +}; + +#define A_int_selected 0xab930018 +static u32 A_int_selected_used[] __attribute((unused)) = { + 0x0000032d, +}; + +#define A_int_status_not_msgin 0xab930015 +static u32 A_int_status_not_msgin_used[] __attribute((unused)) = { + 0x0000002d, +}; + +#define A_msgin_buf 0x00000000 +static u32 A_msgin_buf_used[] __attribute((unused)) = { + 0x0000024b, + 0x0000025f, + 0x00000267, + 0x0000026f, + 0x0000028b, + 0x0000029f, + 0x000002a7, + 0x000002af, + 0x000002cb, + 0x000002df, + 0x000002e7, + 0x000002ef, + 0x0000030b, +}; + +#define A_reselected_identify 0x00000000 +static u32 A_reselected_identify_used[] __attribute((unused)) = { + 0x00000319, +}; + +#define Ent_do_select 0x00000000 +#define Ent_done_ident 0x00000050 +#define Ent_end_data_trans 0x00000908 +#define Ent_patch_input_data 0x000000e8 +#define Ent_patch_new_dsa 0x00000c88 +#define Ent_patch_output_data 0x00000500 +#define Ent_reselect 0x00000c48 +#define Ent_resume_cmd 0x00000068 +#define Ent_resume_msgin1a 0x000009e0 +#define Ent_resume_msgin1b 0x000009f0 +#define Ent_resume_msgin2a 0x00000ae0 +#define Ent_resume_msgin2b 0x00000af0 +#define Ent_resume_msgin3a 0x00000be0 +#define Ent_resume_msgin3b 0x00000bf0 +#define Ent_resume_pmm 0x00000078 +#define Ent_resume_rej_ident 0x00000c20 +#define Ent_wait_disc1 0x000009d0 +#define Ent_wait_disc2 0x00000ad0 +#define Ent_wait_disc3 0x00000bd0 +#define Ent_wait_disc_complete 0x000000d0 +static u32 LABELPATCHES[] __attribute((unused)) = { + 0x00000007, + 0x00000009, + 0x00000015, + 0x00000017, + 0x0000001f, + 0x00000021, + 0x00000023, + 0x00000025, + 0x0000013d, + 0x00000243, + 0x00000245, + 0x0000024d, + 0x0000024f, + 0x00000251, + 0x00000253, + 0x00000259, + 0x00000261, + 0x00000269, + 0x0000027b, + 0x00000287, + 0x0000028d, + 0x0000028f, + 0x00000291, + 0x00000293, + 0x00000299, + 0x000002a1, + 0x000002a9, + 0x000002bb, + 0x000002c7, + 0x000002cd, + 0x000002cf, + 0x000002d1, + 0x000002d3, + 0x000002d9, + 0x000002e1, + 0x000002e9, + 0x000002fb, + 0x00000307, + 0x00000311, + 0x00000315, + 0x0000031f, + 0x0000032b, +}; + +static struct { + u32 offset; + void *address; +} EXTERNAL_PATCHES[] __attribute((unused)) = { +}; + +static u32 INSTRUCTIONS __attribute((unused)) = 407; +static u32 PATCHES __attribute((unused)) = 42; +static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/sim710_u.h linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/sim710_u.h --- linux-2.4.20-wolk4.6-fullkernel/drivers/scsi/sim710_u.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/scsi/sim710_u.h 2002-08-03 02:39:44.000000000 +0200 @@ -0,0 +1,67 @@ +#undef A_did_reject +#undef A_dsa_cmnd +#undef A_dsa_datain +#undef A_dsa_dataout +#undef A_dsa_msgin +#undef A_dsa_msgout +#undef A_dsa_select +#undef A_dsa_size +#undef A_dsa_status +#undef A_had_cmdout +#undef A_had_datain +#undef A_had_dataout +#undef A_had_extmsg +#undef A_had_msgin +#undef A_had_msgout +#undef A_had_select +#undef A_had_status +#undef A_int_bad_msg1 +#undef A_int_bad_msg2 +#undef A_int_bad_msg3 +#undef A_int_cmd_bad_phase +#undef A_int_cmd_complete +#undef A_int_data_bad_phase +#undef A_int_disc1 +#undef A_int_disc2 +#undef A_int_disc3 +#undef A_int_msg_sdtr1 +#undef A_int_msg_sdtr2 +#undef A_int_msg_sdtr3 +#undef A_int_no_msgout1 +#undef A_int_no_msgout2 +#undef A_int_no_msgout3 +#undef A_int_not_cmd_complete +#undef A_int_not_rej +#undef A_int_resel_not_msgin +#undef A_int_reselected +#undef A_int_sel_no_ident +#undef A_int_sel_not_cmd +#undef A_int_selected +#undef A_int_status_not_msgin +#undef A_int_test1 +#undef A_msg_reject +#undef A_msgin_buf +#undef A_reselected_identify +#undef A_test1_dst +#undef A_test1_src +#undef Ent_do_select +#undef Ent_done_ident +#undef Ent_end_data_trans +#undef Ent_patch_input_data +#undef Ent_patch_new_dsa +#undef Ent_patch_output_data +#undef Ent_reselect +#undef Ent_resume_cmd +#undef Ent_resume_msgin1a +#undef Ent_resume_msgin1b +#undef Ent_resume_msgin2a +#undef Ent_resume_msgin2b +#undef Ent_resume_msgin3a +#undef Ent_resume_msgin3b +#undef Ent_resume_pmm +#undef Ent_resume_rej_ident +#undef Ent_test1 +#undef Ent_wait_disc1 +#undef Ent_wait_disc2 +#undef Ent_wait_disc3 +#undef Ent_wait_disc_complete diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/Config.in linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/Config.in --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/Config.in 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/Config.in 2003-08-17 21:26:58.000000000 +0200 @@ -15,6 +15,7 @@ if [ "$CONFIG_I2C_PROC" = "m" -o "$CONFI dep_tristate ' Analog Devices ADM1021 and compatibles' CONFIG_SENSORS_ADM1021 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Analog Devices ADM1024' CONFIG_SENSORS_ADM1024 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Analog Devices ADM1025' CONFIG_SENSORS_ADM1025 $CONFIG_I2C $CONFIG_I2C_PROC + dep_tristate ' Analog Devices ADM1026' CONFIG_SENSORS_ADM1026 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Analog Devices ADM9240 and compatibles' CONFIG_SENSORS_ADM9240 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Dallas DS1621 and DS1625' CONFIG_SENSORS_DS1621 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Fujitsu-Siemens Poseidon' CONFIG_SENSORS_FSCPOS $CONFIG_I2C $CONFIG_I2C_PROC @@ -27,6 +28,7 @@ if [ "$CONFIG_I2C_PROC" = "m" -o "$CONFI dep_tristate ' National Semiconductor LM75 and compatibles' CONFIG_SENSORS_LM75 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' National Semiconductor LM78' CONFIG_SENSORS_LM78 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' National Semiconductor LM80' CONFIG_SENSORS_LM80 $CONFIG_I2C $CONFIG_I2C_PROC + dep_tristate ' National Semiconductor LM85, Analog Devices ADM1027' CONFIG_SENSORS_LM85 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' National Semiconductor LM87' CONFIG_SENSORS_LM87 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' National Semiconductor LM92' CONFIG_SENSORS_LM92 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Silicon Integrated Systems Corp. SiS5595' CONFIG_SENSORS_SIS5595 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/Makefile linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/Makefile --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/Makefile 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/Makefile 2003-08-17 21:26:58.000000000 +0200 @@ -5,12 +5,10 @@ MOD_LIST_NAME := SENSORS_MODULES O_TARGET := sensor.o -export-objs := sensors.o - -obj-$(CONFIG_SENSORS) += sensors.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1024) += adm1024.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o +obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o obj-$(CONFIG_SENSORS_BT869) += bt869.o obj-$(CONFIG_SENSORS_DDCMON) += ddcmon.o @@ -24,6 +22,7 @@ obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_LM75) += lm75.o obj-$(CONFIG_SENSORS_LM78) += lm78.o obj-$(CONFIG_SENSORS_LM80) += lm80.o +obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM92) += lm92.o obj-$(CONFIG_SENSORS_MAXILIFE) += maxilife.o diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1021.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1021.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1021.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1021.c 2003-08-17 21:26:58.000000000 +0200 @@ -19,27 +19,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -59,8 +45,9 @@ SENSORS_INSMOD_8(adm1021, adm1023, max16 #define ADM1021_REG_TEMP 0x00 #define ADM1021_REG_REMOTE_TEMP 0x01 #define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = Analog Devices, 0x49 = TI, + 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ +#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1021A/ADM1023 = 0x3X */ #define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ /* These use different addresses for reading/writing */ #define ADM1021_REG_CONFIG_R 0x03 @@ -85,6 +72,10 @@ SENSORS_INSMOD_8(adm1021, adm1023, max16 /* write-only */ #define ADM1021_REG_ONESHOT 0x0F +#define ADM1021_ALARM_TEMP (ADM1021_ALARM_TEMP_HIGH | ADM1021_ALARM_TEMP_LOW) +#define ADM1021_ALARM_RTEMP (ADM1021_ALARM_RTEMP_HIGH | ADM1021_ALARM_RTEMP_LOW\ + | ADM1021_ALARM_RTEMP_NA) +#define ADM1021_ALARM_ALL (ADM1021_ALARM_TEMP | ADM1021_ALARM_RTEMP) /* Conversions. Rounding and limit checking is only done on the TO_REG variants. Note that you should be a bit careful with which arguments @@ -116,33 +107,19 @@ struct adm1021_data { u8 temp, temp_os, temp_hyst; /* Register values */ u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code; + u8 fail; /* Special values for ADM1023 only */ u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec, remote_temp_offset, remote_temp_offset_prec; }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_adm1021_init(void); -static int __init adm1021_cleanup(void); static int adm1021_attach_adapter(struct i2c_adapter *adapter); static int adm1021_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void adm1021_init_client(struct i2c_client *client); static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void adm1021_inc_use(struct i2c_client *client); -static void adm1021_dec_use(struct i2c_client *client); static int adm1021_read_value(struct i2c_client *client, u8 reg); +static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask); static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value); static void adm1021_temp(struct i2c_client *client, int operation, @@ -162,16 +139,29 @@ static int read_only = 0; /* This is the driver that will be inserted */ static struct i2c_driver adm1021_driver = { - /* name */ "ADM1021, MAX1617 sensor driver", - /* id */ I2C_DRIVERID_ADM1021, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &adm1021_attach_adapter, - /* detach_client */ &adm1021_detach_client, - /* command */ &adm1021_command, - /* inc_use */ &adm1021_inc_use, - /* dec_use */ &adm1021_dec_use + .owner = THIS_MODULE, + .name = "ADM1021, MAX1617 sensor driver", + .id = I2C_DRIVERID_ADM1021, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1021_attach_adapter, + .detach_client = adm1021_detach_client, }; +/* -- SENSORS SYSCTL START -- */ + +#define ADM1021_SYSCTL_TEMP 1200 +#define ADM1021_SYSCTL_REMOTE_TEMP 1201 +#define ADM1021_SYSCTL_DIE_CODE 1202 +#define ADM1021_SYSCTL_ALARMS 1203 + +#define ADM1021_ALARM_TEMP_HIGH 0x40 +#define ADM1021_ALARM_TEMP_LOW 0x20 +#define ADM1021_ALARM_RTEMP_HIGH 0x10 +#define ADM1021_ALARM_RTEMP_LOW 0x08 +#define ADM1021_ALARM_RTEMP_NA 0x04 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected adm1021. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -199,15 +189,12 @@ static ctl_table adm1021_max_dir_table_t {0} }; -/* Used by init/cleanup */ -static int __initdata adm1021_initialized = 0; - /* I choose here for semi-static allocation. Complete dynamic allocation could also be used; the code needed for this would probably take more memory than the datastructure takes now. */ static int adm1021_id = 0; -int adm1021_attach_adapter(struct i2c_adapter *adapter) +static int adm1021_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, adm1021_detect); } @@ -233,7 +220,7 @@ static int adm1021_detect(struct i2c_ada #endif if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; + goto error0; /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. @@ -243,7 +230,7 @@ static int adm1021_detect(struct i2c_ada sizeof(struct adm1021_data), GFP_KERNEL))) { err = -ENOMEM; - goto ERROR0; + goto error0; } data = (struct adm1021_data *) (new_client + 1); @@ -259,7 +246,7 @@ static int adm1021_detect(struct i2c_ada if ( (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00) - goto ERROR1; + goto error1; } /* Determine the chip type. */ @@ -319,7 +306,7 @@ static int adm1021_detect(struct i2c_ada printk("adm1021.o: Internal error: unknown kind (%d)?!?", kind); #endif - goto ERROR1; + goto error1; } /* Fill in the remaining client fields and put it into the global list */ @@ -332,18 +319,14 @@ static int adm1021_detect(struct i2c_ada /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto ERROR3; + goto error3; /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - data->type == - adm1021 ? - adm1021_dir_table_template : - adm1021_max_dir_table_template, - THIS_MODULE)) < 0) { + if ((i = i2c_register_entry(new_client, type_name, + data->type == adm1021 ? adm1021_dir_table_template : + adm1021_max_dir_table_template)) < 0) { err = i; - goto ERROR4; + goto error4; } data->sysctl_id = i; @@ -351,19 +334,16 @@ static int adm1021_detect(struct i2c_ada adm1021_init_client(new_client); return 0; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: + error4: i2c_detach_client(new_client); - ERROR3: - ERROR1: + error3: + error1: kfree(new_client); - ERROR0: + error0: return err; } -void adm1021_init_client(struct i2c_client *client) +static void adm1021_init_client(struct i2c_client *client) { /* Initialize the adm1021 chip */ adm1021_write_value(client, ADM1021_REG_TOS_W, @@ -380,7 +360,7 @@ void adm1021_init_client(struct i2c_clie adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); } -int adm1021_detach_client(struct i2c_client *client) +static int adm1021_detach_client(struct i2c_client *client) { int err; @@ -401,33 +381,28 @@ int adm1021_detach_client(struct i2c_cli } -/* No commands defined yet */ -int adm1021_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void adm1021_inc_use(struct i2c_client *client) +/* All registers are byte-sized */ +static int adm1021_read_value(struct i2c_client *client, u8 reg) { -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif + return i2c_smbus_read_byte_data(client, reg); } -void adm1021_dec_use(struct i2c_client *client) +/* only update value if read succeeded; set fail bit if failed */ +static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask) { -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} + int i; + struct adm1021_data *data = client->data; -/* All registers are byte-sized */ -int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); + i = i2c_smbus_read_byte_data(client, reg); + if (i < 0) { + data->fail |= mask; + return i; + } + *val = i; + return 0; } -int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) +static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) { if (read_only > 0) return 0; @@ -435,47 +410,56 @@ int adm1021_write_value(struct i2c_clien return i2c_smbus_write_byte_data(client, reg, value); } -void adm1021_update_client(struct i2c_client *client) +static void adm1021_update_client(struct i2c_client *client) { struct adm1021_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || - !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting adm1021 update\n"); #endif - data->temp = adm1021_read_value(client, ADM1021_REG_TEMP); - data->temp_os = - adm1021_read_value(client, ADM1021_REG_TOS_R); - data->temp_hyst = - adm1021_read_value(client, ADM1021_REG_THYST_R); - data->remote_temp = - adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); - data->remote_temp_os = - adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = - adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); - data->alarms = - adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec; + data->fail = 0; + adm1021_rd_good(&(data->temp), client, ADM1021_REG_TEMP, + ADM1021_ALARM_TEMP); + adm1021_rd_good(&(data->temp_os), client, ADM1021_REG_TOS_R, + ADM1021_ALARM_TEMP); + adm1021_rd_good(&(data->temp_hyst), client, + ADM1021_REG_THYST_R, ADM1021_ALARM_TEMP); + adm1021_rd_good(&(data->remote_temp), client, + ADM1021_REG_REMOTE_TEMP, ADM1021_ALARM_RTEMP); + adm1021_rd_good(&(data->remote_temp_os), client, + ADM1021_REG_REMOTE_TOS_R, ADM1021_ALARM_RTEMP); + adm1021_rd_good(&(data->remote_temp_hyst), client, + ADM1021_REG_REMOTE_THYST_R, + ADM1021_ALARM_RTEMP); + data->alarms = ADM1021_ALARM_ALL; + if (!adm1021_rd_good(&(data->alarms), client, + ADM1021_REG_STATUS, 0)) + data->alarms &= ADM1021_ALARM_ALL; if (data->type == adm1021) - data->die_code = - adm1021_read_value(client, - ADM1021_REG_DIE_CODE); + adm1021_rd_good(&(data->die_code), client, + ADM1021_REG_DIE_CODE, 0); if (data->type == adm1023) { - data->remote_temp_prec = - adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); - data->remote_temp_os_prec = - adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); - data->remote_temp_hyst_prec = - adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); - data->remote_temp_offset = - adm1021_read_value(client, ADM1021_REG_REM_OFFSET); - data->remote_temp_offset_prec = - adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + adm1021_rd_good(&(data->remote_temp_prec), client, + ADM1021_REG_REM_TEMP_PREC, + ADM1021_ALARM_TEMP); + adm1021_rd_good(&(data->remote_temp_os_prec), client, + ADM1021_REG_REM_TOS_PREC, + ADM1021_ALARM_RTEMP); + adm1021_rd_good(&(data->remote_temp_hyst_prec), client, + ADM1021_REG_REM_THYST_PREC, + ADM1021_ALARM_RTEMP); + adm1021_rd_good(&(data->remote_temp_offset), client, + ADM1021_REG_REM_OFFSET, + ADM1021_ALARM_RTEMP); + adm1021_rd_good(&(data->remote_temp_offset_prec), + client, ADM1021_REG_REM_OFFSET_PREC, + ADM1021_ALARM_RTEMP); } data->last_updated = jiffies; data->valid = 1; @@ -514,8 +498,9 @@ void adm1021_temp(struct i2c_client *cli void adm1021_remote_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { -int prec=0; struct adm1021_data *data = client->data; + int prec = 0; + if (operation == SENSORS_PROC_REAL_INFO) if (data->type == adm1023) { *nrels_mag = 3; } else { *nrels_mag = 0; } @@ -606,64 +591,31 @@ void adm1021_alarms(struct i2c_client *c *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { adm1021_update_client(client); - results[0] = data->alarms; + results[0] = data->alarms | data->fail; *nrels_mag = 1; } else if (operation == SENSORS_PROC_REAL_WRITE) { /* Can't write to it */ } } -int __init sensors_adm1021_init(void) +static int __init sm_adm1021_init(void) { - int res; - - printk("adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE); - adm1021_initialized = 0; - if ((res = i2c_add_driver(&adm1021_driver))) { - printk - ("adm1021.o: Driver registration failed, module not inserted.\n"); - adm1021_cleanup(); - return res; - } - adm1021_initialized++; - return 0; + printk(KERN_INFO "adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE); + return i2c_add_driver(&adm1021_driver); } -int __init adm1021_cleanup(void) +static void __exit sm_adm1021_exit(void) { - int res; - - if (adm1021_initialized >= 1) { - if ((res = i2c_del_driver(&adm1021_driver))) { - printk - ("adm1021.o: Driver deregistration failed, module not removed.\n"); - return res; - } - adm1021_initialized--; - } - - return 0; + i2c_del_driver(&adm1021_driver); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("adm1021 driver"); +MODULE_LICENSE("GPL"); MODULE_PARM(read_only, "i"); MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); -int init_module(void) -{ - return sensors_adm1021_init(); -} - -int cleanup_module(void) -{ - return adm1021_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_adm1021_init) +module_exit(sm_adm1021_exit) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1024.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1024.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1024.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1024.c 2003-08-17 21:26:58.000000000 +0200 @@ -23,29 +23,19 @@ /* Supports the Analog Devices ADM1024. See doc/chips/adm1024 for details */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -127,7 +117,7 @@ SENSORS_INSMOD_1(adm1024); #define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255)) #define IN_FROM_REG(val,nr) (val) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -203,11 +193,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define ADM1024_INIT_TEMP_HOT_MAX 700 #define ADM1024_INIT_TEMP_HOT_HYST 600 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered ADM1024, we need to keep some data in memory. That data is pointed to by adm1024_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new adm1024 client is @@ -241,22 +226,11 @@ struct adm1024_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_adm1024_init(void); -static int __init adm1024_cleanup(void); static int adm1024_attach_adapter(struct i2c_adapter *adapter); static int adm1024_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int adm1024_detach_client(struct i2c_client *client); -static int adm1024_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void adm1024_inc_use(struct i2c_client *client); -static void adm1024_dec_use(struct i2c_client *client); static int adm1024_read_value(struct i2c_client *client, u8 register); static int adm1024_write_value(struct i2c_client *client, u8 register, @@ -291,20 +265,48 @@ static void adm1024_vid(struct i2c_clien static int adm1024_id = 0; static struct i2c_driver adm1024_driver = { - /* name */ "ADM1024 sensor driver", - /* id */ I2C_DRIVERID_ADM1024, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &adm1024_attach_adapter, - /* detach_client */ &adm1024_detach_client, - /* command */ &adm1024_command, - /* inc_use */ &adm1024_inc_use, - /* dec_use */ &adm1024_dec_use + .owner = THIS_MODULE, + .name = "ADM1024 sensor driver", + .id = I2C_DRIVERID_ADM1024, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1024_attach_adapter, + .detach_client = adm1024_detach_client, }; -/* Used by adm1024_init/cleanup */ -static int __initdata adm1024_initialized = 0; - /* The /proc/sys entries */ +/* -- SENSORS SYSCTL START -- */ + +#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1024_SYSCTL_IN1 1001 +#define ADM1024_SYSCTL_IN2 1002 +#define ADM1024_SYSCTL_IN3 1003 +#define ADM1024_SYSCTL_IN4 1004 +#define ADM1024_SYSCTL_IN5 1005 +#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM1024_SYSCTL_FAN2 1102 +#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celcius */ +#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celcius */ +#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1024_SYSCTL_ANALOG_OUT 2002 +#define ADM1024_SYSCTL_VID 2003 + +#define ADM1024_ALARM_IN0 0x0001 +#define ADM1024_ALARM_IN1 0x0002 +#define ADM1024_ALARM_IN2 0x0004 +#define ADM1024_ALARM_IN3 0x0008 +#define ADM1024_ALARM_IN4 0x0100 +#define ADM1024_ALARM_IN5 0x0200 +#define ADM1024_ALARM_FAN1 0x0040 +#define ADM1024_ALARM_FAN2 0x0080 +#define ADM1024_ALARM_TEMP 0x0010 +#define ADM1024_ALARM_TEMP1 0x0020 +#define ADM1024_ALARM_TEMP2 0x0001 +#define ADM1024_ALARM_CHAS 0x1000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected ADM1024. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -344,7 +346,7 @@ static ctl_table adm1024_dir_table_templ {0} }; -int adm1024_attach_adapter(struct i2c_adapter *adapter) +static int adm1024_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, adm1024_detect); } @@ -438,8 +440,7 @@ static int adm1024_detect(struct i2c_ada /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - adm1024_dir_table_template, - THIS_MODULE)) < 0) { + adm1024_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -461,7 +462,7 @@ static int adm1024_detect(struct i2c_ada return err; } -int adm1024_detach_client(struct i2c_client *client) +static int adm1024_detach_client(struct i2c_client *client) { int err; @@ -480,38 +481,18 @@ int adm1024_detach_client(struct i2c_cli } -/* No commands defined yet */ -int adm1024_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void adm1024_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void adm1024_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -int adm1024_read_value(struct i2c_client *client, u8 reg) +static int adm1024_read_value(struct i2c_client *client, u8 reg) { return 0xFF & i2c_smbus_read_byte_data(client, reg); } -int adm1024_write_value(struct i2c_client *client, u8 reg, u8 value) +static int adm1024_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* Called when we have found a new ADM1024. It should set limits, etc. */ -void adm1024_init_client(struct i2c_client *client) +static void adm1024_init_client(struct i2c_client *client) { /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others. This makes most other @@ -567,16 +548,17 @@ void adm1024_init_client(struct i2c_clie adm1024_write_value(client, ADM1024_REG_CONFIG, 0x07); } -void adm1024_update_client(struct i2c_client *client) +static void adm1024_update_client(struct i2c_client *client) { struct adm1024_data *data = client->data; - int timeout = data->type == adm1024 ? HZ / 2 : HZ * 2; u8 i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + timeout) - || !data->valid) { + if ( + (jiffies - data->last_updated > + (data->type == adm1024 ? HZ / 2 : HZ * 2)) + || (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting adm1024 update\n"); @@ -879,58 +861,24 @@ void adm1024_vid(struct i2c_client *clie } } -int __init sensors_adm1024_init(void) +static int __init sm_adm1024_init(void) { - int res; - printk("adm1024.o version %s (%s)\n", LM_VERSION, LM_DATE); - adm1024_initialized = 0; - - if ((res = i2c_add_driver(&adm1024_driver))) { - printk - ("adm1024.o: Driver registration failed, module not inserted.\n"); - adm1024_cleanup(); - return res; - } - adm1024_initialized++; - return 0; + return i2c_add_driver(&adm1024_driver); } -int __init adm1024_cleanup(void) +static void __exit sm_adm1024_exit(void) { - int res; - - if (adm1024_initialized >= 1) { - if ((res = i2c_del_driver(&adm1024_driver))) { - printk - ("adm1024.o: Driver deregistration failed, module not removed.\n"); - return res; - } - adm1024_initialized--; - } - return 0; + i2c_del_driver(&adm1024_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("ADM1024 driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return sensors_adm1024_init(); -} - -int cleanup_module(void) -{ - return adm1024_cleanup(); -} -#endif /* MODULE */ +module_init(sm_adm1024_init); +module_exit(sm_adm1024_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1025.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1025.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1025.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1025.c 2003-08-17 21:26:58.000000000 +0200 @@ -22,34 +22,22 @@ /* Supports the Analog Devices ADM1025. See doc/chips/adm1025 for details */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -158,11 +146,6 @@ SENSORS_INSMOD_1(adm1025); #define ADM1025_INIT_TEMP_MAX 600 #define ADM1025_INIT_TEMP_MIN 0 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered ADM1025, we need to keep some data in memory. That data is pointed to by adm1025_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new adm1025 client is @@ -191,23 +174,10 @@ struct adm1025_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_adm1025_init(void); -static int __init adm1025_cleanup(void); - static int adm1025_attach_adapter(struct i2c_adapter *adapter); static int adm1025_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int adm1025_detach_client(struct i2c_client *client); -static int adm1025_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void adm1025_inc_use(struct i2c_client *client); -static void adm1025_dec_use(struct i2c_client *client); - static int adm1025_read_value(struct i2c_client *client, u8 register); static int adm1025_write_value(struct i2c_client *client, u8 register, u8 value); @@ -237,20 +207,41 @@ static void adm1025_vrm(struct i2c_clien static int adm1025_id = 0; static struct i2c_driver adm1025_driver = { - /* name */ "ADM1025 sensor driver", - /* id */ I2C_DRIVERID_ADM1025, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &adm1025_attach_adapter, - /* detach_client */ &adm1025_detach_client, - /* command */ &adm1025_command, - /* inc_use */ &adm1025_inc_use, - /* dec_use */ &adm1025_dec_use + .owner = THIS_MODULE, + .name = "ADM1025 sensor driver", + .id = I2C_DRIVERID_ADM1025, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1025_attach_adapter, + .detach_client = adm1025_detach_client, }; -/* Used by adm1025_init/cleanup */ -static int __initdata adm1025_initialized = 0; - /* The /proc/sys entries */ +/* -- SENSORS SYSCTL START -- */ + +#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1025_SYSCTL_IN1 1001 +#define ADM1025_SYSCTL_IN2 1002 +#define ADM1025_SYSCTL_IN3 1003 +#define ADM1025_SYSCTL_IN4 1004 +#define ADM1025_SYSCTL_IN5 1005 +#define ADM1025_SYSCTL_RTEMP 1251 +#define ADM1025_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1025_SYSCTL_ANALOG_OUT 2002 +#define ADM1025_SYSCTL_VID 2003 +#define ADM1025_SYSCTL_VRM 2004 + +#define ADM1025_ALARM_IN0 0x0001 +#define ADM1025_ALARM_IN1 0x0002 +#define ADM1025_ALARM_IN2 0x0004 +#define ADM1025_ALARM_IN3 0x0008 +#define ADM1025_ALARM_IN4 0x0100 +#define ADM1025_ALARM_IN5 0x0200 +#define ADM1025_ALARM_RTEMP 0x0020 +#define ADM1025_ALARM_TEMP 0x0010 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected ADM1025. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -284,7 +275,7 @@ static ctl_table adm1025_dir_table_templ {0} }; -int adm1025_attach_adapter(struct i2c_adapter *adapter) +static int adm1025_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, adm1025_detect); } @@ -378,8 +369,7 @@ static int adm1025_detect(struct i2c_ada /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - adm1025_dir_table_template, - THIS_MODULE)) < 0) { + adm1025_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -401,7 +391,7 @@ static int adm1025_detect(struct i2c_ada return err; } -int adm1025_detach_client(struct i2c_client *client) +static int adm1025_detach_client(struct i2c_client *client) { int err; @@ -420,38 +410,18 @@ int adm1025_detach_client(struct i2c_cli } -/* No commands defined yet */ -int adm1025_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void adm1025_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void adm1025_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -int adm1025_read_value(struct i2c_client *client, u8 reg) +static int adm1025_read_value(struct i2c_client *client, u8 reg) { return 0xFF & i2c_smbus_read_byte_data(client, reg); } -int adm1025_write_value(struct i2c_client *client, u8 reg, u8 value) +static int adm1025_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* Called when we have found a new ADM1025. It should set limits, etc. */ -void adm1025_init_client(struct i2c_client *client) +static void adm1025_init_client(struct i2c_client *client) { struct adm1025_data *data = client->data; @@ -499,16 +469,17 @@ void adm1025_init_client(struct i2c_clie adm1025_write_value(client, ADM1025_REG_CONFIG, 0x01); } -void adm1025_update_client(struct i2c_client *client) +static void adm1025_update_client(struct i2c_client *client) { struct adm1025_data *data = client->data; - int timeout = data->type == adm1025 ? HZ / 2 : HZ * 2; u8 i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + timeout) - || !data->valid) { + if ( + (jiffies - data->last_updated > + (data->type == adm1025 ? HZ / 2 : HZ * 2)) + || (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting adm1025 update\n"); @@ -723,54 +694,22 @@ void adm1025_vrm(struct i2c_client *clie } } -int __init sensors_adm1025_init(void) +static int __init sm_adm1025_init(void) { - int res; - printk("adm1025.o version %s (%s)\n", LM_VERSION, LM_DATE); - adm1025_initialized = 0; - - if ((res = i2c_add_driver(&adm1025_driver))) { - printk - ("adm1025.o: Driver registration failed, module not inserted.\n"); - adm1025_cleanup(); - return res; - } - adm1025_initialized++; - return 0; + return i2c_add_driver(&adm1025_driver); } -int __init adm1025_cleanup(void) +static void __exit sm_adm1025_exit(void) { - int res; - - if (adm1025_initialized >= 1) { - if ((res = i2c_del_driver(&adm1025_driver))) { - printk - ("adm1025.o: Driver deregistration failed, module not removed.\n"); - return res; - } - adm1025_initialized--; - } - return 0; + i2c_del_driver(&adm1025_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("ADM1025 driver"); -int init_module(void) -{ - return sensors_adm1025_init(); -} - -int cleanup_module(void) -{ - return adm1025_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_adm1025_init); +module_exit(sm_adm1025_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1026.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1026.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/adm1026.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/adm1026.c 2003-08-17 21:26:58.000000000 +0200 @@ -0,0 +1,1754 @@ +/* + adm1026.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 2002, 2003 Philip Pokorny + + 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. + + CHANGELOG + + 2003-03-13 Initial development + 2003-05-07 First Release. Includes GPIO fixup and full + functionality. + 2003-05-18 Minor fixups and tweaks. + Print GPIO config after fixup. + Adjust fan MIN if DIV changes. + 2003-05-21 Fix printing of FAN/GPIO config + Fix silly bug in fan_div logic + Fix fan_min handling so that 0xff is 0 is 0xff + 2003-05-25 Fix more silly typos... + 2003-06-11 Change FAN_xx_REG macros to use different scaling + Most (all?) drivers assume two pulses per rev fans + and the old scaling was producing double the RPM's + Thanks to Jerome Hsiao @ Arima for pointing this out. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include + +#ifndef I2C_DRIVERID_ADM1026 +/* i2c-id.h hasn't been updated to assign us an ID. + * So... Use a local ID from 0xf000 to 0xffff as + * documented in i2c-id.h + */ +#define I2C_DRIVERID_ADM1026 (0xf126) +#endif + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(adm1026); + +static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +MODULE_PARM(gpio_input,"1-17i"); +MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); +MODULE_PARM(gpio_output,"1-17i"); +MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as outputs"); +MODULE_PARM(gpio_inverted,"1-17i"); +MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as inverted"); +MODULE_PARM(gpio_normal,"1-17i"); +MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as normal/non-inverted"); +MODULE_PARM(gpio_fan,"1-8i"); +MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); + +/* Many ADM1026 constants specified below */ + +/* The ADM1026 registers */ +#define ADM1026_REG_CONFIG1 (0x00) +#define CFG1_MONITOR (0x01) +#define CFG1_INT_ENABLE (0x02) +#define CFG1_INT_CLEAR (0x04) +#define CFG1_AIN8_9 (0x08) +#define CFG1_THERM_HOT (0x10) +#define CFG1_DAC_AFC (0x20) +#define CFG1_PWM_AFC (0x40) +#define CFG1_RESET (0x80) +#define ADM1026_REG_CONFIG2 (0x01) +/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ +#define ADM1026_REG_CONFIG3 (0x07) +#define CFG3_GPIO16_ENABLE (0x01) +#define CFG3_CI_CLEAR (0x02) +#define CFG3_VREF_250 (0x04) +#define CFG3_GPIO16_DIR (0x40) +#define CFG3_GPIO16_POL (0x80) +#define ADM1026_REG_E2CONFIG (0x13) +#define E2CFG_READ (0x01) +#define E2CFG_WRITE (0x02) +#define E2CFG_ERASE (0x04) +#define E2CFG_ROM (0x08) +#define E2CFG_CLK_EXT (0x80) + +/* There are 10 general analog inputs and 7 dedicated inputs + * They are: + * 0 - 9 = AIN0 - AIN9 + * 10 = Vbat + * 11 = 3.3V Standby + * 12 = 3.3V Main + * 13 = +5V + * 14 = Vccp (CPU core voltage) + * 15 = +12V + * 16 = -12V + */ +static u16 REG_IN[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f + }; +static u16 REG_IN_MIN[] = { + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, + 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }; +static u16 REG_IN_MAX[] = { + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x47 + }; +#define ADM1026_REG_IN(nr) (REG_IN[(nr)]) +#define ADM1026_REG_IN_MIN(nr) (REG_IN_MIN[(nr)]) +#define ADM1026_REG_IN_MAX(nr) (REG_IN_MAX[(nr)]) + +/* Temperatures are: + * 0 - Internal + * 1 - External 1 + * 2 - External 2 + */ +static u16 REG_TEMP[] = { 0x1f, 0x28, 0x29 }; +static u16 REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; +static u16 REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; +static u16 REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; +static u16 REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; +static u16 REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; +#define ADM1026_REG_TEMP(nr) (REG_TEMP[(nr)]) +#define ADM1026_REG_TEMP_MIN(nr) (REG_TEMP_MIN[(nr)]) +#define ADM1026_REG_TEMP_MAX(nr) (REG_TEMP_MAX[(nr)]) +#define ADM1026_REG_TEMP_TMIN(nr) (REG_TEMP_TMIN[(nr)]) +#define ADM1026_REG_TEMP_THERM(nr) (REG_TEMP_THERM[(nr)]) +#define ADM1026_REG_TEMP_OFFSET(nr) (REG_TEMP_OFFSET[(nr)]) + +#define ADM1026_REG_FAN(nr) (0x38 + (nr)) +#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) +#define ADM1026_REG_FAN_DIV_0_3 (0x02) +#define ADM1026_REG_FAN_DIV_4_7 (0x03) + +#define ADM1026_REG_DAC (0x04) +#define ADM1026_REG_PWM (0x05) + +#define ADM1026_REG_GPIO_CFG_0_3 (0x08) +#define ADM1026_REG_GPIO_CFG_4_7 (0x09) +#define ADM1026_REG_GPIO_CFG_8_11 (0x0a) +#define ADM1026_REG_GPIO_CFG_12_15 (0x0b) +/* CFG_16 in REG_CFG3 */ +#define ADM1026_REG_GPIO_STATUS_0_7 (0x24) +#define ADM1026_REG_GPIO_STATUS_8_15 (0x25) +/* STATUS_16 in REG_STATUS4 */ +#define ADM1026_REG_GPIO_MASK_0_7 (0x1c) +#define ADM1026_REG_GPIO_MASK_8_15 (0x1d) +/* MASK_16 in REG_MASK4 */ + +#define ADM1026_REG_COMPANY 0x16 +#define ADM1026_REG_VERSTEP 0x17 +/* These are the recognized values for the above regs */ +#define ADM1026_COMPANY_ANALOG_DEV 0x41 +#define ADM1026_VERSTEP_GENERIC 0x40 +#define ADM1026_VERSTEP_ADM1026 0x44 + +#define ADM1026_REG_MASK1 0x18 +#define ADM1026_REG_MASK2 0x19 +#define ADM1026_REG_MASK3 0x1a +#define ADM1026_REG_MASK4 0x1b + +#define ADM1026_REG_STATUS1 0x20 +#define ADM1026_REG_STATUS2 0x21 +#define ADM1026_REG_STATUS3 0x22 +#define ADM1026_REG_STATUS4 0x23 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + */ + +/* IN are scaled acording to built-in resistors. These are the + * voltages corresponding to 3/4 of full scale (192 or 0xc0) + * NOTE: The -12V input needs an additional factor to account + * for the Vref pullup resistor. + * NEG12_OFFSET = SCALE * Vref / V-192 - Vref + * = 13875 * 2.50 / 1.875 - 2500 + * = 16000 + */ +#if 1 +/* The values in this table are based on Table II, page 15 of the + * datasheet. + */ +static int adm1026_scaling[] = { /* .001 Volts */ + 2250, 2250, 2250, 2250, 2250, 2250, + 1875, 1875, 1875, 1875, 3000, 3330, + 3330, 4995, 2250, 12000, 13875 + }; +#define NEG12_OFFSET 16000 +#else +/* The values in this table are based on the resistors in + * Figure 5 on page 16. But the 3.3V inputs are not in + * the figure and the values for the 5V input are wrong. + * For 5V, I'm guessing that R2 at 55.2k is right, but + * the total resistance should be 1400 or 1449 like the + * other inputs. Using 1449, gives 4.922V at 192. + */ +static int adm1026_scaling[] = { /* .001 Volts */ + 2249, 2249, 2249, 2249, 2249, 2249, + 1875, 1875, 1875, 1875, 3329, 3329, + 3329, 4922, 2249, 11969, 13889 + }; +#define NEG12_OFFSET 16019 +#endif + +#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) +#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),0,255)) +#if 0 /* If we have extended A/D bits */ +#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,adm1026_scaling[n])) +#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) +#else +#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) +#endif + +/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses + * and we assume a 2 pulse-per-rev fan tach signal + * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 + */ +#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*(div)),1,254)) +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*(div))) +#define DIV_FROM_REG(val) (1<<(val)) +#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) + +/* Temperature is reported in 1 degC increments */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) +#define TEMP_FROM_REG(val) (val) +#define OFFSET_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) +#define OFFSET_FROM_REG(val) (val) + +#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_FROM_REG(val) (val) + +/* Analog output is a voltage, but it's used like a PWM + * Seems like this should be scaled, but to be consistent + * with other drivers, we do it this way. + */ +#define DAC_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define DAC_FROM_REG(val) (val) + +/* sensors_vid.h defines vid_from_reg() */ +#define VID_FROM_REG(val,vrm) (vid_from_reg(val,vrm)) + +#define ALARMS_FROM_REG(val) (val) + +/* Unlike some other drivers we DO NOT set initial limits. Use + * the config file to set limits. + */ + +/* Typically used with systems using a v9.1 VRM spec ? */ +#define ADM1026_INIT_VRM 91 +#define ADM1026_INIT_VID -1 + +/* Chip sampling rates + * + * Some sensors are not updated more frequently than once per second + * so it doesn't make sense to read them more often than that. + * We cache the results and return the saved data if the driver + * is called again before a second has elapsed. + * + * Also, there is significant configuration data for this chip + * So, we keep the config data up to date in the cache + * when it is written and only sample it once every 5 *minutes* + */ +#define ADM1026_DATA_INTERVAL (1 * HZ) +#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) + +/* We allow for multiple chips in a single system. + * + * For each registered ADM1026, we need to keep state information + * at client->data. The adm1026_data structure is dynamically + * allocated, when a new client structure is allocated. */ + +struct adm1026_data { + struct semaphore lock; + int sysctl_id; + enum chips type; + + struct semaphore update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ + + u8 in[17]; /* Register value */ + u8 in_max[17]; /* Register value */ + u8 in_min[17]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_tmin[3]; /* Register value */ + s8 temp_therm[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u8 fan[8]; /* Register value */ + u8 fan_min[8]; /* Register value */ + u8 fan_div[8]; /* Decoded value */ + u8 pwm; /* Register value */ + u8 analog_out; /* Register value */ + int vid; /* Decoded value */ + u8 vrm; /* VRM version */ + long alarms; /* Register encoding, combined */ + long alarm_mask; /* Register encoding, combined */ + long gpio; /* Register encoding, combined */ + long gpio_mask; /* Register encoding, combined */ + u8 gpio_config[17]; /* Decoded value */ + u8 config1; /* Register value */ + u8 config2; /* Register value */ + u8 config3; /* Register value */ +}; + +static int adm1026_attach_adapter(struct i2c_adapter *adapter); +static int adm1026_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static int adm1026_detach_client(struct i2c_client *client); + +static int adm1026_read_value(struct i2c_client *client, u8 register); +static int adm1026_write_value(struct i2c_client *client, u8 register, int value); +static void adm1026_print_gpio(struct i2c_client *client); +static void adm1026_fixup_gpio(struct i2c_client *client); +static void adm1026_update_client(struct i2c_client *client); +static void adm1026_init_client(struct i2c_client *client); + + +static void adm1026_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results); +static void adm1026_in16(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results); +static void adm1026_fan(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_fixup_fan_min(struct i2c_client *client, + int fan, int old_div); +static void adm1026_fan_div(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_temp_offset(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_temp_tmin(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_temp_therm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_vid(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_vrm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_alarm_mask(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_gpio(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_gpio_mask(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_pwm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_analog_out(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1026_afc(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +static struct i2c_driver adm1026_driver = { + .owner = THIS_MODULE, + .name = "ADM1026 compatible sensor driver", + .id = I2C_DRIVERID_ADM1026, + .flags = I2C_DF_NOTIFY, + .attach_adapter = &adm1026_attach_adapter, + .detach_client = &adm1026_detach_client, +}; + +/* Unique ID assigned to each ADM1026 detected */ +static int adm1026_id = 0; + +/* -- SENSORS SYSCTL START -- */ +#define ADM1026_SYSCTL_FAN0 1000 +#define ADM1026_SYSCTL_FAN1 1001 +#define ADM1026_SYSCTL_FAN2 1002 +#define ADM1026_SYSCTL_FAN3 1003 +#define ADM1026_SYSCTL_FAN4 1004 +#define ADM1026_SYSCTL_FAN5 1005 +#define ADM1026_SYSCTL_FAN6 1006 +#define ADM1026_SYSCTL_FAN7 1007 +#define ADM1026_SYSCTL_FAN_DIV 1008 +#define ADM1026_SYSCTL_GPIO 1009 +#define ADM1026_SYSCTL_GPIO_MASK 1010 +#define ADM1026_SYSCTL_ALARMS 1011 +#define ADM1026_SYSCTL_ALARM_MASK 1012 +#define ADM1026_SYSCTL_IN0 1013 +#define ADM1026_SYSCTL_IN1 1014 +#define ADM1026_SYSCTL_IN2 1015 +#define ADM1026_SYSCTL_IN3 1016 +#define ADM1026_SYSCTL_IN4 1017 +#define ADM1026_SYSCTL_IN5 1018 +#define ADM1026_SYSCTL_IN6 1019 +#define ADM1026_SYSCTL_IN7 1020 +#define ADM1026_SYSCTL_IN8 1021 +#define ADM1026_SYSCTL_IN9 1022 +#define ADM1026_SYSCTL_IN10 1023 +#define ADM1026_SYSCTL_IN11 1024 +#define ADM1026_SYSCTL_IN12 1025 +#define ADM1026_SYSCTL_IN13 1026 +#define ADM1026_SYSCTL_IN14 1027 +#define ADM1026_SYSCTL_IN15 1028 +#define ADM1026_SYSCTL_IN16 1029 +#define ADM1026_SYSCTL_PWM 1030 +#define ADM1026_SYSCTL_ANALOG_OUT 1031 +#define ADM1026_SYSCTL_AFC 1032 +#define ADM1026_SYSCTL_TEMP1 1033 +#define ADM1026_SYSCTL_TEMP2 1034 +#define ADM1026_SYSCTL_TEMP3 1035 +#define ADM1026_SYSCTL_TEMP_OFFSET1 1036 +#define ADM1026_SYSCTL_TEMP_OFFSET2 1037 +#define ADM1026_SYSCTL_TEMP_OFFSET3 1038 +#define ADM1026_SYSCTL_TEMP_THERM1 1039 +#define ADM1026_SYSCTL_TEMP_THERM2 1040 +#define ADM1026_SYSCTL_TEMP_THERM3 1041 +#define ADM1026_SYSCTL_TEMP_TMIN1 1042 +#define ADM1026_SYSCTL_TEMP_TMIN2 1043 +#define ADM1026_SYSCTL_TEMP_TMIN3 1044 +#define ADM1026_SYSCTL_VID 1045 +#define ADM1026_SYSCTL_VRM 1046 + +#define ADM1026_ALARM_TEMP2 (1L << 0) +#define ADM1026_ALARM_TEMP3 (1L << 1) +#define ADM1026_ALARM_IN9 (1L << 1) +#define ADM1026_ALARM_IN11 (1L << 2) +#define ADM1026_ALARM_IN12 (1L << 3) +#define ADM1026_ALARM_IN13 (1L << 4) +#define ADM1026_ALARM_IN14 (1L << 5) +#define ADM1026_ALARM_IN15 (1L << 6) +#define ADM1026_ALARM_IN16 (1L << 7) +#define ADM1026_ALARM_IN0 (1L << 8) +#define ADM1026_ALARM_IN1 (1L << 9) +#define ADM1026_ALARM_IN2 (1L << 10) +#define ADM1026_ALARM_IN3 (1L << 11) +#define ADM1026_ALARM_IN4 (1L << 12) +#define ADM1026_ALARM_IN5 (1L << 13) +#define ADM1026_ALARM_IN6 (1L << 14) +#define ADM1026_ALARM_IN7 (1L << 15) +#define ADM1026_ALARM_FAN0 (1L << 16) +#define ADM1026_ALARM_FAN1 (1L << 17) +#define ADM1026_ALARM_FAN2 (1L << 18) +#define ADM1026_ALARM_FAN3 (1L << 19) +#define ADM1026_ALARM_FAN4 (1L << 20) +#define ADM1026_ALARM_FAN5 (1L << 21) +#define ADM1026_ALARM_FAN6 (1L << 22) +#define ADM1026_ALARM_FAN7 (1L << 23) +#define ADM1026_ALARM_TEMP1 (1L << 24) +#define ADM1026_ALARM_IN10 (1L << 25) +#define ADM1026_ALARM_IN8 (1L << 26) +#define ADM1026_ALARM_THERM (1L << 27) +#define ADM1026_ALARM_AFC_FAN (1L << 28) +#define ADM1026_ALARM_UNUSED (1L << 29) +#define ADM1026_ALARM_CI (1L << 30) +/* -- SENSORS SYSCTL END -- */ + +/* The /proc/sys entries */ +/* These files are created for each detected ADM1026. This is just a template; + * The actual list is built from this and additional per-chip + * custom lists below. Note the XXX_LEN macros. These must be + * compile time constants because they will be used to allocate + * space for the final template passed to i2c_register_entry. + * We depend on the ability of GCC to evaluate expressions at + * compile time to turn these expressions into compile time + * constants, but this can generate a warning. + */ +static ctl_table adm1026_common[] = { + {ADM1026_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN11, "in11", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN12, "in12", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN13, "in13", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN14, "in14", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN15, "in15", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in}, + {ADM1026_SYSCTL_IN16, "in16", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_in16}, + + {ADM1026_SYSCTL_FAN0, "fan0", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN6, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN7, "fan7", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_fan}, + {ADM1026_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_fan_div}, + + {ADM1026_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_temp}, + {ADM1026_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_temp}, + {ADM1026_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_temp}, + {ADM1026_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, + {ADM1026_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, + {ADM1026_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, + {ADM1026_SYSCTL_TEMP_TMIN1, "temp1_tmin", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, + {ADM1026_SYSCTL_TEMP_TMIN2, "temp2_tmin", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, + {ADM1026_SYSCTL_TEMP_TMIN3, "temp3_tmin", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, + {ADM1026_SYSCTL_TEMP_THERM1, "temp1_therm", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, + {ADM1026_SYSCTL_TEMP_THERM2, "temp2_therm", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, + {ADM1026_SYSCTL_TEMP_THERM3, "temp3_therm", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, + + {ADM1026_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_vid}, + {ADM1026_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_vrm}, + + {ADM1026_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_alarms}, + {ADM1026_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_alarm_mask}, + + {ADM1026_SYSCTL_GPIO, "gpio", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_gpio}, + {ADM1026_SYSCTL_GPIO_MASK, "gpio_mask", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_gpio_mask}, + + {ADM1026_SYSCTL_PWM, "pwm", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_pwm}, + {ADM1026_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_analog_out}, + {ADM1026_SYSCTL_AFC, "afc", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1026_afc}, + + {0} +}; +#define CTLTBL_COMMON (sizeof(adm1026_common)/sizeof(adm1026_common[0])) + +#define MAX2(a,b) ((a)>(b)?(a):(b)) +#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c))) +#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d))) + +#define CTLTBL_MAX (CTLTBL_COMMON) + +/* This function is called when: + * the module is loaded + * a new adapter is loaded + */ +int adm1026_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, adm1026_detect); +} + +/* This function is called by i2c_detect */ +int adm1026_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i; + int company, verstep ; + struct i2c_client *new_client; + struct adm1026_data *data; + int err = 0; + const char *type_name = ""; + struct ctl_table template[CTLTBL_MAX] ; + struct ctl_table * template_next = template ; + + if (i2c_is_isa_adapter(adapter)) { + /* This chip has no ISA interface */ + goto ERROR0 ; + } + + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + /* We need to be able to do byte I/O */ + goto ERROR0 ; + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1026_{read,write}_value. */ + + if (!(new_client = kmalloc((sizeof(struct i2c_client)) + + sizeof(struct adm1026_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + data = (struct adm1026_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &adm1026_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); + verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); + +#ifdef DEBUG + printk("adm1026: Detecting device at %d,0x%02x with" + " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", + i2c_adapter_id(new_client->adapter), new_client->addr, + company, verstep + ); +#endif + + /* If auto-detecting, Determine the chip type. */ + if (kind <= 0) { +#ifdef DEBUG + printk("adm1026: Autodetecting device at %d,0x%02x ...\n", + i2c_adapter_id(adapter), address ); +#endif + if( company == ADM1026_COMPANY_ANALOG_DEV + && verstep == ADM1026_VERSTEP_ADM1026 ) { + kind = adm1026 ; + } else if( company == ADM1026_COMPANY_ANALOG_DEV + && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) { + printk("adm1026: Unrecgonized stepping 0x%02x" + " Defaulting to ADM1026.\n", verstep ); + kind = adm1026 ; + } else if( (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) { + printk("adm1026: Found version/stepping 0x%02x" + " Assuming generic ADM1026.\n", verstep ); + kind = any_chip ; + } else { +#ifdef DEBUG + printk("adm1026: Autodetection failed\n"); +#endif + /* Not an ADM1026 ... */ + if( kind == 0 ) { /* User used force=x,y */ + printk("adm1026: Generic ADM1026 Version 6 not" + " found at %d,0x%02x. Try force_adm1026.\n", + i2c_adapter_id(adapter), address ); + } + err = 0 ; + goto ERROR1; + } + } + + /* Fill in the chip specific driver values */ + switch (kind) { + case any_chip : + type_name = "adm1026"; + strcpy(new_client->name, "Generic ADM1026"); + template_next = template ; /* None used */ + break ; + case adm1026 : + type_name = "adm1026"; + strcpy(new_client->name, "Analog Devices ADM1026"); + template_next = template ; + break ; +#if 0 + /* Example of another adm1026 "compatible" device */ + case adx1000 : + type_name = "adx1000"; + strcpy(new_client->name, "Compatible ADX1000"); + memcpy( template, adx_specific, sizeof(adx_specific) ); + template_next = template + CTLTBL_ADX1000 ; + break ; +#endif + default : + printk("adm1026: Internal error, invalid kind (%d)!", kind); + err = -EFAULT ; + goto ERROR1; + } + + /* Fill in the remaining client fields */ + new_client->id = adm1026_id++; + printk("adm1026(%d): Assigning ID %d to %s at %d,0x%02x\n", + new_client->id, new_client->id, new_client->name, + i2c_adapter_id(new_client->adapter), + new_client->addr + ); + + /* Housekeeping values */ + data->type = kind; + data->valid = 0; + + /* Set the VRM version */ + data->vrm = ADM1026_INIT_VRM ; + data->vid = ADM1026_INIT_VID ; + + init_MUTEX(&data->update_lock); + + /* Initialize the ADM1026 chip */ + adm1026_init_client(new_client); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR1; + + /* Finish out the template */ + memcpy(template_next, adm1026_common, sizeof(adm1026_common)); + + /* Register a new directory entry with module sensors */ + if ((i = i2c_register_entry(new_client, + type_name, + template)) < 0) { + err = i; + goto ERROR2; + } + data->sysctl_id = i; + + return 0; + + /* Error out and cleanup code */ + ERROR2: + i2c_detach_client(new_client); + ERROR1: + kfree(new_client); + ERROR0: + return err; +} + +int adm1026_detach_client(struct i2c_client *client) +{ + int err; + int id ; + + id = client->id; + i2c_deregister_entry(((struct adm1026_data *)(client->data))->sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk("adm1026(%d): Client deregistration failed," + " client not detached.\n", id ); + return err; + } + + kfree(client); + + return 0; +} + +int adm1026_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + if( reg < 0x80 ) { + /* "RAM" locations */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff ; + } else { + /* EEPROM, do nothing */ + res = 0 ; + } + + return res ; +} + +int adm1026_write_value(struct i2c_client *client, u8 reg, int value) +{ + int res ; + + if( reg < 0x80 ) { + /* "RAM" locations */ + res = i2c_smbus_write_byte_data(client, reg, value); + } else { + /* EEPROM, do nothing */ + res = 0 ; + } + + return res ; +} + +/* Called when we have found a new ADM1026. */ +void adm1026_init_client(struct i2c_client *client) +{ + int value ; + int i; + struct adm1026_data *data = client->data; + +#ifdef DEBUG + printk("adm1026(%d): Initializing device\n", client->id); +#endif + + /* Read chip config */ + data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); + data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); + data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); + + /* Inform user of chip config */ +#ifdef DEBUG + printk("adm1026(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n", + client->id, data->config1 ); +#endif + if( (data->config1 & CFG1_MONITOR) == 0 ) { + printk("adm1026(%d): Monitoring not currently enabled.\n", + client->id ); + } + if( data->config1 & CFG1_INT_ENABLE ) { + printk("adm1026(%d): SMBALERT interrupts are enabled.\n", + client->id ); + } + if( data->config1 & CFG1_AIN8_9 ) { + printk("adm1026(%d): in8 and in9 enabled. temp3 disabled.\n", + client->id ); + } else { + printk("adm1026(%d): temp3 enabled. in8 and in9 disabled.\n", + client->id ); + } + if( data->config1 & CFG1_THERM_HOT ) { + printk("adm1026(%d): Automatic THERM, PWM, and temp limits enabled.\n", + client->id ); + } + + value = data->config3 ; + if( data->config3 & CFG3_GPIO16_ENABLE ) { + printk("adm1026(%d): GPIO16 enabled. THERM pin disabled.\n", + client->id ); + } else { + printk("adm1026(%d): THERM pin enabled. GPIO16 disabled.\n", + client->id ); + } + if( data->config3 & CFG3_VREF_250 ) { + printk("adm1026(%d): Vref is 2.50 Volts.\n", client->id ); + } else { + printk("adm1026(%d): Vref is 1.82 Volts.\n", client->id ); + } + + /* Read and pick apart the existing GPIO configuration */ + value = 0 ; + for( i = 0 ; i <= 15 ; ++i ) { + if( (i & 0x03) == 0 ) { + value = adm1026_read_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4 ); + } + data->gpio_config[i] = value & 0x03 ; + value >>= 2 ; + } + data->gpio_config[16] = (data->config3 >> 6) & 0x03 ; + + /* ... and then print it */ + adm1026_print_gpio(client); + + /* If the user asks us to reprogram the GPIO config, then + * do it now. But only if this is the first ADM1026. + */ + if( client->id == 0 + && (gpio_input[0] != -1 || gpio_output[0] != -1 + || gpio_inverted[0] != -1 || gpio_normal[0] != -1 + || gpio_fan[0] != -1 ) ) { + adm1026_fixup_gpio(client); + } + + /* WE INTENTIONALLY make no changes to the limits, + * offsets, pwms and fans. If they were + * configured, we don't want to mess with them. + * If they weren't, the default is generally safe + * and will suffice until 'sensors -s' can be run. + */ + + /* Start monitoring */ + value = adm1026_read_value(client, ADM1026_REG_CONFIG1); + + /* Set MONITOR, clear interrupt acknowledge and s/w reset */ + value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET) ; +#ifdef DEBUG + printk("adm1026(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); +#endif + data->config1 = value ; + adm1026_write_value(client, ADM1026_REG_CONFIG1, value); + +} + +void adm1026_print_gpio(struct i2c_client *client) +{ + struct adm1026_data *data = client->data; + int i ; + + printk("adm1026(%d): GPIO config is:\nadm1026(%d):", + client->id, client->id ); + for( i = 0 ; i <= 7 ; ++i ) { + if( data->config2 & (1 << i) ) { + printk( " %sGP%s%d", + data->gpio_config[i] & 0x02 ? "" : "!", + data->gpio_config[i] & 0x01 ? "OUT" : "IN", + i ); + } else { + printk( " FAN%d", i ); + } + } + printk( "\nadm1026(%d):", client->id ); + for( i = 8 ; i <= 15 ; ++i ) { + printk( " %sGP%s%d", + data->gpio_config[i] & 0x02 ? "" : "!", + data->gpio_config[i] & 0x01 ? "OUT" : "IN", + i ); + } + if( data->config3 & CFG3_GPIO16_ENABLE ) { + printk( " %sGP%s16\n", + data->gpio_config[16] & 0x02 ? "" : "!", + data->gpio_config[16] & 0x01 ? "OUT" : "IN" ); + } else { + /* GPIO16 is THERM */ + printk( " THERM\n" ); + } +} + +void adm1026_fixup_gpio(struct i2c_client *client) +{ + struct adm1026_data *data = client->data; + int i ; + int value ; + + /* Make the changes requested. */ + /* We may need to unlock/stop monitoring or soft-reset the + * chip before we can make changes. This hasn't been + * tested much. FIXME + */ + + /* Make outputs */ + for( i = 0 ; i <= 16 ; ++i ) { + if( gpio_output[i] >= 0 && gpio_output[i] <= 16 ) { + data->gpio_config[gpio_output[i]] |= 0x01 ; + } + /* if GPIO0-7 is output, it isn't a FAN tach */ + if( gpio_output[i] >= 0 && gpio_output[i] <= 7 ) { + data->config2 |= 1 << gpio_output[i] ; + } + } + + /* Input overrides output */ + for( i = 0 ; i <= 16 ; ++i ) { + if( gpio_input[i] >= 0 && gpio_input[i] <= 16 ) { + data->gpio_config[gpio_input[i]] &= ~ 0x01 ; + } + /* if GPIO0-7 is input, it isn't a FAN tach */ + if( gpio_input[i] >= 0 && gpio_input[i] <= 7 ) { + data->config2 |= 1 << gpio_input[i] ; + } + } + + /* Inverted */ + for( i = 0 ; i <= 16 ; ++i ) { + if( gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16 ) { + data->gpio_config[gpio_inverted[i]] &= ~ 0x02 ; + } + } + + /* Normal overrides inverted */ + for( i = 0 ; i <= 16 ; ++i ) { + if( gpio_normal[i] >= 0 && gpio_normal[i] <= 16 ) { + data->gpio_config[gpio_normal[i]] |= 0x02 ; + } + } + + /* Fan overrides input and output */ + for( i = 0 ; i <= 7 ; ++i ) { + if( gpio_fan[i] >= 0 && gpio_fan[i] <= 7 ) { + data->config2 &= ~( 1 << gpio_fan[i] ); + } + } + + /* Write new configs to registers */ + adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); + data->config3 = (data->config3 & 0x3f) + | ((data->gpio_config[16] & 0x03) << 6) ; + adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); + for( i = 15, value = 0 ; i >= 0 ; --i ) { + value <<= 2 ; + value |= data->gpio_config[i] & 0x03 ; + if( (i & 0x03) == 0 ) { + adm1026_write_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4, + value ); + value = 0 ; + } + } + + /* Print the new config */ + adm1026_print_gpio(client); +} + +void adm1026_update_client(struct i2c_client *client) +{ + struct adm1026_data *data = client->data; + int i; + long value, alarms, gpio ; + + down(&data->update_lock); + + if (!data->valid + || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL )) { + /* Things that change quickly */ + +#ifdef DEBUG + printk("adm1026(%d): Reading sensor values\n", client->id); +#endif + for (i = 0 ; i <= 16 ; ++i) { + data->in[i] = + adm1026_read_value(client, ADM1026_REG_IN(i)); + } + + for (i = 0 ; i <= 7 ; ++i) { + data->fan[i] = + adm1026_read_value(client, ADM1026_REG_FAN(i)); + } + + for (i = 0 ; i <= 2 ; ++i) { + /* NOTE: temp[] is s8 and we assume 2's complement + * "conversion" in the assignment */ + data->temp[i] = + adm1026_read_value(client, ADM1026_REG_TEMP(i)); + } + + data->pwm = adm1026_read_value(client, ADM1026_REG_PWM); + data->analog_out = adm1026_read_value(client, ADM1026_REG_DAC); + + /* GPIO16 is MSbit of alarms, move it to gpio */ + alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); + gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */ + alarms &= 0x7f ; + alarms <<= 8 ; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); + alarms <<= 8 ; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); + alarms <<= 8 ; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); + data->alarms = alarms ; + + /* Read the GPIO values */ + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_8_15); + gpio <<= 8 ; + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_0_7); + data->gpio = gpio ; + + data->last_reading = jiffies ; + }; /* last_reading */ + + if (!data->valid + || (jiffies - data->last_config > ADM1026_CONFIG_INTERVAL) ) { + /* Things that don't change often */ + +#ifdef DEBUG + printk("adm1026(%d): Reading config values\n", client->id); +#endif + for (i = 0 ; i <= 16 ; ++i) { + data->in_min[i] = + adm1026_read_value(client, ADM1026_REG_IN_MIN(i)); + data->in_max[i] = + adm1026_read_value(client, ADM1026_REG_IN_MAX(i)); + } + + value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) + | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); + for (i = 0 ; i <= 7 ; ++i) { + data->fan_min[i] = + adm1026_read_value(client, ADM1026_REG_FAN_MIN(i)); + data->fan_div[i] = DIV_FROM_REG(value & 0x03); + value >>= 2 ; + } + + for (i = 0; i <= 2; ++i) { + /* NOTE: temp_xxx[] are s8 and we assume 2's complement + * "conversion" in the assignment */ + data->temp_min[i] = + adm1026_read_value(client, ADM1026_REG_TEMP_MIN(i)); + data->temp_max[i] = + adm1026_read_value(client, ADM1026_REG_TEMP_MAX(i)); + data->temp_tmin[i] = + adm1026_read_value(client, ADM1026_REG_TEMP_TMIN(i)); + data->temp_therm[i] = + adm1026_read_value(client, ADM1026_REG_TEMP_THERM(i)); + data->temp_offset[i] = + adm1026_read_value(client, ADM1026_REG_TEMP_OFFSET(i)); + } + + /* Read the STATUS/alarm masks */ + alarms = adm1026_read_value(client, ADM1026_REG_MASK4); + gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */ + alarms = (alarms & 0x7f) << 8 ; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); + alarms <<= 8 ; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); + alarms <<= 8 ; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); + data->alarm_mask = alarms ; + + /* Read the GPIO values */ + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_8_15); + gpio <<= 8 ; + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); + data->gpio_mask = gpio ; + + /* Read the GPIO config */ + data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); + data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); + data->gpio_config[16] = (data->config3 >> 6) & 0x03 ; + + value = 0 ; + for( i = 0 ; i <= 15 ; ++i ) { + if( (i & 0x03) == 0 ) { + value = adm1026_read_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4 ); + } + data->gpio_config[i] = value & 0x03 ; + value >>= 2 ; + } + + data->last_config = jiffies; + }; /* last_config */ + + /* We don't know where or even _if_ the VID might be on the GPIO + * pins. But the datasheet gives an example config showing + * GPIO11-15 being used to monitor VID0-4, so we go with that + * but make the vid WRITEABLE so if it's wrong, the user can + * set it in /etc/sensors.conf perhaps using an expression or + * 0 to trigger a re-read from the GPIO pins. + */ + if( data->vid == ADM1026_INIT_VID ) { + /* Hasn't been set yet, make a bold assumption */ + printk("adm1026(%d): Setting VID from GPIO11-15.\n", + client->id ); + data->vid = (data->gpio >> 11) & 0x1f ; + } + + data->valid = 1; + + up(&data->update_lock); +} + + +/* The following functions are the call-back functions of the /proc/sys and + sysctl files. The appropriate function is referenced in the ctl_table + extra1 field. + + Each function must return the magnitude (power of 10 to divide the + data with) if it is called with operation set to SENSORS_PROC_REAL_INFO. + It must put a maximum of *nrels elements in results reflecting the + data of this file, and set *nrels to the number it actually put in + it, if operation is SENSORS_PROC_REAL_READ. Finally, it must get + up to *nrels elements from results and write them to the chip, if + operations is SENSORS_PROC_REAL_WRITE. + */ +void adm1026_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_IN0; + + /* We handle in0 - in15 here. in16 (-12V) is handled below */ + if (nr < 0 || nr > 15) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; /* 1.000 */ + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = INS_FROM_REG(nr,data->in_min[nr]); + results[1] = INS_FROM_REG(nr,data->in_max[nr]); + results[2] = INS_FROM_REG(nr,data->in[nr]); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->in_max[nr] = INS_TO_REG(nr,results[1]); + adm1026_write_value(client, ADM1026_REG_IN_MAX(nr), + data->in_max[nr]); + } + if (*nrels_mag > 0) { + data->in_min[nr] = INS_TO_REG(nr,results[0]); + adm1026_write_value(client, ADM1026_REG_IN_MIN(nr), + data->in_min[nr]); + } + up(&data->update_lock); + } +} + +void adm1026_in16(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_IN0; + + /* We handle in16 (-12V) here */ + if (nr != 16) + return ; /* ERROR */ + + /* Apply offset and swap min/max so that min is 90% of + * target and max is 110% of target. + */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; /* 1.000 */ + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = INS_FROM_REG(nr,data->in_max[nr])-NEG12_OFFSET ; + results[1] = INS_FROM_REG(nr,data->in_min[nr])-NEG12_OFFSET ; + results[2] = INS_FROM_REG(nr,data->in[nr])-NEG12_OFFSET ; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->in_min[nr] = INS_TO_REG(nr,results[1]+NEG12_OFFSET); + adm1026_write_value(client, ADM1026_REG_IN_MIN(nr), + data->in_min[nr]); + } + if (*nrels_mag > 0) { + data->in_max[nr] = INS_TO_REG(nr,results[0]+NEG12_OFFSET); + adm1026_write_value(client, ADM1026_REG_IN_MAX(nr), + data->in_max[nr]); + } + up(&data->update_lock); + } +} + +void adm1026_fan(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_FAN0 ; + + if (nr < 0 || nr > 7) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = FAN_FROM_REG(data->fan_min[nr], data->fan_div[nr]); + results[1] = FAN_FROM_REG(data->fan[nr], data->fan_div[nr]); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->fan_min[nr] = FAN_TO_REG(results[0], + data->fan_div[nr]); + adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), + data->fan_min[nr]); + } + up(&data->update_lock); + } +} + +/* Adjust fan_min to account for new fan divisor */ +void adm1026_fixup_fan_min(struct i2c_client *client, int fan, int old_div) +{ + struct adm1026_data *data = client->data; + int new_div = data->fan_div[fan] ; + int new_min; + + /* 0 and 0xff are special. Don't adjust them */ + if( data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff ) { + return ; + } + + new_min = data->fan_min[fan] * old_div / new_div ; + new_min = SENSORS_LIMIT(new_min, 1, 254); + data->fan_min[fan] = new_min ; + adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); +} + +void adm1026_fan_div(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int i ; + int value, div, old ; + + if (ctl_name != ADM1026_SYSCTL_FAN_DIV) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + for( i = 0 ; i <= 7 ; ++i ) { + results[i] = data->fan_div[i] ; + } + *nrels_mag = 8; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + value = 0 ; + for( i = 7 ; i >= 0 ; --i ) { + value <<= 2 ; + if (*nrels_mag > i) { + old = data->fan_div[i] ; + div = DIV_TO_REG(results[i]) ; + data->fan_div[i] = DIV_FROM_REG(div) ; + if( data->fan_div[i] != old ) { + adm1026_fixup_fan_min(client,i,old); + } + } else { + div = DIV_TO_REG(data->fan_div[i]) ; + } + value |= div ; + } + adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, + value & 0xff); + adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, + (value >> 8) & 0xff); + up(&data->update_lock); + } +} + +void adm1026_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_TEMP1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_min[nr]); + results[1] = TEMP_FROM_REG(data->temp_max[nr]); + results[2] = TEMP_FROM_REG(data->temp[nr]); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->temp_max[nr] = TEMP_TO_REG(results[1]); + adm1026_write_value(client, ADM1026_REG_TEMP_MAX(nr), + data->temp_max[nr]); + } + if (*nrels_mag > 0) { + data->temp_min[nr] = TEMP_TO_REG(results[0]); + adm1026_write_value(client, ADM1026_REG_TEMP_MIN(nr), + data->temp_min[nr]); + } + up(&data->update_lock); + } +} + +void adm1026_temp_offset(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_TEMP_OFFSET1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_offset[nr]); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->temp_offset[nr] = TEMP_TO_REG(results[0]); + adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET(nr), + data->temp_offset[nr]); + } + up(&data->update_lock); + } +} + +void adm1026_temp_tmin(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_TEMP_TMIN1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_tmin[nr]); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->temp_tmin[nr] = TEMP_TO_REG(results[0]); + adm1026_write_value(client, ADM1026_REG_TEMP_TMIN(nr), + data->temp_tmin[nr]); + } + up(&data->update_lock); + } +} + +void adm1026_temp_therm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + int nr = ctl_name - ADM1026_SYSCTL_TEMP_THERM1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_therm[nr]); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->temp_therm[nr] = TEMP_TO_REG(results[0]); + adm1026_write_value(client, ADM1026_REG_TEMP_THERM(nr), + data->temp_therm[nr]); + } + up(&data->update_lock); + } +} + +void adm1026_pwm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + + if (ctl_name != ADM1026_SYSCTL_PWM) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = PWM_FROM_REG(data->pwm); + results[1] = 1 ; /* Always enabled */ + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + /* PWM enable is read-only */ + if (*nrels_mag > 0) { + data->pwm = PWM_TO_REG(results[0]); + adm1026_write_value(client, ADM1026_REG_PWM, + data->pwm); + } + up(&data->update_lock); + } +} + +void adm1026_analog_out(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + + if (ctl_name != ADM1026_SYSCTL_ANALOG_OUT) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; /* 0 - 255 */ + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = DAC_FROM_REG(data->analog_out); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->analog_out = DAC_TO_REG(results[0]); + adm1026_write_value(client, ADM1026_REG_DAC, + data->analog_out); + } + up(&data->update_lock); + } +} + +void adm1026_afc(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + + if (ctl_name != ADM1026_SYSCTL_AFC) + return ; /* ERROR */ + + /* PWM auto fan control, DAC auto fan control */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = (data->config1 & CFG1_PWM_AFC) != 0 ; + results[1] = (data->config1 & CFG1_DAC_AFC) != 0 ; + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->config1 = (data->config1 & ~CFG1_DAC_AFC) + | (results[1] ? CFG1_DAC_AFC : 0) ; + } + if (*nrels_mag > 0) { + data->config1 = (data->config1 & ~CFG1_PWM_AFC) + | (results[0] ? CFG1_PWM_AFC : 0) ; + adm1026_write_value(client, ADM1026_REG_CONFIG1, + data->config1); + } + up(&data->update_lock); + } +} + +void adm1026_vid(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + + if( ctl_name != ADM1026_SYSCTL_VID ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = VID_FROM_REG((data->vid)&0x3f,data->vrm); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + /* Hmmm... There isn't a VID_TO_REG mapping */ + if (*nrels_mag > 0) { + if( results[0] >= 0 ) { + data->vid = results[0] & 0x3f ; + } else { + data->vid = ADM1026_INIT_VID ; + } + } + up(&data->update_lock); + } + +} + +void adm1026_vrm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + + if( ctl_name != ADM1026_SYSCTL_VRM ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + results[0] = data->vrm ; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag > 0) { + data->vrm = results[0] ; + } + } +} + +void adm1026_alarms(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + + if( ctl_name != ADM1026_SYSCTL_ALARMS ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = data->alarms ; + *nrels_mag = 1; + } + /* FIXME: Perhaps we should implement a write function + * to clear an alarm? + */ +} + +void adm1026_alarm_mask(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + unsigned long mask ; + + if( ctl_name != ADM1026_SYSCTL_ALARM_MASK ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = data->alarm_mask ; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->alarm_mask = results[0] & 0x7fffffff ; + mask = data->alarm_mask + | (data->gpio_mask & 0x10000 ? 0x80000000 : 0) ; + adm1026_write_value(client, ADM1026_REG_MASK1, + mask & 0xff); + mask >>= 8 ; + adm1026_write_value(client, ADM1026_REG_MASK2, + mask & 0xff); + mask >>= 8 ; + adm1026_write_value(client, ADM1026_REG_MASK3, + mask & 0xff); + mask >>= 8 ; + adm1026_write_value(client, ADM1026_REG_MASK4, + mask & 0xff); + } + up(&data->update_lock); + } +} + +void adm1026_gpio(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + long gpio ; + + if( ctl_name != ADM1026_SYSCTL_GPIO ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = data->gpio ; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->gpio = results[0] & 0x1ffff ; + gpio = data->gpio ; + adm1026_write_value(client, + ADM1026_REG_GPIO_STATUS_0_7, + gpio & 0xff ); + gpio >>= 8 ; + adm1026_write_value(client, + ADM1026_REG_GPIO_STATUS_8_15, + gpio & 0xff ); + gpio = ((gpio >> 1) & 0x80) + | (data->alarms >> 24 & 0x7f); + adm1026_write_value(client, + ADM1026_REG_STATUS4, + gpio & 0xff ); + } + up(&data->update_lock); + } +} + +void adm1026_gpio_mask(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct adm1026_data *data = client->data; + long mask ; + + if( ctl_name != ADM1026_SYSCTL_GPIO_MASK ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1026_update_client(client); + results[0] = data->gpio_mask ; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->gpio_mask = results[0] & 0x1ffff ; + mask = data->gpio_mask ; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7, + mask & 0xff); + mask >>= 8 ; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15, + mask & 0xff); + mask = ((mask >> 1) & 0x80) + | (data->alarm_mask >> 24 & 0x7f); + adm1026_write_value(client, ADM1026_REG_MASK1, + mask & 0xff); + } + up(&data->update_lock); + } +} + +static int __init sm_adm1026_init(void) +{ + printk("adm1026: Version %s (%s)\n", LM_VERSION, LM_DATE); + printk("adm1026: See http://www.penguincomputing.com/lm_sensors for more info.\n" ); + return i2c_add_driver(&adm1026_driver); +} + +static void __exit sm_adm1026_exit(void) +{ + i2c_del_driver(&adm1026_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Pokorny #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -149,7 +136,7 @@ SENSORS_INSMOD_3(adm9240, ds1780, lm81); #define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255)) #define IN_FROM_REG(val,nr) (val) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -222,11 +209,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define ADM9240_INIT_TEMP_HOT_MAX 700 #define ADM9240_INIT_TEMP_HOT_HYST 600 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered ADM9240, we need to keep some data in memory. That data is pointed to by adm9240_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new adm9240 client is @@ -254,22 +236,10 @@ struct adm9240_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_adm9240_init(void); -static int __init adm9240_cleanup(void); - static int adm9240_attach_adapter(struct i2c_adapter *adapter); static int adm9240_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int adm9240_detach_client(struct i2c_client *client); -static int adm9240_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void adm9240_inc_use(struct i2c_client *client); -static void adm9240_dec_use(struct i2c_client *client); static int adm9240_read_value(struct i2c_client *client, u8 register); static int adm9240_write_value(struct i2c_client *client, u8 register, @@ -300,20 +270,45 @@ static void adm9240_vid(struct i2c_clien static int adm9240_id = 0; static struct i2c_driver adm9240_driver = { - /* name */ "ADM9240 sensor driver", - /* id */ I2C_DRIVERID_ADM9240, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &adm9240_attach_adapter, - /* detach_client */ &adm9240_detach_client, - /* command */ &adm9240_command, - /* inc_use */ &adm9240_inc_use, - /* dec_use */ &adm9240_dec_use + .owner = THIS_MODULE, + .name = "ADM9240 sensor driver", + .id = I2C_DRIVERID_ADM9240, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm9240_attach_adapter, + .detach_client = adm9240_detach_client, }; -/* Used by adm9240_init/cleanup */ -static int __initdata adm9240_initialized = 0; - /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ + +#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM9240_SYSCTL_IN1 1001 +#define ADM9240_SYSCTL_IN2 1002 +#define ADM9240_SYSCTL_IN3 1003 +#define ADM9240_SYSCTL_IN4 1004 +#define ADM9240_SYSCTL_IN5 1005 +#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM9240_SYSCTL_FAN2 1102 +#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM9240_SYSCTL_ANALOG_OUT 2002 +#define ADM9240_SYSCTL_VID 2003 + +#define ADM9240_ALARM_IN0 0x0001 +#define ADM9240_ALARM_IN1 0x0002 +#define ADM9240_ALARM_IN2 0x0004 +#define ADM9240_ALARM_IN3 0x0008 +#define ADM9240_ALARM_IN4 0x0100 +#define ADM9240_ALARM_IN5 0x0200 +#define ADM9240_ALARM_FAN1 0x0040 +#define ADM9240_ALARM_FAN2 0x0080 +#define ADM9240_ALARM_TEMP 0x0010 +#define ADM9240_ALARM_CHAS 0x1000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected ADM9240. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -349,7 +344,7 @@ static ctl_table adm9240_dir_table_templ {0} }; -int adm9240_attach_adapter(struct i2c_adapter *adapter) +static int adm9240_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, adm9240_detect); } @@ -458,8 +453,7 @@ static int adm9240_detect(struct i2c_ada /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - adm9240_dir_table_template, - THIS_MODULE)) < 0) { + adm9240_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -481,7 +475,7 @@ static int adm9240_detect(struct i2c_ada return err; } -int adm9240_detach_client(struct i2c_client *client) +static int adm9240_detach_client(struct i2c_client *client) { int err; @@ -500,38 +494,19 @@ int adm9240_detach_client(struct i2c_cli } -/* No commands defined yet */ -int adm9240_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void adm9240_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void adm9240_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} -int adm9240_read_value(struct i2c_client *client, u8 reg) +static int adm9240_read_value(struct i2c_client *client, u8 reg) { return 0xFF & i2c_smbus_read_byte_data(client, reg); } -int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) +static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* Called when we have found a new ADM9240. It should set limits, etc. */ -void adm9240_init_client(struct i2c_client *client) +static void adm9240_init_client(struct i2c_client *client) { /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others. This makes most other @@ -576,17 +551,17 @@ void adm9240_init_client(struct i2c_clie adm9240_write_value(client, ADM9240_REG_CONFIG, 0x01); } -void adm9240_update_client(struct i2c_client *client) +static void adm9240_update_client(struct i2c_client *client) { struct adm9240_data *data = client->data; - int timeout = data->type == adm9240 ? HZ / 2 : HZ * 2; u8 i; down(&data->update_lock); if ( - time_after(jiffies, data->last_updated + timeout) - || !data->valid) { + (jiffies - data->last_updated > + (data->type == adm9240 ? HZ / 2 : HZ * 2)) + || (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting adm9240 update\n"); @@ -825,54 +800,22 @@ void adm9240_vid(struct i2c_client *clie } } -int __init sensors_adm9240_init(void) +static int __init sm_adm9240_init(void) { - int res; - printk("adm9240.o version %s (%s)\n", LM_VERSION, LM_DATE); - adm9240_initialized = 0; - - if ((res = i2c_add_driver(&adm9240_driver))) { - printk - ("adm9240.o: Driver registration failed, module not inserted.\n"); - adm9240_cleanup(); - return res; - } - adm9240_initialized++; - return 0; + return i2c_add_driver(&adm9240_driver); } -int __init adm9240_cleanup(void) +static void __exit sm_adm9240_exit(void) { - int res; - - if (adm9240_initialized >= 1) { - if ((res = i2c_del_driver(&adm9240_driver))) { - printk - ("adm9240.o: Driver deregistration failed, module not removed.\n"); - return res; - } - adm9240_initialized--; - } - return 0; + i2c_del_driver(&adm9240_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("ADM9240 driver"); -int init_module(void) -{ - return sensors_adm9240_init(); -} - -int cleanup_module(void) -{ - return adm9240_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_adm9240_init); +module_exit(sm_adm9240_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/bt869.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/bt869.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/bt869.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/bt869.c 2003-08-17 21:26:58.000000000 +0200 @@ -23,28 +23,15 @@ #define DEBUG 1 -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif - /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -89,27 +76,11 @@ struct bt869_data { u8 svideo; /* output format: (2=RGB) 1=SVIDEO, 0=Composite */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_bt869_init(void); -static int __init bt869_cleanup(void); static int bt869_attach_adapter(struct i2c_adapter *adapter); static int bt869_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void bt869_init_client(struct i2c_client *client); static int bt869_detach_client(struct i2c_client *client); -static int bt869_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void bt869_inc_use(struct i2c_client *client); -static void bt869_dec_use(struct i2c_client *client); static int bt869_read_value(struct i2c_client *client, u8 reg); static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value); static void bt869_write_values(struct i2c_client *client, u16 *values); @@ -132,16 +103,25 @@ static void bt869_update_client(struct i /* This is the driver that will be inserted */ static struct i2c_driver bt869_driver = { - /* name */ "BT869 video-output chip driver", - /* id */ I2C_DRIVERID_BT869, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &bt869_attach_adapter, - /* detach_client */ &bt869_detach_client, - /* command */ &bt869_command, - /* inc_use */ &bt869_inc_use, - /* dec_use */ &bt869_dec_use + .owner = THIS_MODULE, + .name = "BT869 video-output chip driver", + .id = I2C_DRIVERID_BT869, + .flags = I2C_DF_NOTIFY, + .attach_adapter = bt869_attach_adapter, + .detach_client = bt869_detach_client, }; +/* -- SENSORS SYSCTL START -- */ +#define BT869_SYSCTL_STATUS 1000 +#define BT869_SYSCTL_NTSC 1001 +#define BT869_SYSCTL_HALF 1002 +#define BT869_SYSCTL_RES 1003 +#define BT869_SYSCTL_COLORBARS 1004 +#define BT869_SYSCTL_DEPTH 1005 +#define BT869_SYSCTL_SVIDEO 1006 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected bt869. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -488,12 +468,9 @@ static u16 registers_720_480[] = }; -/* Used by init/cleanup */ -static int __initdata bt869_initialized = 0; - int bt869_id = 0; -int bt869_attach_adapter(struct i2c_adapter *adapter) +static int bt869_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, bt869_detect); } @@ -575,8 +552,7 @@ int bt869_detect(struct i2c_adapter *ada /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - bt869_dir_table_template, - THIS_MODULE)) < 0) { + bt869_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -597,7 +573,7 @@ int bt869_detect(struct i2c_adapter *ada return err; } -int bt869_detach_client(struct i2c_client *client) +static int bt869_detach_client(struct i2c_client *client) { int err; @@ -616,32 +592,10 @@ int bt869_detach_client(struct i2c_clien } -/* No commands defined yet */ -int bt869_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void bt869_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void bt869_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* All registers are byte-sized. bt869 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int bt869_read_value(struct i2c_client *client, u8 reg) +static int bt869_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte(client); } @@ -649,7 +603,7 @@ int bt869_read_value(struct i2c_client * /* All registers are byte-sized. bt869 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int bt869_write_value(struct i2c_client *client, u8 reg, u16 value) +static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value) { #ifdef DEBUG printk("bt869.o: write_value(0x%X, 0x%X)\n", reg, value); @@ -657,7 +611,7 @@ int bt869_write_value(struct i2c_client return i2c_smbus_write_byte_data(client, reg, value); } -void bt869_write_values(struct i2c_client *client, u16 *values) +static void bt869_write_values(struct i2c_client *client, u16 *values) { /* writes set of registers from array. 0,0 marks end of table */ while (*values) { @@ -666,7 +620,7 @@ void bt869_write_values(struct i2c_clien } } -void bt869_init_client(struct i2c_client *client) +static void bt869_init_client(struct i2c_client *client) { struct bt869_data *data = client->data; @@ -691,14 +645,14 @@ void bt869_init_client(struct i2c_client } -void bt869_update_client(struct i2c_client *client) +static void bt869_update_client(struct i2c_client *client) { struct bt869_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting bt869 update\n"); #endif @@ -918,54 +872,22 @@ void bt869_depth(struct i2c_client *clie } } -int __init sensors_bt869_init(void) +static int __init sm_bt869_init(void) { - int res; - printk("bt869.o version %s (%s)\n", LM_VERSION, LM_DATE); - bt869_initialized = 0; - if ((res = i2c_add_driver(&bt869_driver))) { - printk - ("bt869.o: Driver registration failed, module not inserted.\n"); - bt869_cleanup(); - return res; - } - bt869_initialized++; - return 0; + return i2c_add_driver(&bt869_driver); } -int __init bt869_cleanup(void) +static void __exit sm_bt869_exit(void) { - int res; - - if (bt869_initialized >= 1) { - if ((res = i2c_del_driver(&bt869_driver))) { - printk - ("bt869.o: Driver deregistration failed, module not removed.\n"); - return res; - } - bt869_initialized--; - } - - return 0; + i2c_del_driver(&bt869_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , Stephen Davies "); MODULE_DESCRIPTION("bt869 driver"); -int init_module(void) -{ - return sensors_bt869_init(); -} - -int cleanup_module(void) -{ - return bt869_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_bt869_init); +module_exit(sm_bt869_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/ddcmon.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/ddcmon.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/ddcmon.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/ddcmon.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,26 +21,14 @@ */ #include -#include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x50, SENSORS_I2C_END }; @@ -80,28 +68,11 @@ struct ddcmon_data { int memtype; }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_ddcmon_init(void); -static int __init ddcmon_cleanup(void); static int ddcmon_attach_adapter(struct i2c_adapter *adapter); static int ddcmon_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int ddcmon_detach_client(struct i2c_client *client); -static int ddcmon_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -static void ddcmon_inc_use(struct i2c_client *client); -static void ddcmon_dec_use(struct i2c_client *client); static void ddcmon_idcall(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); @@ -118,16 +89,23 @@ static void ddcmon_update_client(struct /* This is the driver that will be inserted */ static struct i2c_driver ddcmon_driver = { - /* name */ "DDCMON READER", - /* id */ I2C_DRIVERID_DDCMON, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &ddcmon_attach_adapter, - /* detach_client */ &ddcmon_detach_client, - /* command */ &ddcmon_command, - /* inc_use */ &ddcmon_inc_use, - /* dec_use */ &ddcmon_dec_use + .owner = THIS_MODULE, + .name = "DDCMON READER", + .id = I2C_DRIVERID_DDCMON, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ddcmon_attach_adapter, + .detach_client = ddcmon_detach_client, }; +/* -- SENSORS SYSCTL START -- */ +#define DDCMON_SYSCTL_ID 1010 +#define DDCMON_SYSCTL_SIZE 1011 +#define DDCMON_SYSCTL_SYNC 1012 +#define DDCMON_SYSCTL_TIMINGS 1013 +#define DDCMON_SYSCTL_SERIAL 1014 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected DDCMON. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -147,12 +125,9 @@ static ctl_table ddcmon_dir_table_templa {0} }; -/* Used by init/cleanup */ -static int __initdata ddcmon_initialized = 0; - static int ddcmon_id = 0; -int ddcmon_attach_adapter(struct i2c_adapter *adapter) +static int ddcmon_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, ddcmon_detect); } @@ -181,6 +156,7 @@ int ddcmon_detect(struct i2c_adapter *ad } data = (struct ddcmon_data *) (new_client + 1); + memset(data, 0xff, DDCMON_SIZE); new_client->addr = address; new_client->data = data; new_client->adapter = adapter; @@ -218,8 +194,7 @@ int ddcmon_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - ddcmon_dir_table_template, - THIS_MODULE)) < 0) { + ddcmon_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -236,7 +211,7 @@ int ddcmon_detect(struct i2c_adapter *ad return err; } -int ddcmon_detach_client(struct i2c_client *client) +static int ddcmon_detach_client(struct i2c_client *client) { int err; @@ -251,48 +226,41 @@ int ddcmon_detach_client(struct i2c_clie return 0; } -/* No commands defined yet */ -int ddcmon_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void ddcmon_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void ddcmon_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -void ddcmon_update_client(struct i2c_client *client) +static void ddcmon_update_client(struct i2c_client *client) { struct ddcmon_data *data = client->data; - int i; + int i, j; down(&data->update_lock); - if (time_after(jiffies ,data->last_updated + 300 * HZ) - || !data->valid) { - if (i2c_smbus_write_byte(client, 0)) { + if ((jiffies - data->last_updated > 300 * HZ) || + (jiffies < data->last_updated) || !data->valid) { + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) + { + for (i=0; idata + i) + != I2C_SMBUS_I2C_BLOCK_MAX) + goto DONE; + } else { + if (i2c_smbus_write_byte(client, 0)) { #ifdef DEBUG - printk("ddcmon read start has failed!\n"); + printk("ddcmon read start has failed!\n"); #endif + goto DONE; + } + for (i = 0; i < DDCMON_SIZE; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) + goto DONE; + data->data[i] = (u8) j; + } } - for (i = 0; i < DDCMON_SIZE; i++) { - data->data[i] = (u8) i2c_smbus_read_byte(client); - } - data->last_updated = jiffies; data->valid = 1; } - +DONE: up(&data->update_lock); } @@ -390,54 +358,23 @@ void ddcmon_serial(struct i2c_client *cl } } -int __init sensors_ddcmon_init(void) +static int __init sm_ddcmon_init(void) { - int res; - printk("ddcmon.o version %s (%s)\n", LM_VERSION, LM_DATE); - ddcmon_initialized = 0; - if ((res = i2c_add_driver(&ddcmon_driver))) { - printk - ("ddcmon.o: Driver registration failed, module not inserted.\n"); - ddcmon_cleanup(); - return res; - } - ddcmon_initialized++; - return 0; + return i2c_add_driver(&ddcmon_driver); } -int __init ddcmon_cleanup(void) +static void __exit sm_ddcmon_exit(void) { - int res; - - if (ddcmon_initialized >= 1) { - if ((res = i2c_del_driver(&ddcmon_driver))) { - printk - ("ddcmon.o: Driver deregistration failed, module not removed.\n"); - return res; - } - } else - ddcmon_initialized--; - return 0; + i2c_del_driver(&ddcmon_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Frodo Looijaard , " "Philip Edelbrock , " "and Mark Studebaker "); MODULE_DESCRIPTION("DDCMON driver"); -int init_module(void) -{ - return sensors_ddcmon_init(); -} - -int cleanup_module(void) -{ - return ddcmon_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_ddcmon_init); +module_exit(sm_ddcmon_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/ds1621.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/ds1621.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/ds1621.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/ds1621.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,27 +21,15 @@ /* Supports DS1621. See doc/chips/ds1621 for details */ -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -110,27 +98,12 @@ struct ds1621_data { u8 temp_int, temp_counter, temp_slope; /* Register values, byte */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_ds1621_init(void); -static int __init ds1621_cleanup(void); static int ds1621_attach_adapter(struct i2c_adapter *adapter); static int ds1621_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void ds1621_init_client(struct i2c_client *client); static int ds1621_detach_client(struct i2c_client *client); -static int ds1621_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void ds1621_inc_use(struct i2c_client *client); -static void ds1621_dec_use(struct i2c_client *client); + static u16 swap_bytes(u16 val); static int ds1621_read_value(struct i2c_client *client, u8 reg); static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value); @@ -149,16 +122,25 @@ static void ds1621_update_client(struct /* This is the driver that will be inserted */ static struct i2c_driver ds1621_driver = { - /* name */ "DS1621 sensor driver", - /* id */ I2C_DRIVERID_DS1621, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &ds1621_attach_adapter, - /* detach_client */ &ds1621_detach_client, - /* command */ &ds1621_command, - /* inc_use */ &ds1621_inc_use, - /* dec_use */ &ds1621_dec_use + .owner = THIS_MODULE, + .name = "DS1621 sensor driver", + .id = I2C_DRIVERID_DS1621, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ds1621_attach_adapter, + .detach_client = ds1621_detach_client, }; +/* -- SENSORS SYSCTL START -- */ +#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ +#define DS1621_ALARM_TEMP_HIGH 0x40 +#define DS1621_ALARM_TEMP_LOW 0x20 +#define DS1621_SYSCTL_ENABLE 2002 +#define DS1621_SYSCTL_CONTINUOUS 2003 +#define DS1621_SYSCTL_POLARITY 2004 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected DS1621. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -178,12 +160,9 @@ static ctl_table ds1621_dir_table_templa {0} }; -/* Used by init/cleanup */ -static int __initdata ds1621_initialized = 0; - static int ds1621_id = 0; -int ds1621_attach_adapter(struct i2c_adapter *adapter) +static int ds1621_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, ds1621_detect); } @@ -266,8 +245,7 @@ int ds1621_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - ds1621_dir_table_template, - THIS_MODULE)) < 0) { + ds1621_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -288,16 +266,10 @@ int ds1621_detect(struct i2c_adapter *ad return err; } -int ds1621_detach_client(struct i2c_client *client) +static int ds1621_detach_client(struct i2c_client *client) { int err; -#ifdef MODULE - if (MOD_IN_USE) - return -EBUSY; -#endif - - i2c_deregister_entry(((struct ds1621_data *) (client->data))-> sysctl_id); @@ -313,29 +285,7 @@ int ds1621_detach_client(struct i2c_clie } -/* No commands defined yet */ -int ds1621_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void ds1621_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void ds1621_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) +static u16 swap_bytes(u16 val) { return (val >> 8) | (val << 8); } @@ -343,7 +293,7 @@ u16 swap_bytes(u16 val) /* All registers are word-sized, except for the configuration register. DS1621 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int ds1621_read_value(struct i2c_client *client, u8 reg) +static int ds1621_read_value(struct i2c_client *client, u8 reg) { if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER) || (reg == DS1621_REG_TEMP_SLOPE)) @@ -355,7 +305,7 @@ int ds1621_read_value(struct i2c_client /* All registers are word-sized, except for the configuration register. DS1621 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) +static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) { if ( (reg == DS1621_COM_START) || (reg == DS1621_COM_STOP) ) return i2c_smbus_write_byte(client, reg); @@ -368,7 +318,7 @@ int ds1621_write_value(struct i2c_client swap_bytes(value)); } -void ds1621_init_client(struct i2c_client *client) +static void ds1621_init_client(struct i2c_client *client) { int reg; @@ -383,15 +333,15 @@ void ds1621_init_client(struct i2c_clien ds1621_write_value(client, DS1621_REG_CONF, reg & 0xfe); } -void ds1621_update_client(struct i2c_client *client) +static void ds1621_update_client(struct i2c_client *client) { struct ds1621_data *data = client->data; u8 new_conf; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting ds1621 update\n"); @@ -574,53 +524,21 @@ void ds1621_polarity(struct i2c_client * } } -int __init sensors_ds1621_init(void) +static int __init sm_ds1621_init(void) { - int res; - printk("ds1621.o version %s (%s)\n", LM_VERSION, LM_DATE); - ds1621_initialized = 0; - if ((res = i2c_add_driver(&ds1621_driver))) { - printk - ("ds1621.o: Driver registration failed, module not inserted.\n"); - ds1621_cleanup(); - return res; - } - ds1621_initialized++; - return 0; + return i2c_add_driver(&ds1621_driver); } -int __init ds1621_cleanup(void) +static void __exit sm_ds1621_exit(void) { - int res; - - if (ds1621_initialized >= 1) { - if ((res = i2c_del_driver(&ds1621_driver))) { - printk - ("ds1621.o: Driver deregistration failed, module not removed.\n"); - return res; - } - ds1621_initialized--; - } - - return 0; + i2c_del_driver(&ds1621_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Christian W. Zuckschwerdt "); MODULE_DESCRIPTION("DS1621 driver"); -int init_module(void) -{ - return sensors_ds1621_init(); -} - -int cleanup_module(void) -{ - return ds1621_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_ds1621_init); +module_exit(sm_ds1621_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/eeprom.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/eeprom.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/eeprom.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/eeprom.c 2003-08-17 21:26:58.000000000 +0200 @@ -20,26 +20,14 @@ */ #include -#include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -86,28 +74,11 @@ struct eeprom_data { #endif }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_eeprom_init(void); -static int __init eeprom_cleanup(void); static int eeprom_attach_adapter(struct i2c_adapter *adapter); static int eeprom_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int eeprom_detach_client(struct i2c_client *client); -static int eeprom_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -static void eeprom_inc_use(struct i2c_client *client); -static void eeprom_dec_use(struct i2c_client *client); #if 0 static int eeprom_write_value(struct i2c_client *client, u8 reg, @@ -121,16 +92,35 @@ static void eeprom_update_client(struct /* This is the driver that will be inserted */ static struct i2c_driver eeprom_driver = { - /* name */ "EEPROM READER", - /* id */ I2C_DRIVERID_EEPROM, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &eeprom_attach_adapter, - /* detach_client */ &eeprom_detach_client, - /* command */ &eeprom_command, - /* inc_use */ &eeprom_inc_use, - /* dec_use */ &eeprom_dec_use + .owner = THIS_MODULE, + .name = "EEPROM READER", + .id = I2C_DRIVERID_EEPROM, + .flags = I2C_DF_NOTIFY, + .attach_adapter = eeprom_attach_adapter, + .detach_client = eeprom_detach_client, }; +/* -- SENSORS SYSCTL START -- */ + +#define EEPROM_SYSCTL1 1000 +#define EEPROM_SYSCTL2 1001 +#define EEPROM_SYSCTL3 1002 +#define EEPROM_SYSCTL4 1003 +#define EEPROM_SYSCTL5 1004 +#define EEPROM_SYSCTL6 1005 +#define EEPROM_SYSCTL7 1006 +#define EEPROM_SYSCTL8 1007 +#define EEPROM_SYSCTL9 1008 +#define EEPROM_SYSCTL10 1009 +#define EEPROM_SYSCTL11 1010 +#define EEPROM_SYSCTL12 1011 +#define EEPROM_SYSCTL13 1012 +#define EEPROM_SYSCTL14 1013 +#define EEPROM_SYSCTL15 1014 +#define EEPROM_SYSCTL16 1015 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected EEPROM. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -172,12 +162,9 @@ static ctl_table eeprom_dir_table_templa {0} }; -/* Used by init/cleanup */ -static int __initdata eeprom_initialized = 0; - static int eeprom_id = 0; -int eeprom_attach_adapter(struct i2c_adapter *adapter) +static int eeprom_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, eeprom_detect); } @@ -216,6 +203,7 @@ int eeprom_detect(struct i2c_adapter *ad } data = (struct eeprom_data *) (new_client + 1); + memset(data, 0xff, EEPROM_SIZE); new_client->addr = address; new_client->data = data; new_client->adapter = adapter; @@ -264,8 +252,7 @@ int eeprom_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - eeprom_dir_table_template, - THIS_MODULE)) < 0) { + eeprom_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -285,7 +272,7 @@ int eeprom_detect(struct i2c_adapter *ad return err; } -int eeprom_detach_client(struct i2c_client *client) +static int eeprom_detach_client(struct i2c_client *client) { int err; @@ -304,61 +291,54 @@ int eeprom_detach_client(struct i2c_clie } -/* No commands defined yet */ -int eeprom_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void eeprom_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void eeprom_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - #if 0 /* No writes yet (PAE) */ -int eeprom_write_value(struct i2c_client *client, u8 reg, u8 value) +static int eeprom_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } #endif -void eeprom_update_client(struct i2c_client *client) +static void eeprom_update_client(struct i2c_client *client) { struct eeprom_data *data = client->data; - int i; + int i, j; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + 300 * HZ) - || !data->valid) { + if ((jiffies - data->last_updated > 300 * HZ) | + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting eeprom update\n"); #endif - if (i2c_smbus_write_byte(client, 0)) { + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) + { + for (i=0; idata + i) + != I2C_SMBUS_I2C_BLOCK_MAX) + goto DONE; + } else { + if (i2c_smbus_write_byte(client, 0)) { #ifdef DEBUG - printk("eeprom read start has failed!\n"); + printk("eeprom read start has failed!\n"); #endif + goto DONE; + } + for (i = 0; i < EEPROM_SIZE; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) + goto DONE; + data->data[i] = (u8) j; + } } - for (i = 0; i < EEPROM_SIZE; i++) { - data->data[i] = (u8) i2c_smbus_read_byte(client); - } - data->last_updated = jiffies; data->valid = 1; } - +DONE: up(&data->update_lock); } @@ -441,54 +421,22 @@ void eeprom_contents(struct i2c_client * } } -int __init sensors_eeprom_init(void) +static int __init sm_eeprom_init(void) { - int res; - printk("eeprom.o version %s (%s)\n", LM_VERSION, LM_DATE); - eeprom_initialized = 0; - if ((res = i2c_add_driver(&eeprom_driver))) { - printk - ("eeprom.o: Driver registration failed, module not inserted.\n"); - eeprom_cleanup(); - return res; - } - eeprom_initialized++; - return 0; + return i2c_add_driver(&eeprom_driver); } -int __init eeprom_cleanup(void) +static void __exit sm_eeprom_exit(void) { - int res; - - if (eeprom_initialized >= 1) { - if ((res = i2c_del_driver(&eeprom_driver))) { - printk - ("eeprom.o: Driver deregistration failed, module not removed.\n"); - return res; - } - } else - eeprom_initialized--; - - return 0; + i2c_del_driver(&eeprom_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("EEPROM driver"); -int init_module(void) -{ - return sensors_eeprom_init(); -} - -int cleanup_module(void) -{ - return eeprom_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_eeprom_init); +module_exit(sm_eeprom_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/fscpos.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/fscpos.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/fscpos.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/fscpos.c 2003-08-17 21:26:58.000000000 +0200 @@ -25,30 +25,19 @@ and Philip Edelbrock */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif - +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; @@ -125,11 +114,6 @@ SENSORS_INSMOD_1(fscpos); /* Initial limits */ -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered FSCPOS, we need to keep some data in memory. That data is pointed to by fscpos_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new fscpos client is @@ -155,22 +139,10 @@ struct fscpos_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_fscpos_init(void); -static int __init fscpos_cleanup(void); - static int fscpos_attach_adapter(struct i2c_adapter *adapter); static int fscpos_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int fscpos_detach_client(struct i2c_client *client); -static int fscpos_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void fscpos_inc_use(struct i2c_client *client); -static void fscpos_dec_use(struct i2c_client *client); static int fscpos_read_value(struct i2c_client *client, u8 register); static int fscpos_write_value(struct i2c_client *client, u8 register, @@ -196,20 +168,30 @@ static void fscpos_wdog(struct i2c_clien static int fscpos_id = 0; static struct i2c_driver fscpos_driver = { - /* name */ "FSCPOS sensor driver", - /* id */ I2C_DRIVERID_FSCPOS, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &fscpos_attach_adapter, - /* detach_client */ &fscpos_detach_client, - /* command */ &fscpos_command, - /* inc_use */ &fscpos_inc_use, - /* dec_use */ &fscpos_dec_use + .owner = THIS_MODULE, + .name = "FSCPOS sensor driver", + .id = I2C_DRIVERID_FSCPOS, + .flags = I2C_DF_NOTIFY, + .attach_adapter = fscpos_attach_adapter, + .detach_client = fscpos_detach_client, }; -/* Used by fscpos_init/cleanup */ -static int __initdata fscpos_initialized = 0; +/* -- SENSORS SYSCTL START -- */ +#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCPOS_SYSCTL_REV 2000 /* Revision */ +#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ +#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ +/* -- SENSORS SYSCTL END -- */ -/* The /proc/sys entries */ /* These files are created for each detected FSCPOS. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -245,7 +227,7 @@ static ctl_table fscpos_dir_table_templa {0} }; -int fscpos_attach_adapter(struct i2c_adapter *adapter) +static int fscpos_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, fscpos_detect); } @@ -317,8 +299,7 @@ int fscpos_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - fscpos_dir_table_template, - THIS_MODULE)) < 0) { + fscpos_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -338,7 +319,7 @@ int fscpos_detect(struct i2c_adapter *ad return err; } -int fscpos_detach_client(struct i2c_client *client) +static int fscpos_detach_client(struct i2c_client *client) { int err; @@ -356,28 +337,7 @@ int fscpos_detach_client(struct i2c_clie return 0; } -/* No commands defined yet */ -int fscpos_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void fscpos_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void fscpos_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -int fscpos_read_value(struct i2c_client *client, u8 reg) +static int fscpos_read_value(struct i2c_client *client, u8 reg) { #ifdef DEBUG printk("fscpos: read reg 0x%02x\n",reg); @@ -385,7 +345,7 @@ int fscpos_read_value(struct i2c_client return i2c_smbus_read_byte_data(client, reg); } -int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) +static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) { #ifdef DEBUG printk("fscpos: write reg 0x%02x, val 0x%02x\n",reg, value); @@ -394,7 +354,7 @@ int fscpos_write_value(struct i2c_client } /* Called when we have found a new FSCPOS. It should set limits, etc. */ -void fscpos_init_client(struct i2c_client *client) +static void fscpos_init_client(struct i2c_client *client) { struct fscpos_data *data = client->data; @@ -404,14 +364,14 @@ void fscpos_init_client(struct i2c_clien data->fan_min[2] = 0xff; } -void fscpos_update_client(struct i2c_client *client) +static void fscpos_update_client(struct i2c_client *client) { struct fscpos_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + 2 * HZ) - || !data->valid) { + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting fscpos update\n"); @@ -715,58 +675,23 @@ void fscpos_wdog(struct i2c_client *clie } } -int __init sensors_fscpos_init(void) +static int __init sm_fscpos_init(void) { - int res; - printk("fscpos.o version %s (%s)\n", LM_VERSION, LM_DATE); - fscpos_initialized = 0; - - if ((res = i2c_add_driver(&fscpos_driver))) { - printk - ("fscpos.o: Driver registration failed, module not inserted.\n"); - fscpos_cleanup(); - return res; - } - fscpos_initialized++; - return 0; + return i2c_add_driver(&fscpos_driver); } -int __init fscpos_cleanup(void) +static void __exit sm_fscpos_exit(void) { - int res; - - if (fscpos_initialized >= 1) { - if ((res = i2c_del_driver(&fscpos_driver))) { - printk - ("fscpos.o: Driver deregistration failed, module not removed.\n"); - return res; - } - fscpos_initialized--; - } - return 0; + i2c_del_driver(&fscpos_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Hermann Jung based on work from Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - - -int init_module(void) -{ - return sensors_fscpos_init(); -} - -int cleanup_module(void) -{ - return fscpos_cleanup(); -} -#endif /* MODULE */ +module_init(sm_fscpos_init); +module_exit(sm_fscpos_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/fscscy.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/fscscy.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/fscscy.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/fscscy.c 2003-08-17 21:26:58.000000000 +0200 @@ -25,34 +25,21 @@ and Philip Edelbrock */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif - /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; @@ -171,11 +158,6 @@ SENSORS_INSMOD_1(fscscy); /* Initial limits */ -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered FSCSCY, we need to keep some data in memory. That data is pointed to by fscscy_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new fscscy client is @@ -211,22 +193,10 @@ struct fscscy_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_fscscy_init(void); -static int __init fscscy_cleanup(void); - static int fscscy_attach_adapter(struct i2c_adapter *adapter); static int fscscy_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int fscscy_detach_client(struct i2c_client *client); -static int fscscy_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void fscscy_inc_use(struct i2c_client *client); -static void fscscy_dec_use(struct i2c_client *client); static int fscscy_read_value(struct i2c_client *client, u8 register); static int fscscy_write_value(struct i2c_client *client, u8 register, @@ -256,20 +226,39 @@ static void fscscy_intrusion(struct i2c_ static int fscscy_id = 0; static struct i2c_driver fscscy_driver = { - /* name */ "FSCSCY sensor driver", - /* id */ I2C_DRIVERID_FSCSCY, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &fscscy_attach_adapter, - /* detach_client */ &fscscy_detach_client, - /* command */ &fscscy_command, - /* inc_use */ &fscscy_inc_use, - /* dec_use */ &fscscy_dec_use + .owner = THIS_MODULE, + .name = "FSCSCY sensor driver", + .id = I2C_DRIVERID_FSCSCY, + .flags = I2C_DF_NOTIFY, + .attach_adapter = fscscy_attach_adapter, + .detach_client = fscscy_detach_client, }; -/* Used by fscscy_init/cleanup */ -static int __initdata fscscy_initialized = 0; - /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ +#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ +#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ +#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ +#define FSCSCY_SYSCTL_REV 2000 /* Revision */ +#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ +#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ +#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected FSCSCY. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -317,7 +306,7 @@ static ctl_table fscscy_dir_table_templa {0} }; -int fscscy_attach_adapter(struct i2c_adapter *adapter) +static int fscscy_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, fscscy_detect); } @@ -389,8 +378,7 @@ int fscscy_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - fscscy_dir_table_template, - THIS_MODULE)) < 0) { + fscscy_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -410,7 +398,7 @@ int fscscy_detect(struct i2c_adapter *ad return err; } -int fscscy_detach_client(struct i2c_client *client) +static int fscscy_detach_client(struct i2c_client *client) { int err; @@ -428,28 +416,7 @@ int fscscy_detach_client(struct i2c_clie return 0; } -/* No commands defined yet */ -int fscscy_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void fscscy_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void fscscy_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -int fscscy_read_value(struct i2c_client *client, u8 reg) +static int fscscy_read_value(struct i2c_client *client, u8 reg) { #ifdef DEBUG printk("fscscy: read reg 0x%02x\n",reg); @@ -457,7 +424,7 @@ int fscscy_read_value(struct i2c_client return i2c_smbus_read_byte_data(client, reg); } -int fscscy_write_value(struct i2c_client *client, u8 reg, u8 value) +static int fscscy_write_value(struct i2c_client *client, u8 reg, u8 value) { #ifdef DEBUG printk("fscscy: write reg 0x%02x, val 0x%02x\n",reg, value); @@ -466,7 +433,7 @@ int fscscy_write_value(struct i2c_client } /* Called when we have found a new FSCSCY. It should set limits, etc. */ -void fscscy_init_client(struct i2c_client *client) +static void fscscy_init_client(struct i2c_client *client) { struct fscscy_data *data = client->data; @@ -489,14 +456,14 @@ void fscscy_init_client(struct i2c_clien data->volt_min[2] = data->volt_max[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT); } -void fscscy_update_client(struct i2c_client *client) +static void fscscy_update_client(struct i2c_client *client) { struct fscscy_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + 2 * HZ) - || !data->valid) { + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting fscscy update\n"); @@ -934,54 +901,22 @@ void fscscy_intrusion(struct i2c_client } } -int __init sensors_fscscy_init(void) +static int __init sm_fscscy_init(void) { - int res; - printk("fscscy.o version %s (%s)\n", LM_VERSION, LM_DATE); - fscscy_initialized = 0; - - if ((res = i2c_add_driver(&fscscy_driver))) { - printk - ("fscscy.o: Driver registration failed, module not inserted.\n"); - fscscy_cleanup(); - return res; - } - fscscy_initialized++; - return 0; + return i2c_add_driver(&fscscy_driver); } -int __init fscscy_cleanup(void) +static void __exit sm_fscscy_exit(void) { - int res; - - if (fscscy_initialized >= 1) { - if ((res = i2c_del_driver(&fscscy_driver))) { - printk - ("fscscy.o: Driver deregistration failed, module not removed.\n"); - return res; - } - fscscy_initialized--; - } - return 0; + i2c_del_driver(&fscscy_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Martin Knoblauch based on work (fscpos) from Hermann Jung "); MODULE_DESCRIPTION("fujitsu siemens scylla chip driver"); -int init_module(void) -{ - return sensors_fscscy_init(); -} - -int cleanup_module(void) -{ - return fscscy_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_fscscy_init); +module_exit(sm_fscscy_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/gl518sm.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/gl518sm.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/gl518sm.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/gl518sm.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,29 +21,17 @@ */ #include -#include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include #ifdef __SMP__ #include #endif +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END }; @@ -93,7 +81,7 @@ SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r8 0,255)) #define TEMP_FROM_REG(val) (((val) - 119) * 10) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -164,11 +152,7 @@ struct gl518_data { int iterate_lock; int quit_thread; struct task_struct *thread; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) wait_queue_head_t wq; -#else - struct wait_queue *wq; -#endif char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_updated_v00; @@ -190,36 +174,18 @@ struct gl518_data { u8 iterate; /* Voltage iteration mode */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_gl518sm_init(void); -static int __init gl518_cleanup(void); static int gl518_attach_adapter(struct i2c_adapter *adapter); static int gl518_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void gl518_init_client(struct i2c_client *client); static int gl518_detach_client(struct i2c_client *client); -static int gl518_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void gl518_inc_use(struct i2c_client *client); -static void gl518_dec_use(struct i2c_client *client); + static u16 swap_bytes(u16 val); static int gl518_read_value(struct i2c_client *client, u8 reg); static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); static void gl518_update_client(struct i2c_client *client); static void gl518_update_client_rev00(struct i2c_client *client); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,68) -static int gl518_update_thread(void *data); -#endif static void gl518_update_iterate(struct i2c_client *client); static void gl518_vin(struct i2c_client *client, int operation, @@ -241,16 +207,39 @@ static void gl518_iterate(struct i2c_cli /* This is the driver that will be inserted */ static struct i2c_driver gl518_driver = { - /* name */ "GL518SM sensor chip driver", - /* id */ I2C_DRIVERID_GL518, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &gl518_attach_adapter, - /* detach_client */ &gl518_detach_client, - /* command */ &gl518_command, - /* inc_use */ &gl518_inc_use, - /* dec_use */ &gl518_dec_use + .owner = THIS_MODULE, + .name = "GL518SM sensor chip driver", + .id = I2C_DRIVERID_GL518, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl518_attach_adapter, + .detach_client = gl518_detach_client, }; +/* -- SENSORS SYSCTL START -- */ + +#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL518_SYSCTL_VIN1 1001 +#define GL518_SYSCTL_VIN2 1002 +#define GL518_SYSCTL_VIN3 1003 +#define GL518_SYSCTL_FAN1 1101 /* RPM */ +#define GL518_SYSCTL_FAN2 1102 +#define GL518_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL518_SYSCTL_BEEP 2002 /* bitvector */ +#define GL518_SYSCTL_FAN1OFF 2003 +#define GL518_SYSCTL_ITERATE 2004 + +#define GL518_ALARM_VDD 0x01 +#define GL518_ALARM_VIN1 0x02 +#define GL518_ALARM_VIN2 0x04 +#define GL518_ALARM_VIN3 0x08 +#define GL518_ALARM_TEMP 0x10 +#define GL518_ALARM_FAN1 0x20 +#define GL518_ALARM_FAN2 0x40 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected GL518. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -284,16 +273,13 @@ static ctl_table gl518_dir_table_templat {0} }; -/* Used by init/cleanup */ -static int __initdata gl518_initialized = 0; - /* I choose here for semi-static GL518SM allocation. Complete dynamic allocation could also be used; the code needed for this would probably take more memory than the datastructure takes now. */ #define MAX_GL518_NR 4 static struct i2c_client *gl518_list[MAX_GL518_NR]; -int gl518_attach_adapter(struct i2c_adapter *adapter) +static int gl518_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, gl518_detect); } @@ -406,8 +392,7 @@ static int gl518_detect(struct i2c_adapt /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry((struct i2c_client *) new_client, type_name, - gl518_dir_table_template, - THIS_MODULE)) < 0) { + gl518_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -444,7 +429,7 @@ static int gl518_detect(struct i2c_adapt /* Called when we have found a new GL518SM. It should set limits, etc. */ -void gl518_init_client(struct i2c_client *client) +static void gl518_init_client(struct i2c_client *client) { /* Power-on defaults (bit 7=1) */ gl518_write_value(client, GL518_REG_CONF, 0x80); @@ -483,7 +468,7 @@ void gl518_init_client(struct i2c_client gl518_write_value(client, GL518_REG_CONF, 0x44); } -int gl518_detach_client(struct i2c_client *client) +static int gl518_detach_client(struct i2c_client *client) { int err, i; struct gl518_data *data = client->data; @@ -517,29 +502,7 @@ int gl518_detach_client(struct i2c_clien } -/* No commands defined yet */ -int gl518_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void gl518_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void gl518_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) +static u16 swap_bytes(u16 val) { return (val >> 8) | (val << 8); } @@ -547,7 +510,7 @@ u16 swap_bytes(u16 val) /* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL518 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int gl518_read_value(struct i2c_client *client, u8 reg) +static int gl518_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) return swap_bytes(i2c_smbus_read_word_data(client, reg)); @@ -558,7 +521,7 @@ int gl518_read_value(struct i2c_client * /* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL518 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) +static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) return i2c_smbus_write_word_data(client, reg, @@ -567,15 +530,15 @@ int gl518_write_value(struct i2c_client return i2c_smbus_write_byte_data(client, reg, value); } -void gl518_update_client(struct i2c_client *client) +static void gl518_update_client(struct i2c_client *client) { struct gl518_data *data = client->data; int val; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting gl518 update\n"); @@ -646,7 +609,7 @@ void gl518_update_client(struct i2c_clie /* Here we decide how to run the iteration code. When called, we trigger the iteration and report the last measured voltage. No delay for user apps */ -void gl518_update_client_rev00(struct i2c_client *client) +static void gl518_update_client_rev00(struct i2c_client *client) { struct gl518_data *data = client->data; int i; @@ -654,7 +617,7 @@ void gl518_update_client_rev00(struct i2 if (data->iterate == 1) { /* 10 sec delay */ /* as that update is slow, we consider the data valid for 30 seconds */ if ( - (time_after(jiffies, data->last_updated_v00 + 30 * HZ) + ((jiffies - data->last_updated_v00 > 30 * HZ) || (data->alarms & 7) || (!data->valid)) && (!data->iterate_lock)) { data->iterate_lock = 1; @@ -673,7 +636,7 @@ void gl518_update_client_rev00(struct i2 } } -int gl518_update_thread(void *c) +static int gl518_update_thread(void *c) { struct i2c_client *client = c; struct gl518_data *data = client->data; @@ -688,11 +651,7 @@ int gl518_update_thread(void *c) current->fs->umask = 0; strcpy(current->comm, "gl518sm"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) init_waitqueue_head(&(data->wq)); -#else - data->wq = NULL; -#endif data->thread = current; #ifdef __SMP__ @@ -720,7 +679,7 @@ int gl518_update_thread(void *c) comparisons for the GL518SM rev 00 that lacks support for direct reading of these values. Values are kept in iter_voltage */ -void gl518_update_iterate(struct i2c_client *client) +static void gl518_update_iterate(struct i2c_client *client) { struct gl518_data *data = client->data; int i, j, loop_more = 1, min[3], max[3], delta[3]; @@ -1063,11 +1022,7 @@ void gl518_iterate(struct i2c_client *cl data->quit_thread = 1; wake_up_interruptible(&data->wq); } else if ((data->iterate == 2) && (!data->thread)) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) init_waitqueue_head(&(data->wq)); -#else - data->wq = NULL; -#endif kernel_thread(gl518_update_thread, (void *) client, 0); } @@ -1075,54 +1030,22 @@ void gl518_iterate(struct i2c_client *cl } } -int __init sensors_gl518sm_init(void) +static int __init sm_gl518sm_init(void) { - int res; - printk("gl518sm.o version %s (%s)\n", LM_VERSION, LM_DATE); - gl518_initialized = 0; - if ((res = i2c_add_driver(&gl518_driver))) { - printk - ("gl518sm.o: Driver registration failed, module not inserted.\n"); - gl518_cleanup(); - return res; - } - gl518_initialized++; - return 0; + return i2c_add_driver(&gl518_driver); } -int __init gl518_cleanup(void) +static void __exit sm_gl518sm_exit(void) { - int res; - - if (gl518_initialized >= 1) { - if ((res = i2c_del_driver(&gl518_driver))) { - printk - ("gl518.o: Driver deregistration failed, module not removed.\n"); - return res; - } - gl518_initialized--; - } - - return 0; + i2c_del_driver(&gl518_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Kyösti Mälkki "); MODULE_DESCRIPTION("GL518SM driver"); -int init_module(void) -{ - return sensors_gl518sm_init(); -} - -int cleanup_module(void) -{ - return gl518_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_gl518sm_init); +module_exit(sm_gl518sm_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/gl520sm.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/gl520sm.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/gl520sm.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/gl520sm.c 2003-08-17 21:26:58.000000000 +0200 @@ -20,27 +20,15 @@ */ -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END }; @@ -95,7 +83,7 @@ That's why _TEMP2 and _VIN4 access the s 0,255)) #define TEMP_FROM_REG(val) (((val) - 130) * 10) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -186,27 +174,12 @@ struct gl520_data { u8 two_temps; /* Boolean */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_gl520_init(void); -static int __init gl520_cleanup(void); static int gl520_attach_adapter(struct i2c_adapter *adapter); static int gl520_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void gl520_init_client(struct i2c_client *client); static int gl520_detach_client(struct i2c_client *client); -static int gl520_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void gl520_inc_use(struct i2c_client *client); -static void gl520_dec_use(struct i2c_client *client); + static u16 swap_bytes(u16 val); static int gl520_read_value(struct i2c_client *client, u8 reg); static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); @@ -233,15 +206,42 @@ static void gl520_config(struct i2c_clie /* This is the driver that will be inserted */ static struct i2c_driver gl520_driver = { - /* name */ "GL520SM sensor chip driver", - /* id */ I2C_DRIVERID_GL520, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &gl520_attach_adapter, - /* detach_client */ &gl520_detach_client, - /* command */ &gl520_command, - /* inc_use */ &gl520_inc_use, - /* dec_use */ &gl520_dec_use + .owner = THIS_MODULE, + .name = "GL520SM sensor chip driver", + .id = I2C_DRIVERID_GL520, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl520_attach_adapter, + .detach_client = gl520_detach_client, }; +/* -- SENSORS SYSCTL START -- */ + +#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL520_SYSCTL_VIN1 1001 +#define GL520_SYSCTL_VIN2 1002 +#define GL520_SYSCTL_VIN3 1003 +#define GL520_SYSCTL_VIN4 1004 +#define GL520_SYSCTL_FAN1 1101 /* RPM */ +#define GL520_SYSCTL_FAN2 1102 +#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define GL520_SYSCTL_VID 1300 +#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL520_SYSCTL_BEEP 2002 /* bitvector */ +#define GL520_SYSCTL_FAN1OFF 2003 +#define GL520_SYSCTL_CONFIG 2004 + +#define GL520_ALARM_VDD 0x01 +#define GL520_ALARM_VIN1 0x02 +#define GL520_ALARM_VIN2 0x04 +#define GL520_ALARM_VIN3 0x08 +#define GL520_ALARM_TEMP1 0x10 +#define GL520_ALARM_FAN1 0x20 +#define GL520_ALARM_FAN2 0x40 +#define GL520_ALARM_TEMP2 0x80 +#define GL520_ALARM_VIN4 0x80 + +/* -- SENSORS SYSCTL END -- */ /* These files are created for each detected GL520. This is just a template; though at first sight, you might think we could use a statically @@ -282,15 +282,12 @@ static ctl_table gl520_dir_table_templat {0} }; -/* Used by init/cleanup */ -static int __initdata gl520_initialized = 0; - /* I choose here for semi-static GL520SM allocation. Complete dynamic allocation could also be used; the code needed for this would probably take more memory than the datastructure takes now. */ static int gl520_id = 0; -int gl520_attach_adapter(struct i2c_adapter *adapter) +static int gl520_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, gl520_detect); } @@ -376,8 +373,7 @@ static int gl520_detect(struct i2c_adapt /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - gl520_dir_table_template, - THIS_MODULE)) < 0) { + gl520_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -403,7 +399,7 @@ static int gl520_detect(struct i2c_adapt /* Called when we have found a new GL520SM. It should set limits, etc. */ -void gl520_init_client(struct i2c_client *client) +static void gl520_init_client(struct i2c_client *client) { /* Power-on defaults (bit 7=1) */ gl520_write_value(client, GL520_REG_CONF, 0x80); @@ -450,7 +446,7 @@ void gl520_init_client(struct i2c_client gl520_write_value(client, GL520_REG_CONF, 0x44); } -int gl520_detach_client(struct i2c_client *client) +static int gl520_detach_client(struct i2c_client *client) { int err; @@ -469,29 +465,7 @@ int gl520_detach_client(struct i2c_clien } -/* No commands defined yet */ -int gl520_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void gl520_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void gl520_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) +static u16 swap_bytes(u16 val) { return (val >> 8) | (val << 8); } @@ -499,7 +473,7 @@ u16 swap_bytes(u16 val) /* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL520 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int gl520_read_value(struct i2c_client *client, u8 reg) +static int gl520_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) return swap_bytes(i2c_smbus_read_word_data(client, reg)); @@ -510,7 +484,7 @@ int gl520_read_value(struct i2c_client * /* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL520 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) return i2c_smbus_write_word_data(client, reg, @@ -519,15 +493,15 @@ int gl520_write_value(struct i2c_client return i2c_smbus_write_byte_data(client, reg, value); } -void gl520_update_client(struct i2c_client *client) +static void gl520_update_client(struct i2c_client *client) { struct gl520_data *data = client->data; int val; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting gl520 update\n"); @@ -623,14 +597,14 @@ void gl520_temp(struct i2c_client *clien regnr = nr == 0 ? GL520_REG_TEMP1_OVER : GL520_REG_TEMP2_OVER; if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(results[nr]); + data->temp_over[nr] = TEMP_TO_REG(results[0]); gl520_write_value(client, regnr, data->temp_over[nr]); } regnr = nr == 0 ? GL520_REG_TEMP1_HYST : GL520_REG_TEMP2_HYST; if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[nr]); + data->temp_hyst[nr] = TEMP_TO_REG(results[1]); gl520_write_value(client, regnr, data->temp_hyst[nr]); } @@ -875,54 +849,22 @@ void gl520_config(struct i2c_client *cli } } -int __init sensors_gl520_init(void) +static int __init sm_gl520sm_init(void) { - int res; - printk("gl520sm.o version %s (%s)\n", LM_VERSION, LM_DATE); - gl520_initialized = 0; - if ((res = i2c_add_driver(&gl520_driver))) { - printk - ("gl520sm.o: Driver registration failed, module not inserted.\n"); - gl520_cleanup(); - return res; - } - gl520_initialized++; - return 0; + return i2c_add_driver(&gl520_driver); } -int __init gl520_cleanup(void) +static void __exit sm_gl520sm_exit(void) { - int res; - - if (gl520_initialized >= 1) { - if ((res = i2c_del_driver(&gl520_driver))) { - printk - ("gl520.o: Driver deregistration failed, module not removed.\n"); - return res; - } - gl520_initialized--; - } - - return 0; + i2c_del_driver(&gl520_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Kyösti Mälkki "); MODULE_DESCRIPTION("GL520SM driver"); -int init_module(void) -{ - return sensors_gl520_init(); -} - -int cleanup_module(void) -{ - return gl520_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_gl520sm_init); +module_exit(sm_gl520sm_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/it87.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/it87.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/it87.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/it87.c 2003-08-17 21:26:58.000000000 +0200 @@ -31,33 +31,21 @@ type at module load time. */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -127,7 +115,7 @@ static int temp_type = 0x2a; #define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) #define IN_FROM_REG(val) (((val) * 16) / 10) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -205,11 +193,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define IT87_INIT_TEMP_HIGH_3 600 #define IT87_INIT_TEMP_LOW_3 200 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered IT87, we need to keep some data in memory. That data is pointed to by it87_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new it87 client is @@ -237,22 +220,10 @@ struct it87_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_it87_init(void); -static int __init it87_cleanup(void); - static int it87_attach_adapter(struct i2c_adapter *adapter); static int it87_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int it87_detach_client(struct i2c_client *client); -static int it87_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void it87_inc_use(struct i2c_client *client); -static void it87_dec_use(struct i2c_client *client); static int it87_read_value(struct i2c_client *client, u8 register); static int it87_write_value(struct i2c_client *client, u8 register, @@ -275,22 +246,55 @@ static void it87_fan_div(struct i2c_clie int ctl_name, int *nrels_mag, long *results); static struct i2c_driver it87_driver = { - /* name */ "IT87xx sensor driver", - /* id */ I2C_DRIVERID_IT87, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &it87_attach_adapter, - /* detach_client */ &it87_detach_client, - /* command */ &it87_command, - /* inc_use */ &it87_inc_use, - /* dec_use */ &it87_dec_use + .owner = THIS_MODULE, + .name = "IT87xx sensor driver", + .id = I2C_DRIVERID_IT87, + .flags = I2C_DF_NOTIFY, + .attach_adapter = it87_attach_adapter, + .detach_client = it87_detach_client, }; -/* Used by it87_init/cleanup */ -static int __initdata it87_initialized = 0; - static int it87_id = 0; /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define IT87_SYSCTL_IN1 1001 +#define IT87_SYSCTL_IN2 1002 +#define IT87_SYSCTL_IN3 1003 +#define IT87_SYSCTL_IN4 1004 +#define IT87_SYSCTL_IN5 1005 +#define IT87_SYSCTL_IN6 1006 +#define IT87_SYSCTL_IN7 1007 +#define IT87_SYSCTL_IN8 1008 +#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ +#define IT87_SYSCTL_FAN2 1102 +#define IT87_SYSCTL_FAN3 1103 +#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ +#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ + +#define IT87_ALARM_IN0 0x000100 +#define IT87_ALARM_IN1 0x000200 +#define IT87_ALARM_IN2 0x000400 +#define IT87_ALARM_IN3 0x000800 +#define IT87_ALARM_IN4 0x001000 +#define IT87_ALARM_IN5 0x002000 +#define IT87_ALARM_IN6 0x004000 +#define IT87_ALARM_IN7 0x008000 +#define IT87_ALARM_FAN1 0x0001 +#define IT87_ALARM_FAN2 0x0002 +#define IT87_ALARM_FAN3 0x0004 +#define IT87_ALARM_TEMP1 0x00010000 +#define IT87_ALARM_TEMP2 0x00020000 +#define IT87_ALARM_TEMP3 0x00040000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected IT87. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -341,7 +345,7 @@ static ctl_table it87_dir_table_template * it87_driver is inserted (when this module is loaded), for each available adapter * when a new adapter is inserted (and it87_driver is still present) */ -int it87_attach_adapter(struct i2c_adapter *adapter) +static int it87_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, it87_detect); } @@ -474,8 +478,7 @@ int it87_detect(struct i2c_adapter *adap /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - it87_dir_table_template, - THIS_MODULE)) < 0) { + it87_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -499,7 +502,7 @@ int it87_detect(struct i2c_adapter *adap return err; } -int it87_detach_client(struct i2c_client *client) +static int it87_detach_client(struct i2c_client *client) { int err; @@ -519,29 +522,6 @@ int it87_detach_client(struct i2c_client return 0; } -/* No commands defined yet */ -int it87_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void it87_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void it87_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - /* The SMBus locks itself, but ISA access must be locked explicitely! We don't want to lock the whole ISA bus, so we lock each client separately. @@ -549,7 +529,7 @@ void it87_dec_use(struct i2c_client *cli would slow down the IT87 access and should not be necessary. There are some ugly typecasts here, but the good new is - they should nowhere else be necessary! */ -int it87_read_value(struct i2c_client *client, u8 reg) +static int it87_read_value(struct i2c_client *client, u8 reg) { int res; if (i2c_is_isa_client(client)) { @@ -569,7 +549,7 @@ int it87_read_value(struct i2c_client *c would slow down the IT87 access and should not be necessary. There are some ugly typecasts here, but the good new is - they should nowhere else be necessary! */ -int it87_write_value(struct i2c_client *client, u8 reg, u8 value) +static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) { if (i2c_is_isa_client(client)) { down(&(((struct it87_data *) (client->data))->lock)); @@ -582,7 +562,7 @@ int it87_write_value(struct i2c_client * } /* Called when we have found a new IT87. It should set limits, etc. */ -void it87_init_client(struct i2c_client *client) +static void it87_init_client(struct i2c_client *client) { /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ @@ -658,15 +638,15 @@ void it87_init_client(struct i2c_client | (update_vbat ? 0x41 : 0x01)); } -void it87_update_client(struct i2c_client *client) +static void it87_update_client(struct i2c_client *client) { struct it87_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { if (update_vbat) { /* Cleared after each update, so reenable. Value @@ -885,41 +865,18 @@ void it87_fan_div(struct i2c_client *cli } } -int __init sensors_it87_init(void) +static int __init sm_it87_init(void) { - int res; - printk("it87.o version %s (%s)\n", LM_VERSION, LM_DATE); - it87_initialized = 0; - - if ((res = i2c_add_driver(&it87_driver))) { - printk - ("it87.o: Driver registration failed, module not inserted.\n"); - it87_cleanup(); - return res; - } - it87_initialized++; - return 0; + return i2c_add_driver(&it87_driver); } -int __init it87_cleanup(void) +static void __exit sm_it87_exit(void) { - int res; - - if (it87_initialized >= 1) { - if ((res = i2c_del_driver(&it87_driver))) { - printk - ("it87.o: Driver deregistration failed, module not removed.\n"); - return res; - } - it87_initialized--; - } - return 0; + i2c_del_driver(&it87_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Chris Gauthron "); MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); @@ -928,14 +885,5 @@ MODULE_PARM_DESC(update_vbat, "Update vb MODULE_PARM(temp_type, "i"); MODULE_PARM_DESC(temp_type, "Temperature sensor type, normally leave unset"); -int init_module(void) -{ - return sensors_it87_init(); -} - -int cleanup_module(void) -{ - return it87_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_it87_init); +module_exit(sm_it87_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm75.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm75.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm75.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm75.c 2003-08-17 21:26:58.000000000 +0200 @@ -18,27 +18,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include - -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -79,27 +65,12 @@ struct lm75_data { u16 temp, temp_os, temp_hyst; /* Register values */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_lm75_init(void); -static int __init lm75_cleanup(void); static int lm75_attach_adapter(struct i2c_adapter *adapter); static int lm75_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void lm75_init_client(struct i2c_client *client); static int lm75_detach_client(struct i2c_client *client); -static int lm75_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm75_inc_use(struct i2c_client *client); -static void lm75_dec_use(struct i2c_client *client); + static u16 swap_bytes(u16 val); static int lm75_read_value(struct i2c_client *client, u8 reg); static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); @@ -110,16 +81,20 @@ static void lm75_update_client(struct i2 /* This is the driver that will be inserted */ static struct i2c_driver lm75_driver = { - /* name */ "LM75 sensor chip driver", - /* id */ I2C_DRIVERID_LM75, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &lm75_attach_adapter, - /* detach_client */ &lm75_detach_client, - /* command */ &lm75_command, - /* inc_use */ &lm75_inc_use, - /* dec_use */ &lm75_dec_use + .owner = THIS_MODULE, + .name = "LM75 sensor chip driver", + .id = I2C_DRIVERID_LM75, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm75_attach_adapter, + .detach_client = lm75_detach_client, }; +/* -- SENSORS SYSCTL START -- */ + +#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected LM75. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -131,12 +106,9 @@ static ctl_table lm75_dir_table_template {0} }; -/* Used by init/cleanup */ -static int __initdata lm75_initialized = 0; - static int lm75_id = 0; -int lm75_attach_adapter(struct i2c_adapter *adapter) +static int lm75_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, lm75_detect); } @@ -163,7 +135,7 @@ int lm75_detect(struct i2c_adapter *adap if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; + goto error0; /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. @@ -172,7 +144,7 @@ int lm75_detect(struct i2c_adapter *adap sizeof(struct lm75_data), GFP_KERNEL))) { err = -ENOMEM; - goto ERROR0; + goto error0; } data = (struct lm75_data *) (new_client + 1); @@ -198,7 +170,7 @@ int lm75_detect(struct i2c_adapter *adap || (i2c_smbus_read_word_data (new_client, i * 8 + 3) != os)) - goto ERROR1; + goto error1; } /* Determine the chip type - only one kind supported! */ @@ -209,11 +181,8 @@ int lm75_detect(struct i2c_adapter *adap type_name = "lm75"; client_name = "LM75 chip"; } else { -#ifdef DEBUG - printk("lm75.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; + pr_debug("lm75.o: Internal error: unknown kind (%d)?!?", kind); + goto error1; } /* Fill in the remaining client fields and put it into the global list */ @@ -225,14 +194,13 @@ int lm75_detect(struct i2c_adapter *adap /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto ERROR3; + goto error3; /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - lm75_dir_table_template, - THIS_MODULE)) < 0) { + lm75_dir_table_template)) < 0) { err = i; - goto ERROR4; + goto error4; } data->sysctl_id = i; @@ -242,63 +210,26 @@ int lm75_detect(struct i2c_adapter *adap /* OK, this is not exactly good programming practice, usually. But it is very code-efficient in this case. */ - ERROR4: + error4: i2c_detach_client(new_client); - ERROR3: - ERROR1: + error3: + error1: kfree(new_client); - ERROR0: + error0: return err; } -int lm75_detach_client(struct i2c_client *client) +static int lm75_detach_client(struct i2c_client *client) { - int err; - -#ifdef MODULE - if (MOD_IN_USE) - return -EBUSY; -#endif - - - i2c_deregister_entry(((struct lm75_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("lm75.o: Client deregistration failed, client not detached.\n"); - return err; - } + struct lm75_data *data = client->data; + i2c_deregister_entry(data->sysctl_id); + i2c_detach_client(client); kfree(client); - - return 0; -} - - -/* No commands defined yet */ -int lm75_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ return 0; } -/* Nothing here yet */ -void lm75_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void lm75_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) +static u16 swap_bytes(u16 val) { return (val >> 8) | (val << 8); } @@ -306,7 +237,7 @@ u16 swap_bytes(u16 val) /* All registers are word-sized, except for the configuration register. LM75 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int lm75_read_value(struct i2c_client *client, u8 reg) +static int lm75_read_value(struct i2c_client *client, u8 reg) { if (reg == LM75_REG_CONF) return i2c_smbus_read_byte_data(client, reg); @@ -317,7 +248,7 @@ int lm75_read_value(struct i2c_client *c /* All registers are word-sized, except for the configuration register. LM75 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) { if (reg == LM75_REG_CONF) return i2c_smbus_write_byte_data(client, reg, value); @@ -326,7 +257,7 @@ int lm75_write_value(struct i2c_client * swap_bytes(value)); } -void lm75_init_client(struct i2c_client *client) +static void lm75_init_client(struct i2c_client *client) { /* Initialize the LM75 chip */ lm75_write_value(client, LM75_REG_TEMP_OS, @@ -336,18 +267,15 @@ void lm75_init_client(struct i2c_client lm75_write_value(client, LM75_REG_CONF, 0); } -void lm75_update_client(struct i2c_client *client) +static void lm75_update_client(struct i2c_client *client) { struct lm75_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - -#ifdef DEBUG - printk("Starting lm75 update\n"); -#endif + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + pr_debug("Starting lm75 update\n"); data->temp = lm75_read_value(client, LM75_REG_TEMP); data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS); @@ -387,53 +315,20 @@ void lm75_temp(struct i2c_client *client } } -int __init sensors_lm75_init(void) +static int __init sm_lm75_init(void) { - int res; - - printk("lm75.o version %s (%s)\n", LM_VERSION, LM_DATE); - lm75_initialized = 0; - if ((res = i2c_add_driver(&lm75_driver))) { - printk - ("lm75.o: Driver registration failed, module not inserted.\n"); - lm75_cleanup(); - return res; - } - lm75_initialized++; - return 0; + printk(KERN_INFO "lm75.o version %s (%s)\n", LM_VERSION, LM_DATE); + return i2c_add_driver(&lm75_driver); } -int __init lm75_cleanup(void) +static void __exit sm_lm75_exit(void) { - int res; - - if (lm75_initialized >= 1) { - if ((res = i2c_del_driver(&lm75_driver))) { - printk - ("lm75.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm75_initialized--; - } - - return 0; + i2c_del_driver(&lm75_driver); } -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("LM75 driver"); +MODULE_LICENSE("GPL"); -int init_module(void) -{ - return sensors_lm75_init(); -} - -int cleanup_module(void) -{ - return lm75_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_lm75_init); +module_exit(sm_lm75_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm78.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm78.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm78.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm78.c 2003-08-17 21:26:58.000000000 +0200 @@ -18,33 +18,21 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -93,7 +81,7 @@ SENSORS_INSMOD_3(lm78, lm78j, lm79); #define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) #define IN_FROM_REG(val) (((val) * 16) / 10) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -163,11 +151,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define LM78_INIT_TEMP_OVER 600 #define LM78_INIT_TEMP_HYST 500 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* There are some complications in a module like this. First off, LM78 chips may be both present on the SMBus and the ISA bus, and we have to handle those cases separately at some places. Second, there might be several @@ -210,22 +193,10 @@ struct lm78_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_lm78_init(void); -static int __init lm78_cleanup(void); - static int lm78_attach_adapter(struct i2c_adapter *adapter); static int lm78_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int lm78_detach_client(struct i2c_client *client); -static int lm78_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm78_inc_use(struct i2c_client *client); -static void lm78_dec_use(struct i2c_client *client); static int lm78_read_value(struct i2c_client *client, u8 register); static int lm78_write_value(struct i2c_client *client, u8 register, @@ -248,22 +219,52 @@ static void lm78_fan_div(struct i2c_clie int ctl_name, int *nrels_mag, long *results); static struct i2c_driver lm78_driver = { - /* name */ "LM78(-J) and LM79 sensor driver", - /* id */ I2C_DRIVERID_LM78, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &lm78_attach_adapter, - /* detach_client */ &lm78_detach_client, - /* command */ &lm78_command, - /* inc_use */ &lm78_inc_use, - /* dec_use */ &lm78_dec_use + .owner = THIS_MODULE, + .name = "LM78(-J) and LM79 sensor driver", + .id = I2C_DRIVERID_LM78, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm78_attach_adapter, + .detach_client = lm78_detach_client, }; -/* Used by lm78_init/cleanup */ -static int __initdata lm78_initialized = 0; - static int lm78_id = 0; /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM78_SYSCTL_IN1 1001 +#define LM78_SYSCTL_IN2 1002 +#define LM78_SYSCTL_IN3 1003 +#define LM78_SYSCTL_IN4 1004 +#define LM78_SYSCTL_IN5 1005 +#define LM78_SYSCTL_IN6 1006 +#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM78_SYSCTL_FAN2 1102 +#define LM78_SYSCTL_FAN3 1103 +#define LM78_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ +#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM78_ALARM_IN0 0x0001 +#define LM78_ALARM_IN1 0x0002 +#define LM78_ALARM_IN2 0x0004 +#define LM78_ALARM_IN3 0x0008 +#define LM78_ALARM_IN4 0x0100 +#define LM78_ALARM_IN5 0x0200 +#define LM78_ALARM_IN6 0x0400 +#define LM78_ALARM_FAN1 0x0040 +#define LM78_ALARM_FAN2 0x0080 +#define LM78_ALARM_FAN3 0x0800 +#define LM78_ALARM_TEMP 0x0010 +#define LM78_ALARM_BTI 0x0020 +#define LM78_ALARM_CHAS 0x1000 +#define LM78_ALARM_FIFO 0x2000 +#define LM78_ALARM_SMI_IN 0x4000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected LM78. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -306,7 +307,7 @@ static ctl_table lm78_dir_table_template * lm78_driver is inserted (when this module is loaded), for each available adapter * when a new adapter is inserted (and lm78_driver is still present) */ -int lm78_attach_adapter(struct i2c_adapter *adapter) +static int lm78_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, lm78_detect); } @@ -445,8 +446,7 @@ int lm78_detect(struct i2c_adapter *adap /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - lm78_dir_table_template, - THIS_MODULE)) < 0) { + lm78_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -470,7 +470,7 @@ int lm78_detect(struct i2c_adapter *adap return err; } -int lm78_detach_client(struct i2c_client *client) +static int lm78_detach_client(struct i2c_client *client) { int err; @@ -490,29 +490,6 @@ int lm78_detach_client(struct i2c_client return 0; } -/* No commands defined yet */ -int lm78_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void lm78_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void lm78_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - /* The SMBus locks itself, but ISA access must be locked explicitely! We don't want to lock the whole ISA bus, so we lock each client separately. @@ -520,7 +497,7 @@ void lm78_dec_use(struct i2c_client *cli would slow down the LM78 access and should not be necessary. There are some ugly typecasts here, but the good new is - they should nowhere else be necessary! */ -int lm78_read_value(struct i2c_client *client, u8 reg) +static int lm78_read_value(struct i2c_client *client, u8 reg) { int res; if (i2c_is_isa_client(client)) { @@ -540,7 +517,7 @@ int lm78_read_value(struct i2c_client *c would slow down the LM78 access and should not be necessary. There are some ugly typecasts here, but the good new is - they should nowhere else be necessary! */ -int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) +static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) { if (i2c_is_isa_client(client)) { down(&(((struct lm78_data *) (client->data))->lock)); @@ -553,7 +530,7 @@ int lm78_write_value(struct i2c_client * } /* Called when we have found a new LM78. It should set limits, etc. */ -void lm78_init_client(struct i2c_client *client) +static void lm78_init_client(struct i2c_client *client) { int vid; @@ -615,15 +592,15 @@ void lm78_init_client(struct i2c_client } -void lm78_update_client(struct i2c_client *client) +static void lm78_update_client(struct i2c_client *client) { struct lm78_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting lm78 update\n"); @@ -821,53 +798,21 @@ void lm78_fan_div(struct i2c_client *cli } } -int __init sensors_lm78_init(void) +static int __init sm_lm78_init(void) { - int res; - printk("lm78.o version %s (%s)\n", LM_VERSION, LM_DATE); - lm78_initialized = 0; - - if ((res = i2c_add_driver(&lm78_driver))) { - printk - ("lm78.o: Driver registration failed, module not inserted.\n"); - lm78_cleanup(); - return res; - } - lm78_initialized++; - return 0; + return i2c_add_driver(&lm78_driver); } -int __init lm78_cleanup(void) +static void __exit sm_lm78_exit(void) { - int res; - - if (lm78_initialized >= 1) { - if ((res = i2c_del_driver(&lm78_driver))) { - printk - ("lm78.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm78_initialized--; - } - return 0; + i2c_del_driver(&lm78_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); -int init_module(void) -{ - return sensors_lm78_init(); -} - -int cleanup_module(void) -{ - return lm78_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_lm78_init); +module_exit(sm_lm78_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm80.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm80.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm80.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm80.c 2003-08-17 21:26:58.000000000 +0200 @@ -19,33 +19,21 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -91,7 +79,7 @@ SENSORS_INSMOD_1(lm80); #define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255)) #define IN_FROM_REG(val,nr) (val) -extern inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) +static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) { if (rpm == 0) return 255; @@ -103,7 +91,7 @@ extern inline unsigned char FAN_TO_REG(u #define FAN_FROM_REG(val,div) ((val)==0?-1:\ (val)==255?0:1350000/((div)*(val))) -extern inline long TEMP_FROM_REG(u16 temp) +static inline long TEMP_FROM_REG(u16 temp) { long res; @@ -175,10 +163,6 @@ extern inline long TEMP_FROM_REG(u16 tem #define LM80_INIT_TEMP_HOT_MAX 700 #define LM80_INIT_TEMP_HOT_HYST 600 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ /* For each registered LM80, we need to keep some data in memory. That data is pointed to by lm80_list[NR]->data. The structure itself is @@ -206,22 +190,11 @@ struct lm80_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_lm80_init(void); -static int __init lm80_cleanup(void); static int lm80_attach_adapter(struct i2c_adapter *adapter); static int lm80_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int lm80_detach_client(struct i2c_client *client); -static int lm80_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm80_inc_use(struct i2c_client *client); -static void lm80_dec_use(struct i2c_client *client); static int lm80_read_value(struct i2c_client *client, u8 register); static int lm80_write_value(struct i2c_client *client, u8 register, @@ -244,20 +217,48 @@ static void lm80_fan_div(struct i2c_clie static int lm80_id = 0; static struct i2c_driver lm80_driver = { - /* name */ "LM80 sensor driver", - /* id */ I2C_DRIVERID_LM80, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &lm80_attach_adapter, - /* detach_client */ &lm80_detach_client, - /* command */ &lm80_command, - /* inc_use */ &lm80_inc_use, - /* dec_use */ &lm80_dec_use + .owner = THIS_MODULE, + .name = "LM80 sensor driver", + .id = I2C_DRIVERID_LM80, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm80_attach_adapter, + .detach_client = lm80_detach_client, }; -/* Used by lm80_init/cleanup */ -static int __initdata lm80_initialized = 0; - /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ + +#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM80_SYSCTL_IN1 1001 +#define LM80_SYSCTL_IN2 1002 +#define LM80_SYSCTL_IN3 1003 +#define LM80_SYSCTL_IN4 1004 +#define LM80_SYSCTL_IN5 1005 +#define LM80_SYSCTL_IN6 1006 +#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM80_SYSCTL_FAN2 1102 +#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM80_ALARM_IN0 0x0001 +#define LM80_ALARM_IN1 0x0002 +#define LM80_ALARM_IN2 0x0004 +#define LM80_ALARM_IN3 0x0008 +#define LM80_ALARM_IN4 0x0010 +#define LM80_ALARM_IN5 0x0020 +#define LM80_ALARM_IN6 0x0040 +#define LM80_ALARM_FAN1 0x0400 +#define LM80_ALARM_FAN2 0x0800 +#define LM80_ALARM_TEMP_HOT 0x0100 +#define LM80_ALARM_TEMP_OS 0x2000 +#define LM80_ALARM_CHAS 0x1000 +#define LM80_ALARM_BTI 0x0200 +#define LM80_ALARM_INT_IN 0x0080 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected LM80. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -291,7 +292,7 @@ static ctl_table lm80_dir_table_template {0} }; -int lm80_attach_adapter(struct i2c_adapter *adapter) +static int lm80_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, lm80_detect); } @@ -375,8 +376,7 @@ int lm80_detect(struct i2c_adapter *adap /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - lm80_dir_table_template, - THIS_MODULE)) < 0) { + lm80_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -396,7 +396,7 @@ int lm80_detect(struct i2c_adapter *adap return err; } -int lm80_detach_client(struct i2c_client *client) +static int lm80_detach_client(struct i2c_client *client) { int err; @@ -414,39 +414,18 @@ int lm80_detach_client(struct i2c_client return 0; } -/* No commands defined yet */ -int lm80_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void lm80_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void lm80_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -int lm80_read_value(struct i2c_client *client, u8 reg) +static int lm80_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); } -int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* Called when we have found a new LM80. It should set limits, etc. */ -void lm80_init_client(struct i2c_client *client) +static void lm80_init_client(struct i2c_client *client) { /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others. This makes most other @@ -500,15 +479,15 @@ void lm80_init_client(struct i2c_client lm80_write_value(client, LM80_REG_CONFIG, 0x01); } -void lm80_update_client(struct i2c_client *client) +static void lm80_update_client(struct i2c_client *client) { struct lm80_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + 2 * HZ) - || !data->valid) { + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting lm80 update\n"); @@ -708,54 +687,22 @@ void lm80_fan_div(struct i2c_client *cli } } -int __init sensors_lm80_init(void) +static int __init sm_lm80_init(void) { - int res; - - printk("lm80.o version %s (%s)\n", LM_VERSION, LM_DATE); - lm80_initialized = 0; - - if ((res = i2c_add_driver(&lm80_driver))) { - printk - ("lm80.o: Driver registration failed, module not inserted.\n"); - lm80_cleanup(); - return res; - } - lm80_initialized++; - return 0; + printk("lm80.o version %s (%s)\n", LM_VERSION, LM_DATE); + return i2c_add_driver(&lm80_driver); } -int __init lm80_cleanup(void) +static void __exit sm_lm80_exit(void) { - int res; - - if (lm80_initialized >= 1) { - if ((res = i2c_del_driver(&lm80_driver))) { - printk - ("lm80.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm80_initialized--; - } - return 0; + i2c_del_driver(&lm80_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("LM80 driver"); -int init_module(void) -{ - return sensors_lm80_init(); -} - -int cleanup_module(void) -{ - return lm80_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_lm80_init); +module_exit(sm_lm80_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm85.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm85.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm85.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm85.c 2003-08-17 21:26:58.000000000 +0200 @@ -0,0 +1,2050 @@ +/* + lm85.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (c) 2002, 2003 Philip Pokorny + Copyright (c) 2003 Margit Schubert-While + + 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. + + CHANGELOG + + 2002-11-13 First patch for LM85 functionality + 2002-11-18 LM85 functionality mostly done + 2002-12-02 Adding ADM1027 functionality + 2002-12-06 Adding ADT7463 functionality + 2003-01-09 Code cleanup. + Save reserved bits in case they are implemented + in a future chip. (Solve problem with lockups + on ADM1027 due to chip initialization) + Added chip initialization bypass option + 2003-02-12 Add THERM asserted counts for ADT7463 + Added #ifdef so we can compile against 2.6.5 + without updating i2c-ids.h + 2003-02-17 Prepare for switch to 2.7.0 development + Implement tmin_control for ADT7463 + Expose THERM asserted counts to /proc + Code cleanup + 2003-02-19 Working with Margit and LM_SENSORS developers + 2003-02-23 Removed chip initialization entirely + Scale voltages in driver at Margit's request + Change PWM from 0-100% to 0-255 per LM sensors standard + 2003-02-27 Documentation and code cleanups + Added this CHANGELOG + Print additional precision for temperatures and voltages + Many thanks to Margit Schubert-While and Brandt xxxxxx + for help testing this version + 2003-02-28 More diagnostic messages regarding BIOS setup + 2003-03-01 Added Interrupt mask register support. + 2003-03-08 Fixed problem with pseudo 16-bit registers + Cleaned up some compiler warnings. + Fixed problem with Operating Point and THERM counting + 2003-03-21 Initial support for EMC6D100 and EMC6D101 chips + 2003-06-30 Add support for EMC6D100 extra voltage inputs. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include + +#ifndef I2C_DRIVERID_LM85 +#define I2C_DRIVERID_LM85 1039 +#endif + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_5(lm85b, lm85c, adm1027, adt7463, emc6d100); + +/* Many LM85 constants specified below */ + +/* The LM85 registers */ +#define LM85_REG_IN(nr) (0x20 + (nr)) +#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) +#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) + +#define LM85_REG_TEMP(nr) (0x25 + (nr)) +#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) +#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) + +/* Fan speeds are LSB, MSB (2 bytes) */ +#define LM85_REG_FAN(nr) (0x28 + (nr) *2) +#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) + +#define LM85_REG_PWM(nr) (0x30 + (nr)) + +#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) + +#define ADT7463_REG_TMIN_CTL1 0x36 +#define ADT7463_REG_TMIN_CTL2 0x37 +#define ADT7463_REG_TMIN_CTL 0x0136 + +#define LM85_REG_DEVICE 0x3d +#define LM85_REG_COMPANY 0x3e +#define LM85_REG_VERSTEP 0x3f +/* These are the recognized values for the above regs */ +#define LM85_DEVICE_ADX 0x27 +#define LM85_COMPANY_NATIONAL 0x01 +#define LM85_COMPANY_ANALOG_DEV 0x41 +#define LM85_COMPANY_SMSC 0x5c +#define LM85_VERSTEP_VMASK 0xf0 +#define LM85_VERSTEP_SMASK 0x0f +#define LM85_VERSTEP_GENERIC 0x60 +#define LM85_VERSTEP_LM85C 0x60 +#define LM85_VERSTEP_LM85B 0x62 +#define LM85_VERSTEP_ADM1027 0x60 +#define LM85_VERSTEP_ADT7463 0x62 +#define LM85_VERSTEP_EMC6D100_A0 0x60 +#define LM85_VERSTEP_EMC6D100_A1 0x61 + +#define LM85_REG_CONFIG 0x40 + +#define LM85_REG_ALARM1 0x41 +#define LM85_REG_ALARM2 0x42 +#define LM85_REG_ALARM 0x0141 + +#define LM85_REG_VID 0x43 + +/* Automated FAN control */ +#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) +#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) +#define LM85_REG_AFAN_SPIKE1 0x62 +#define LM85_REG_AFAN_SPIKE2 0x63 +#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) +#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) +#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) +#define LM85_REG_AFAN_HYST1 0x6d +#define LM85_REG_AFAN_HYST2 0x6e + +#define LM85_REG_TACH_MODE 0x74 +#define LM85_REG_SPINUP_CTL 0x75 + +#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) +#define ADM1027_REG_CONFIG2 0x73 +#define ADM1027_REG_INTMASK1 0x74 +#define ADM1027_REG_INTMASK2 0x75 +#define ADM1027_REG_INTMASK 0x0174 +#define ADM1027_REG_EXTEND_ADC1 0x76 +#define ADM1027_REG_EXTEND_ADC2 0x77 +#define ADM1027_REG_EXTEND_ADC 0x0176 +#define ADM1027_REG_CONFIG3 0x78 +#define ADM1027_REG_FAN_PPR 0x7b + +#define ADT7463_REG_THERM 0x79 +#define ADT7463_REG_THERM_LIMIT 0x7A +#define ADT7463_REG_CONFIG4 0x7D + +#define EMC6D100_REG_SFR 0x7c +#define EMC6D100_REG_ALARM3 0x7d +#define EMC6D100_REG_CONF 0x7f +#define EMC6D100_REG_INT_EN 0x80 +/* IN5, IN6 and IN7 */ +#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) +#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) +#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + */ + +/* IN are scaled 1.000 == 0xc0, mag = 3 */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255)) +#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0) +#define IN_FROM_REG(val) (INEXT_FROM_REG(val,0)) + +/* IN are scaled acording to built-in resistors */ +static int lm85_scaling[] = { /* .001 Volts */ + 2500, 2250, 3300, 5000, 12000, + 3300, 1500, 1800, /* EMC6D100 */ + }; +#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) +#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)) +#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n])) +#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) + +/* FAN speed is measured using 90kHz clock */ +#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) +#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) + +/* Temperature is reported in .01 degC increments */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127)) +#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25) +#define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0)) +#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) +#define OPPOINT_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) +#define OPPOINT_FROM_REG(val) (val) + +#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_FROM_REG(val) (val) + +#define EXT_FROM_REG(val,sensor) (((val)>>(sensor * 2))&0x03) + +/* ZONEs have the following parameters: + * Limit (low) temp, 1. degC + * Hysteresis (below limit), 1. degC (0-15) + * Range of speed control, .1 degC (2-80) + * Critical (high) temp, 1. degC + * + * FAN PWMs have the following parameters: + * Reference Zone, 1, 2, 3, etc. + * Spinup time, .05 sec + * PWM value at limit/low temp, 1 count + * PWM Frequency, 1. Hz + * PWM is Min or OFF below limit, flag + * Invert PWM output, flag + * + * Some chips filter the temp, others the fan. + * Filter constant (or disabled) .1 seconds + */ + +/* These are the zone temperature range encodings */ +static int lm85_range_map[] = { /* .1 degC */ + 20, 25, 33, 40, 50, 66, + 80, 100, 133, 160, 200, 266, + 320, 400, 533, 800 + }; +static int RANGE_TO_REG( int range ) +{ + int i; + + if( range >= lm85_range_map[15] ) { return 15 ; } + for( i = 0 ; i < 15 ; ++i ) + if( range <= lm85_range_map[i] ) + break ; + return( i & 0x0f ); +} +#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) + +/* These are the Acoustic Enhancement, or Temperature smoothing encodings + * NOTE: The enable/disable bit is INCLUDED in these encodings as the + * MSB (bit 3, value 8). If the enable bit is 0, the encoded value + * is ignored, or set to 0. + */ +static int lm85_smooth_map[] = { /* .1 sec */ + 350, 176, 118, 70, 44, 30, 16, 8 +/* 35.4 * 1/1, 1/2, 1/3, 1/5, 1/8, 1/12, 1/24, 1/48 */ + }; +static int SMOOTH_TO_REG( int smooth ) +{ + int i; + + if( smooth <= 0 ) { return 0 ; } /* Disabled */ + for( i = 0 ; i < 7 ; ++i ) + if( smooth >= lm85_smooth_map[i] ) + break ; + return( (i & 0x07) | 0x08 ); +} +#define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0) + +/* These are the fan spinup delay time encodings */ +static int lm85_spinup_map[] = { /* .1 sec */ + 0, 1, 2, 4, 7, 10, 20, 40 + }; +static int SPINUP_TO_REG( int spinup ) +{ + int i; + + if( spinup >= lm85_spinup_map[7] ) { return 7 ; } + for( i = 0 ; i < 7 ; ++i ) + if( spinup <= lm85_spinup_map[i] ) + break ; + return( i & 0x07 ); +} +#define SPINUP_FROM_REG(val) (lm85_spinup_map[(val)&0x07]) + +/* These are the PWM frequency encodings */ +static int lm85_freq_map[] = { /* .1 Hz */ + 100, 150, 230, 300, 380, 470, 620, 980 + }; +static int FREQ_TO_REG( int freq ) +{ + int i; + + if( freq >= lm85_freq_map[7] ) { return 7 ; } + for( i = 0 ; i < 7 ; ++i ) + if( freq <= lm85_freq_map[i] ) + break ; + return( i & 0x07 ); +} +#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) + +/* Since we can't use strings, I'm abusing these numbers + * to stand in for the following meanings: + * 1 -- PWM responds to Zone 1 + * 2 -- PWM responds to Zone 2 + * 3 -- PWM responds to Zone 3 + * 23 -- PWM responds to the higher temp of Zone 2 or 3 + * 123 -- PWM responds to highest of Zone 1, 2, or 3 + * 0 -- PWM is always at 0% (ie, off) + * -1 -- PWM is always at 100% + * -2 -- PWM responds to manual control + */ +static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; +static int ZONE_TO_REG( int zone ) +{ + int i; + + for( i = 0 ; i <= 7 ; ++i ) + if( zone == lm85_zone_map[i] ) + break ; + if( i > 7 ) /* Not found. */ + i = 3; /* Always 100% */ + return( (i & 0x07)<<5 ); +} +#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) + +#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15)) +#define HYST_FROM_REG(val) (-(val)*10) + +#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) +#define OFFSET_FROM_REG(val) ((val)*25) + +#define PPR_MASK(fan) (0x03<<(fan *2)) +#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) +#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) + +/* sensors_vid.h defines vid_from_reg() */ +#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) + +#define ALARMS_FROM_REG(val) (val) + +/* When converting to REG, we need to fixup the carry-over bit */ +#define INTMASK_FROM_REG(val) (val) +#define INTMASK_TO_REG(val) (SENSORS_LIMIT((val)|((val)&0xff00?0x80:0),0,65535)) + +/* Unlike some other drivers we DO NOT set initial limits. Use + * the config file to set limits. Some users have reported + * motherboards shutting down when we set limits in a previous + * version of this driver. This may be caused by APM/ACPI + * detecting an out-of-limit condition when we had the wrong + * limits set. + */ + +/* Typically used with Pentium 4 systems v9.1 VRM spec */ +#define LM85_INIT_VRM 91 + +/* Chip sampling rates + * + * Some sensors are not updated more frequently than once per second + * so it doesn't make sense to read them more often than that. + * We cache the results and return the saved data if the driver + * is called again before a second has elapsed. + * + * Also, there is significant configuration data for this chip + * given the automatic PWM fan control that is possible. There + * are about 47 bytes of config data to only 22 bytes of actual + * readings. So, we keep the config data up to date in the cache + * when it is written and only sample it once every 5 *minutes* + */ +#define LM85_DATA_INTERVAL (1 * HZ) +#define LM85_CONFIG_INTERVAL (5 * 60 * HZ) + +/* For each registered LM85, we need to keep some data in memory. That + data is pointed to by client->data. The structure itself is + dynamically allocated, when a new lm85 client is allocated. */ + +/* LM85 can automatically adjust fan speeds based on temperature + * This structure encapsulates an entire Zone config. There are + * three zones (one for each temperature input) on the lm85 + */ +struct lm85_zone { + s8 limit; /* Low temp limit */ + u8 hyst; /* Low limit hysteresis. (0-15) */ + u8 range; /* Temp range, encoded */ + s8 critical; /* "All fans ON" temp limit */ +}; + +struct lm85_autofan { + u8 config; /* Register value */ + u8 freq; /* PWM frequency, encoded */ + u8 min_pwm; /* Minimum PWM value, encoded */ + u8 min_off; /* Min PWM or OFF below "limit", flag */ +}; + +struct lm85_data { + struct semaphore lock; + int sysctl_id; + enum chips type; + + struct semaphore update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ + + u8 in[8]; /* Register value */ + u8 in_max[8]; /* Register value */ + u8 in_min[8]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u16 fan[4]; /* Register value */ + u16 fan_min[4]; /* Register value */ + u8 pwm[3]; /* Register value */ + u8 spinup_ctl; /* Register encoding, combined */ + u8 tach_mode; /* Register encoding, combined */ + u16 extend_adc; /* Register value */ + u8 fan_ppr; /* Register value */ + u8 smooth[3]; /* Register encoding */ + u8 vid; /* Register value */ + u8 vrm; /* VRM version */ + u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ + s8 oppoint[3]; /* Register value */ + u16 tmin_ctl; /* Register value */ + long therm_total; /* Cummulative therm count */ + long therm_ovfl; /* Count of therm overflows */ + u8 therm_limit; /* Register value */ + u32 alarms; /* Register encoding, combined */ + u32 alarm_mask; /* Register encoding, combined */ + struct lm85_autofan autofan[3]; + struct lm85_zone zone[3]; +}; + +static int lm85_attach_adapter(struct i2c_adapter *adapter); +static int lm85_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static int lm85_detach_client(struct i2c_client *client); +static int lm85_read_value(struct i2c_client *client, u16 register); +static int lm85_write_value(struct i2c_client *client, u16 register, int value); +static void lm85_update_client(struct i2c_client *client); +static void lm85_init_client(struct i2c_client *client); + + +static void lm85_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results); +static void lm85_fan(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_vid(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_vrm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_pwm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_zone(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_pwm_config(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_pwm_zone(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_smooth(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +static void lm85_spinup_ctl(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm85_tach_mode(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +static void adm1027_tach_mode(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1027_temp_offset(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1027_fan_ppr(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1027_alarm_mask(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +static void adt7463_tmin_ctl(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adt7463_therm_signal(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +static void emc6d100_in(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +static struct i2c_driver lm85_driver = { + .owner = THIS_MODULE, + .name = "LM85 compatible sensor driver", + .id = I2C_DRIVERID_LM85, + .flags = I2C_DF_NOTIFY, + .attach_adapter = &lm85_attach_adapter, + .detach_client = &lm85_detach_client, +}; + +/* Unique ID assigned to each LM85 detected */ +static int lm85_id = 0; + +/* -- SENSORS SYSCTL START -- */ +/* Common parameters */ +#define LM85_SYSCTL_IN0 1000 +#define LM85_SYSCTL_IN1 1001 +#define LM85_SYSCTL_IN2 1002 +#define LM85_SYSCTL_IN3 1003 +#define LM85_SYSCTL_IN4 1004 +#define LM85_SYSCTL_FAN1 1005 +#define LM85_SYSCTL_FAN2 1006 +#define LM85_SYSCTL_FAN3 1007 +#define LM85_SYSCTL_FAN4 1008 +#define LM85_SYSCTL_TEMP1 1009 +#define LM85_SYSCTL_TEMP2 1010 +#define LM85_SYSCTL_TEMP3 1011 +#define LM85_SYSCTL_VID 1012 +#define LM85_SYSCTL_ALARMS 1013 +#define LM85_SYSCTL_PWM1 1014 +#define LM85_SYSCTL_PWM2 1015 +#define LM85_SYSCTL_PWM3 1016 +#define LM85_SYSCTL_VRM 1017 +#define LM85_SYSCTL_PWM_CFG1 1019 +#define LM85_SYSCTL_PWM_CFG2 1020 +#define LM85_SYSCTL_PWM_CFG3 1021 +#define LM85_SYSCTL_PWM_ZONE1 1022 +#define LM85_SYSCTL_PWM_ZONE2 1023 +#define LM85_SYSCTL_PWM_ZONE3 1024 +#define LM85_SYSCTL_ZONE1 1025 +#define LM85_SYSCTL_ZONE2 1026 +#define LM85_SYSCTL_ZONE3 1027 +#define LM85_SYSCTL_SMOOTH1 1028 +#define LM85_SYSCTL_SMOOTH2 1029 +#define LM85_SYSCTL_SMOOTH3 1030 + +/* Vendor specific values */ +#define LM85_SYSCTL_SPINUP_CTL 1100 +#define LM85_SYSCTL_TACH_MODE 1101 + +/* Analog Devices variant of the LM85 */ +#define ADM1027_SYSCTL_TACH_MODE 1200 +#define ADM1027_SYSCTL_TEMP_OFFSET1 1201 +#define ADM1027_SYSCTL_TEMP_OFFSET2 1202 +#define ADM1027_SYSCTL_TEMP_OFFSET3 1203 +#define ADM1027_SYSCTL_FAN_PPR 1204 +#define ADM1027_SYSCTL_ALARM_MASK 1205 + +/* Analog Devices variant of the LM85/ADM1027 */ +#define ADT7463_SYSCTL_TMIN_CTL1 1300 +#define ADT7463_SYSCTL_TMIN_CTL2 1301 +#define ADT7463_SYSCTL_TMIN_CTL3 1302 +#define ADT7463_SYSCTL_THERM_SIGNAL 1303 + +/* SMSC variant of the LM85 */ +#define EMC6D100_SYSCTL_IN5 1400 +#define EMC6D100_SYSCTL_IN6 1401 +#define EMC6D100_SYSCTL_IN7 1402 + +#define LM85_ALARM_IN0 0x0001 +#define LM85_ALARM_IN1 0x0002 +#define LM85_ALARM_IN2 0x0004 +#define LM85_ALARM_IN3 0x0008 +#define LM85_ALARM_TEMP1 0x0010 +#define LM85_ALARM_TEMP2 0x0020 +#define LM85_ALARM_TEMP3 0x0040 +#define LM85_ALARM_ALARM2 0x0080 +#define LM85_ALARM_IN4 0x0100 +#define LM85_ALARM_RESERVED 0x0200 +#define LM85_ALARM_FAN1 0x0400 +#define LM85_ALARM_FAN2 0x0800 +#define LM85_ALARM_FAN3 0x1000 +#define LM85_ALARM_FAN4 0x2000 +#define LM85_ALARM_TEMP1_FAULT 0x4000 +#define LM85_ALARM_TEMP3_FAULT 0x08000 +#define LM85_ALARM_IN6 0x10000 +#define LM85_ALARM_IN7 0x20000 +#define LM85_ALARM_IN5 0x40000 +/* -- SENSORS SYSCTL END -- */ + +/* The /proc/sys entries */ +/* These files are created for each detected LM85. This is just a template; + * The actual list is built from this and additional per-chip + * custom lists below. Note the XXX_LEN macros. These must be + * compile time constants because they will be used to allocate + * space for the final template passed to i2c_register_entry. + * We depend on the ability of GCC to evaluate expressions at + * compile time to turn these expressions into compile time + * constants, but this can generate a warning. + */ +static ctl_table lm85_common[] = { + {LM85_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_in}, + {LM85_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_in}, + {LM85_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_in}, + {LM85_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_in}, + {LM85_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_in}, + {LM85_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_fan}, + {LM85_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_fan}, + {LM85_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_fan}, + {LM85_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_fan}, + {LM85_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_temp}, + {LM85_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_temp}, + {LM85_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_temp}, + {LM85_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_vid}, + {LM85_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_vrm}, + {LM85_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_alarms}, + {LM85_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_pwm}, + {LM85_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_pwm}, + {LM85_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_pwm}, + {LM85_SYSCTL_PWM_CFG1, "pwm1_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_pwm_config}, + {LM85_SYSCTL_PWM_CFG2, "pwm2_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_pwm_config}, + {LM85_SYSCTL_PWM_CFG3, "pwm3_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_pwm_config}, + {LM85_SYSCTL_PWM_ZONE1, "pwm1_zone", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, + {LM85_SYSCTL_PWM_ZONE2, "pwm2_zone", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, + {LM85_SYSCTL_PWM_ZONE3, "pwm3_zone", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, + {LM85_SYSCTL_ZONE1, "zone1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_zone}, + {LM85_SYSCTL_ZONE2, "zone2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_zone}, + {LM85_SYSCTL_ZONE3, "zone3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_zone}, + {LM85_SYSCTL_SMOOTH1, "smooth1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_smooth}, + {LM85_SYSCTL_SMOOTH2, "smooth2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_smooth}, + {LM85_SYSCTL_SMOOTH3, "smooth3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm85_smooth}, + {0} +}; +#define CTLTBL_COMMON (sizeof(lm85_common)/sizeof(lm85_common[0])) + +/* NOTE: tach_mode is a shared name, but implemented with + * different functions + */ +static ctl_table lm85_specific[] = { + {LM85_SYSCTL_SPINUP_CTL, "spinup_ctl", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_spinup_ctl}, + {LM85_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_tach_mode}, +/* {0} The doc generator needs this. */ +}; +#define CTLTBL_LM85 (sizeof(lm85_specific)/sizeof(lm85_specific[0])) + +static ctl_table adm1027_specific[] = { + {ADM1027_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_tach_mode}, + {ADM1027_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, + {ADM1027_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, + {ADM1027_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, + {ADM1027_SYSCTL_FAN_PPR, "fan_ppr", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_fan_ppr}, + {ADM1027_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_alarm_mask}, +/* {0} The doc generator needs this. */ +}; +#define CTLTBL_ADM1027 (sizeof(adm1027_specific)/sizeof(adm1027_specific[0])) + +static ctl_table adt7463_specific[] = { + {ADT7463_SYSCTL_TMIN_CTL1, "tmin_ctl1", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, + {ADT7463_SYSCTL_TMIN_CTL2, "tmin_ctl2", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, + {ADT7463_SYSCTL_TMIN_CTL3, "tmin_ctl3", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, + {ADT7463_SYSCTL_THERM_SIGNAL, "therm_signal", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_therm_signal}, +/* {0} The doc generator needs this. */ +}; +#define CTLTBL_ADT7463 (sizeof(adt7463_specific)/sizeof(adt7463_specific[0])) + +static ctl_table emc6d100_specific[] = { + {EMC6D100_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &emc6d100_in}, + {EMC6D100_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &emc6d100_in}, + {EMC6D100_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &emc6d100_in}, +/* {0} The doc generator needs this. */ +}; +#define CTLTBL_EMC6D100 (sizeof(emc6d100_specific)/sizeof(emc6d100_specific[0])) + + +#define MAX2(a,b) ((a)>(b)?(a):(b)) +#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c))) +#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d))) + +#define CTLTBL_MAX (CTLTBL_COMMON + MAX3(CTLTBL_LM85, CTLTBL_ADM1027+CTLTBL_ADT7463, CTLTBL_EMC6D100)) + +/* This function is called when: + * lm85_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and lm85_driver is still present) */ +int lm85_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, lm85_detect); +} + +/* This function is called by i2c_detect */ +int lm85_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i; + int company, verstep ; + struct i2c_client *new_client; + struct lm85_data *data; + int err = 0; + const char *type_name = ""; + struct ctl_table template[CTLTBL_MAX] ; + int template_used ; + + if (i2c_is_isa_adapter(adapter)) { + /* This chip has no ISA interface */ + goto ERROR0 ; + }; + + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + /* We need to be able to do byte I/O */ + goto ERROR0 ; + }; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm85_{read,write}_value. */ + + if (!(new_client = kmalloc((sizeof(struct i2c_client)) + + sizeof(struct lm85_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + data = (struct lm85_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &lm85_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + company = lm85_read_value(new_client, LM85_REG_COMPANY); + verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); + +#ifdef DEBUG + printk("lm85: Detecting device at %d,0x%02x with" + " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", + i2c_adapter_id(new_client->adapter), new_client->addr, + company, verstep + ); +#endif + + /* If auto-detecting, Determine the chip type. */ + if (kind <= 0) { +#ifdef DEBUG + printk("lm85: Autodetecting device at %d,0x%02x ...\n", + i2c_adapter_id(adapter), address ); +#endif + if( company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85C ) { + kind = lm85c ; + } else if( company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85B ) { + kind = lm85b ; + } else if( company == LM85_COMPANY_NATIONAL + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + printk("lm85: Detected National Semiconductor chip\n"); + printk("lm85: Unrecgonized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && verstep == LM85_VERSTEP_ADM1027 ) { + kind = adm1027 ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && verstep == LM85_VERSTEP_ADT7463 ) { + kind = adt7463 ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + printk("lm85: Detected Analog Devices chip\n"); + printk("lm85: Unrecgonized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( company == LM85_COMPANY_SMSC + && (verstep == LM85_VERSTEP_EMC6D100_A0 + || verstep == LM85_VERSTEP_EMC6D100_A1) ) { + /* Unfortunately, we can't tell a '100 from a '101 + * from the registers. Since a '101 is a '100 + * in a package with fewer pins and therefore no + * 3.3V, 1.5V or 1.8V inputs, perhaps if those + * inputs read 0, then it's a '101. + */ + kind = emc6d100 ; + } else if( company == LM85_COMPANY_SMSC + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + printk("lm85: Detected SMSC chip\n"); + printk("lm85: Unrecognized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( kind == any_chip + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + printk("lm85: Generic LM85 Version 6 detected\n"); + /* Leave kind as "any_chip" */ + } else { +#ifdef DEBUG + printk("lm85: Autodetection failed\n"); +#endif + /* Not an LM85 ... */ + if( kind == any_chip ) { /* User used force=x,y */ + printk("lm85: Generic LM85 Version 6 not" + " found at %d,0x%02x. Try force_lm85c.\n", + i2c_adapter_id(adapter), address ); + } + err = 0 ; + goto ERROR1; + } + } + + /* Fill in the chip specific driver values */ + switch (kind) { + case any_chip : + type_name = "lm85"; + strcpy(new_client->name, "Generic LM85"); + template_used = 0 ; + break ; + case lm85b : + type_name = "lm85b"; + strcpy(new_client->name, "National LM85-B"); + memcpy( template, lm85_specific, sizeof(lm85_specific) ); + template_used = CTLTBL_LM85 ; + break ; + case lm85c : + type_name = "lm85c"; + strcpy(new_client->name, "National LM85-C"); + memcpy( template, lm85_specific, sizeof(lm85_specific) ); + template_used = CTLTBL_LM85 ; + break ; + case adm1027 : + type_name = "adm1027"; + strcpy(new_client->name, "Analog Devices ADM1027"); + memcpy( template, adm1027_specific, sizeof(adm1027_specific) ); + template_used = CTLTBL_ADM1027 ; + break ; + case adt7463 : + type_name = "adt7463"; + strcpy(new_client->name, "Analog Devices ADT7463"); + memcpy( template, adt7463_specific, sizeof(adt7463_specific) ); + template_used = CTLTBL_ADT7463 ; + memcpy( template+template_used, adm1027_specific, sizeof(adm1027_specific) ); + template_used += CTLTBL_ADM1027 ; + break ; + case emc6d100 : + type_name = "emc6d100"; + strcpy(new_client->name, "SMSC EMC6D100"); + memcpy(template, emc6d100_specific, sizeof(emc6d100_specific)); + template_used = CTLTBL_EMC6D100 ; + break ; + default : + printk("lm85: Internal error, invalid kind (%d)!", kind); + err = -EFAULT ; + goto ERROR1; + } + + /* Fill in the remaining client fields */ + new_client->id = lm85_id++; + printk("lm85: Assigning ID %d to %s at %d,0x%02x\n", + new_client->id, new_client->name, + i2c_adapter_id(new_client->adapter), + new_client->addr + ); + + /* Housekeeping values */ + data->type = kind; + data->valid = 0; + + /* Set the VRM version */ + data->vrm = LM85_INIT_VRM ; + + /* Zero the accumulators */ + data->therm_total = 0; + data->therm_ovfl = 0; + + init_MUTEX(&data->update_lock); + + /* Initialize the LM85 chip */ + lm85_init_client(new_client); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR1; + + /* Finish out the template */ + memcpy( template + template_used, lm85_common, sizeof(lm85_common) ); + + /* Register a new directory entry with module sensors */ + if ((i = i2c_register_entry(new_client, + type_name, + template)) < 0) { + err = i; + goto ERROR2; + } + data->sysctl_id = i; + + return 0; + + /* Error out and cleanup code */ + ERROR2: + i2c_detach_client(new_client); + ERROR1: + kfree(new_client); + ERROR0: + return err; +} + +int lm85_detach_client(struct i2c_client *client) +{ + int err; + int id ; + + id = client->id; + i2c_deregister_entry(((struct lm85_data *)(client->data))->sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk("lm85(%d): Client deregistration failed," + " client not detached.\n", id ); + return err; + } + + kfree(client); + + return 0; +} + +int lm85_read_value(struct i2c_client *client, u16 reg) +{ + int res; + + /* What size location is it? */ + switch( reg ) { + case LM85_REG_FAN(0) : /* Read WORD data */ + case LM85_REG_FAN(1) : + case LM85_REG_FAN(2) : + case LM85_REG_FAN(3) : + case LM85_REG_FAN_MIN(0) : + case LM85_REG_FAN_MIN(1) : + case LM85_REG_FAN_MIN(2) : + case LM85_REG_FAN_MIN(3) : + case LM85_REG_ALARM : /* Read ALARM1 and ALARM2 */ + case ADM1027_REG_INTMASK : /* Read MASK1 and MASK2 */ + case ADM1027_REG_EXTEND_ADC : /* Read ADC1 and ADC2 */ + reg &= 0xff ; /* Pseudo words have address + 0x0100 */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff ; + res |= (i2c_smbus_read_byte_data(client, reg+1) & 0xff) << 8 ; + break ; + case ADT7463_REG_TMIN_CTL : /* Read WORD MSB, LSB */ + reg &= 0xff ; /* Pseudo words have address + 0x0100 */ + res = (i2c_smbus_read_byte_data(client, reg) & 0xff) << 8 ; + res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; + break ; + default: /* Read BYTE data */ + res = i2c_smbus_read_byte_data(client, reg & 0xff) & 0xff ; + break ; + } + + return res ; +} + +int lm85_write_value(struct i2c_client *client, u16 reg, int value) +{ + int res ; + + switch( reg ) { + case LM85_REG_FAN(0) : /* Write WORD data */ + case LM85_REG_FAN(1) : + case LM85_REG_FAN(2) : + case LM85_REG_FAN(3) : + case LM85_REG_FAN_MIN(0) : + case LM85_REG_FAN_MIN(1) : + case LM85_REG_FAN_MIN(2) : + case LM85_REG_FAN_MIN(3) : + case ADM1027_REG_INTMASK : + /* NOTE: ALARM and ADC are read only, so not included here */ + reg &= 0xff ; /* Pseudo words have address + 0x0100 */ + res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; + res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; + break ; + case ADT7463_REG_TMIN_CTL : /* Write WORD MSB, LSB */ + reg &= 0xff ; /* Pseudo words have address + 0x0100 */ + res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); + res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; + break ; + default: /* Write BYTE data */ + res = i2c_smbus_write_byte_data(client, reg & 0xff, value); + break ; + } + + return res ; +} + +/* Called when we have found a new LM85. It should set limits, etc. */ +void lm85_init_client(struct i2c_client *client) +{ + int value; + struct lm85_data *data = client->data; + +#ifdef DEBUG + printk("lm85(%d): Initializing device\n", client->id); +#endif + + /* Warn if part was not "READY" */ + value = lm85_read_value(client, LM85_REG_CONFIG); +#ifdef DEBUG + printk("lm85(%d): LM85_REG_CONFIG is: 0x%02x\n", client->id, value ); +#endif + if( value & 0x02 ) { + printk("lm85(%d): Client (%d,0x%02x) config is locked.\n", + client->id, + i2c_adapter_id(client->adapter), client->addr ); + }; + if( ! (value & 0x04) ) { + printk("lm85(%d): Client (%d,0x%02x) is not ready.\n", + client->id, + i2c_adapter_id(client->adapter), client->addr ); + }; + if( (data->type == adm1027 || data->type == adt7463) + && (value & 0x10) + ) { + printk("lm85(%d): Client (%d,0x%02x) VxI mode is set. " + "Please report this to the lm85 maintainer.\n", + client->id, + i2c_adapter_id(client->adapter), client->addr ); + }; + + /* See if SYNC to PWM3 is set */ + if( data->type == adt7463 + && (lm85_read_value(client, LM85_REG_AFAN_SPIKE1) & 0x10) + ) { + printk("lm85(%d): Sync to PWM3 is set. Expect PWM3 " + "to control fans 2, 3, and 4\n", + client->id ); + }; + + /* See if PWM2 is #SMBALERT */ + if( (data->type == adm1027 || data->type == adt7463) + && (lm85_read_value(client, ADM1027_REG_CONFIG3) & 0x01) + ) { + printk("lm85(%d): PWM2 is SMBALERT. PWM2 not available.\n", + client->id ); + }; + + /* Check if 2.5V and 5V inputs are reconfigured */ + if( data->type == adt7463 ) { + value = lm85_read_value(client, ADT7463_REG_CONFIG4); + if( value & 0x01 ) { + printk("lm85(%d): 2.5V input (in0) is SMBALERT. " + "in0 not available.\n", client->id ); + }; + if( value & 0x02 ) { + printk("lm85(%d): 5V input (in3) is THERM. " + "in3 not available.\n", client->id ); + } + }; + + /* FIXME? Display EMC6D100 config info? */ + + /* WE INTENTIONALLY make no changes to the limits, + * offsets, pwms, fans and zones. If they were + * configured, we don't want to mess with them. + * If they weren't, the default is 100% PWM, no + * control and will suffice until 'sensors -s' + * can be run by the user. + */ + + /* Start monitoring */ + value = lm85_read_value(client, LM85_REG_CONFIG); + /* Try to clear LOCK, Set START, save everything else */ + value = ((value & ~ 0x02) | 0x01) & 0xff ; +#ifdef DEBUG + printk("lm85(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); +#endif + lm85_write_value(client, LM85_REG_CONFIG, value); + +} + +void lm85_update_client(struct i2c_client *client) +{ + struct lm85_data *data = client->data; + int i; + + down(&data->update_lock); + + if (!data->valid + || (jiffies - data->last_reading > LM85_DATA_INTERVAL )) { + /* Things that change quickly */ + +#ifdef DEBUG + printk("lm85(%d): Reading sensor values\n", client->id); +#endif + /* Have to read extended bits first to "freeze" the + * more significant bits that are read later. + */ + switch( data->type ) { + case adm1027 : + case adt7463 : + data->extend_adc = + lm85_read_value(client, ADM1027_REG_EXTEND_ADC); + break ; + default : + data->extend_adc = 0 ; + break ; + } + + for (i = 0; i <= 4; ++i) { + data->in[i] = + lm85_read_value(client, LM85_REG_IN(i)); + } + + for (i = 0; i <= 3; ++i) { + data->fan[i] = + lm85_read_value(client, LM85_REG_FAN(i)); + } + + for (i = 0; i <= 2; ++i) { + data->temp[i] = + lm85_read_value(client, LM85_REG_TEMP(i)); + } + + for (i = 0; i <= 2; ++i) { + data->pwm[i] = + lm85_read_value(client, LM85_REG_PWM(i)); + } + + data->alarms = lm85_read_value(client, LM85_REG_ALARM); + + switch( ((struct lm85_data *)(client->data))->type ) { + case adt7463 : + /* REG_THERM code duplicated in therm_signal() */ + i = lm85_read_value(client, ADT7463_REG_THERM); + if( data->therm_total < LONG_MAX - 256 ) { + data->therm_total += i ; + } + if( i >= 255 ) { + ++data->therm_ovfl ; + } + break ; + case emc6d100 : + /* Three more voltage sensors */ + for (i = 5; i <= 7; ++i) { + data->in[i] = + lm85_read_value(client, EMC6D100_REG_IN(i)); + } + /* More alarm bits */ + data->alarms |= + lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; + + break ; + default : break ; /* no warnings */ + } + + data->last_reading = jiffies ; + }; /* last_reading */ + + if (!data->valid + || (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) { + /* Things that don't change often */ + +#ifdef DEBUG + printk("lm85(%d): Reading config values\n", client->id); +#endif + for (i = 0; i <= 4; ++i) { + data->in_min[i] = + lm85_read_value(client, LM85_REG_IN_MIN(i)); + data->in_max[i] = + lm85_read_value(client, LM85_REG_IN_MAX(i)); + } + + for (i = 0; i <= 3; ++i) { + data->fan_min[i] = + lm85_read_value(client, LM85_REG_FAN_MIN(i)); + } + + for (i = 0; i <= 2; ++i) { + data->temp_min[i] = + lm85_read_value(client, LM85_REG_TEMP_MIN(i)); + data->temp_max[i] = + lm85_read_value(client, LM85_REG_TEMP_MAX(i)); + } + + data->vid = lm85_read_value(client, LM85_REG_VID); + + for (i = 0; i <= 2; ++i) { + int val ; + data->autofan[i].config = + lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); + val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); + data->autofan[i].freq = val & 0x07 ; + data->zone[i].range = (val >> 4) & 0x0f ; + data->autofan[i].min_pwm = + lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); + data->zone[i].limit = + lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); + data->zone[i].critical = + lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); + } + + i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); + data->smooth[0] = i & 0x0f ; + data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ + data->autofan[0].min_off = i & 0x20 ; + data->autofan[1].min_off = i & 0x40 ; + data->autofan[2].min_off = i & 0x80 ; + i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); + data->smooth[1] = (i>>4) & 0x0f ; + data->smooth[2] = i & 0x0f ; + + i = lm85_read_value(client, LM85_REG_AFAN_HYST1); + data->zone[0].hyst = (i>>4) & 0x0f ; + data->zone[1].hyst = i & 0x0f ; + + i = lm85_read_value(client, LM85_REG_AFAN_HYST2); + data->zone[2].hyst = (i>>4) & 0x0f ; + + switch( ((struct lm85_data *)(client->data))->type ) { + case lm85b : + case lm85c : + data->tach_mode = lm85_read_value(client, + LM85_REG_TACH_MODE ); + data->spinup_ctl = lm85_read_value(client, + LM85_REG_SPINUP_CTL ); + break ; + case adt7463 : + for (i = 0; i <= 2; ++i) { + data->oppoint[i] = lm85_read_value(client, + ADT7463_REG_OPPOINT(i) ); + } + data->tmin_ctl = lm85_read_value(client, + ADT7463_REG_TMIN_CTL ); + data->therm_limit = lm85_read_value(client, + ADT7463_REG_THERM_LIMIT ); + /* FALL THROUGH */ + case adm1027 : + for (i = 0; i <= 2; ++i) { + data->temp_offset[i] = lm85_read_value(client, + ADM1027_REG_TEMP_OFFSET(i) ); + } + data->tach_mode = lm85_read_value(client, + ADM1027_REG_CONFIG3 ); + data->fan_ppr = lm85_read_value(client, + ADM1027_REG_FAN_PPR ); + data->alarm_mask = lm85_read_value(client, + ADM1027_REG_INTMASK ); + break ; + case emc6d100 : + for (i = 5; i <= 7; ++i) { + data->in_min[i] = + lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); + data->in_max[i] = + lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); + } + break ; + default : break ; /* no warnings */ + } + + data->last_config = jiffies; + }; /* last_config */ + + data->valid = 1; + + up(&data->update_lock); +} + + +/* The next functions are the call-back functions of the /proc/sys and + sysctl files. Which function is used is defined in the ctl_table in + the extra1 field. + Each function must return the magnitude (power of 10 to divide the data + with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must + put a maximum of *nrels elements in results reflecting the data of this + file, and set *nrels to the number it actually put in it, if operation== + SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from + results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. + */ +void lm85_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_IN0; + + if (nr < 0 || nr > 4) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; /* 1.000 */ + else if (operation == SENSORS_PROC_REAL_READ) { + int ext = 0 ; + lm85_update_client(client); + ext = EXT_FROM_REG(data->extend_adc, nr); + results[0] = INS_FROM_REG(nr,data->in_min[nr]); + results[1] = INS_FROM_REG(nr,data->in_max[nr]); + results[2] = INSEXT_FROM_REG(nr,data->in[nr],ext); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->in_max[nr] = INS_TO_REG(nr,results[1]); + lm85_write_value(client, LM85_REG_IN_MAX(nr), + data->in_max[nr]); + } + if (*nrels_mag > 0) { + data->in_min[nr] = INS_TO_REG(nr,results[0]); + lm85_write_value(client, LM85_REG_IN_MIN(nr), + data->in_min[nr]); + } + up(&data->update_lock); + } +} + +void lm85_fan(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_FAN1 ; + + if (nr < 0 || nr > 3) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = FAN_FROM_REG(data->fan_min[nr]); + results[1] = FAN_FROM_REG(data->fan[nr]); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->fan_min[nr] = FAN_TO_REG(results[0]); + lm85_write_value(client, LM85_REG_FAN_MIN(nr), + data->fan_min[nr]); + } + up(&data->update_lock); + } +} + + +void lm85_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_TEMP1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + int ext = 0 ; + lm85_update_client(client); + + /* +5 for offset of temp data in ext reg */ + ext = EXT_FROM_REG(data->extend_adc, nr+5); + + results[0] = TEMP_FROM_REG(data->temp_min[nr]); + results[1] = TEMP_FROM_REG(data->temp_max[nr]); + results[2] = TEMPEXT_FROM_REG(data->temp[nr],ext); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->temp_max[nr] = TEMP_TO_REG(results[1]); + lm85_write_value(client, LM85_REG_TEMP_MAX(nr), + data->temp_max[nr]); + } + if (*nrels_mag > 0) { + data->temp_min[nr] = TEMP_TO_REG(results[0]); + lm85_write_value(client, LM85_REG_TEMP_MIN(nr), + data->temp_min[nr]); + } + up(&data->update_lock); + } +} + +void lm85_pwm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_PWM1 ; + int pwm_zone ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = PWM_FROM_REG(data->pwm[nr]); + pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); + /* PWM "enabled" if not off (0) nor on (-1) */ + results[1] = pwm_zone != 0 && pwm_zone != -1 ; + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + /* PWM enable is read-only */ + if (*nrels_mag > 0) { + data->pwm[nr] = PWM_TO_REG(results[0]); + lm85_write_value(client, LM85_REG_PWM(nr), + data->pwm[nr]); + } + up(&data->update_lock); + } +} + +void lm85_vid(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + + if( ctl_name != LM85_SYSCTL_VID ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = VID_FROM_REG((data->vid)&0x3f,data->vrm); + *nrels_mag = 1; + } +} + +void lm85_vrm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + + if( ctl_name != LM85_SYSCTL_VRM ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + results[0] = data->vrm ; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->vrm = results[0] ; + } + up(&data->update_lock); + } +} + +void lm85_alarms(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + + if( ctl_name != LM85_SYSCTL_ALARMS ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = ALARMS_FROM_REG(data->alarms); + *nrels_mag = 1; + } +} + +void lm85_spinup_ctl(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int old; + + if( ctl_name != LM85_SYSCTL_SPINUP_CTL ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = (data->spinup_ctl & 1) != 0 ; + results[1] = (data->spinup_ctl & 2) != 0 ; + results[2] = (data->spinup_ctl & 4) != 0 ; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + old = data->spinup_ctl ; + if (*nrels_mag > 2) { + old = (old & (~4)) | (results[2]?4:0) ; + } + if (*nrels_mag > 1) { + old = (old & (~2)) | (results[1]?2:0) ; + } + if (*nrels_mag > 0) { + old = (old & (~1)) | (results[0]?1:0) ; + lm85_write_value(client, LM85_REG_SPINUP_CTL, old); + data->spinup_ctl = old ; + } + up(&data->update_lock); + } +} + +void lm85_tach_mode(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int old; + + /* Tach Mode 1, Tach Mode 2, Tach Mode 3 & 4 */ + + if( ctl_name != LM85_SYSCTL_TACH_MODE ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = (data->tach_mode & 0x03) ; + results[1] = (data->tach_mode & 0x0c) >> 2 ; + results[2] = (data->tach_mode & 0x30) >> 4 ; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + old = data->tach_mode ; + if (*nrels_mag > 2) { + old = (old & (~0x30)) | ((results[2]&3) << 4) ; + } + if (*nrels_mag > 1) { + old = (old & (~0x0c)) | ((results[1]&3) << 2) ; + } + if (*nrels_mag > 0) { + old = (old & (~0x03)) | (results[0]&3) ; + lm85_write_value(client, LM85_REG_TACH_MODE, old); + data->tach_mode = old ; + } + up(&data->update_lock); + } +} + +void adm1027_tach_mode(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int old; + + /* Tach/DC 1, Tach/DC 2, Tach/DC 3, Tach/DC 4 */ + + if( ctl_name != ADM1027_SYSCTL_TACH_MODE ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = (data->tach_mode & 0x10) != 0 ; + results[1] = (data->tach_mode & 0x20) != 0 ; + results[2] = (data->tach_mode & 0x40) != 0 ; + results[3] = (data->tach_mode & 0x80) != 0 ; + *nrels_mag = 4; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + old = data->tach_mode ; + if (*nrels_mag > 3) { + old = (old & (~0x80)) | (results[3] ? 0x80 : 0) ; + } + if (*nrels_mag > 2) { + old = (old & (~0x40)) | (results[2] ? 0x40 : 0) ; + } + if (*nrels_mag > 1) { + old = (old & (~0x20)) | (results[1] ? 0x20 : 0) ; + } + if (*nrels_mag > 0) { + old = (old & (~0x10)) | (results[0] ? 0x10 : 0) ; + + /* Enable fast measurements if any TACH's are DC */ + old = (old & (~0x08)) | ((old&0xf0) ? 0x08 : 0) ; + + lm85_write_value(client, ADM1027_REG_CONFIG3, old); + data->tach_mode = old ; + } + up(&data->update_lock); + } +} + +void lm85_pwm_config(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_PWM_CFG1 ; + + /* Spinup, min PWM, PWM Frequency, min below limit, Invert */ + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + + results[0] = SPINUP_FROM_REG(data->autofan[nr].config); + results[1] = PWM_FROM_REG(data->autofan[nr].min_pwm)*10; + results[2] = FREQ_FROM_REG(data->autofan[nr].freq); + results[3] = data->autofan[nr].min_off ? 10 : 0 ; + results[4] = (data->autofan[nr].config & 0x10) ? 10 : 0 ; + *nrels_mag = 5; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + int old_config ; + + down(&data->update_lock); + old_config = data->autofan[nr].config ; + if (*nrels_mag > 4) { + old_config = (old_config & (~0x10)) | (results[4]?0x10:0) ; + } + if (*nrels_mag > 3) { + data->autofan[nr].min_off = results[3] != 0 ; + lm85_write_value(client, LM85_REG_AFAN_SPIKE1, + data->smooth[0] + | data->syncpwm3 + | (data->autofan[0].min_off ? 0x20 : 0) + | (data->autofan[1].min_off ? 0x40 : 0) + | (data->autofan[2].min_off ? 0x80 : 0) + ); + } + if (*nrels_mag > 2) { + data->autofan[nr].freq = FREQ_TO_REG(results[2]) ; + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + (data->zone[nr].range << 4) + | data->autofan[nr].freq + ); + } + if (*nrels_mag > 1) { + data->autofan[nr].min_pwm = PWM_TO_REG((results[1]+5)/10); + lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), + data->autofan[nr].min_pwm + ); + } + if (*nrels_mag > 0) { + old_config = (old_config & (~0x07)) | SPINUP_TO_REG(results[0]) ; + lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), old_config); + data->autofan[nr].config = old_config ; + } + up(&data->update_lock); + } +} + +void lm85_smooth(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_SMOOTH1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = SMOOTH_FROM_REG(data->smooth[nr]); + *nrels_mag = 1; + + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if( *nrels_mag > 0 ) { + data->smooth[nr] = SMOOTH_TO_REG(results[0]); + } + if( nr == 0 ) { + lm85_write_value(client, LM85_REG_AFAN_SPIKE1, + data->smooth[0] + | data->syncpwm3 + | (data->autofan[0].min_off ? 0x20 : 0) + | (data->autofan[1].min_off ? 0x40 : 0) + | (data->autofan[2].min_off ? 0x80 : 0) + ); + } else { + lm85_write_value(client, LM85_REG_AFAN_SPIKE2, + (data->smooth[1] << 4) | data->smooth[2]); + } + up(&data->update_lock); + } +} + +void lm85_zone(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_ZONE1 ; + + /* Limit, Hysteresis (neg), Range, Critical */ + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + + results[0] = TEMP_FROM_REG(data->zone[nr].limit) / 10; + results[1] = HYST_FROM_REG(data->zone[nr].hyst); + results[2] = RANGE_FROM_REG(data->zone[nr].range); + results[3] = TEMP_FROM_REG(data->zone[nr].critical) / 10; + *nrels_mag = 4; + + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 3) { + data->zone[nr].critical = TEMP_TO_REG(results[3]*10); + lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), + data->zone[nr].critical ); + } + if (*nrels_mag > 2) { + data->zone[nr].range = RANGE_TO_REG(results[2]); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + (data->zone[nr].range << 4) + | data->autofan[nr].freq + ); + } + if (*nrels_mag > 1) { + data->zone[nr].hyst = HYST_TO_REG(results[1]); + if( nr == 0 || nr == 1 ) { + lm85_write_value(client, LM85_REG_AFAN_HYST1, + (data->zone[0].hyst << 4) + | data->zone[1].hyst + ); + } else { + lm85_write_value(client, LM85_REG_AFAN_HYST2, + (data->zone[2].hyst << 4) + ); + } + } + if (*nrels_mag > 0) { + data->zone[nr].limit = TEMP_TO_REG(results[0]*10); + lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), + data->zone[nr].limit + ); + } + up(&data->update_lock); + } +} + +void lm85_pwm_zone(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - LM85_SYSCTL_PWM_ZONE1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = ZONE_FROM_REG(data->autofan[nr].config); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->autofan[nr].config = + (data->autofan[nr].config & (~0xe0)) + | ZONE_TO_REG(results[0]) ; + lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), + data->autofan[nr].config); + } + up(&data->update_lock); + } +} + +void adm1027_temp_offset(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - ADM1027_SYSCTL_TEMP_OFFSET1 ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + switch( data->type ) { + case adm1027 : + default : + results[0] = TEMP_FROM_REG(data->temp_offset[nr]); + break ; + case adt7463 : + results[0] = TEMPEXT_FROM_REG(0,data->temp_offset[nr]); + break ; + } + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + switch( data->type ) { + case adm1027 : + default : + data->temp_offset[nr] = TEMP_TO_REG(results[0]); + break ; + case adt7463 : + data->temp_offset[nr] = EXTTEMP_TO_REG(results[0]); + break ; + }; + lm85_write_value(client, ADM1027_REG_TEMP_OFFSET(nr), + data->temp_offset[nr]); + } + up(&data->update_lock); + } +} + +void adm1027_fan_ppr(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int old ; + + if (ctl_name != ADM1027_SYSCTL_FAN_PPR) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = PPR_FROM_REG(data->fan_ppr,0); + results[1] = PPR_FROM_REG(data->fan_ppr,1); + results[2] = PPR_FROM_REG(data->fan_ppr,2); + results[3] = PPR_FROM_REG(data->fan_ppr,3); + *nrels_mag = 4; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + old = data->fan_ppr ; + if (*nrels_mag > 3) { + old = (old & ~PPR_MASK(3)) | PPR_TO_REG(results[3],3); + }; + if (*nrels_mag > 2) { + old = (old & ~PPR_MASK(2)) | PPR_TO_REG(results[2],2); + }; + if (*nrels_mag > 1) { + old = (old & ~PPR_MASK(1)) | PPR_TO_REG(results[1],1); + }; + if (*nrels_mag > 0) { + old = (old & ~PPR_MASK(0)) | PPR_TO_REG(results[0],0); + lm85_write_value(client, ADM1027_REG_FAN_PPR, old); + data->fan_ppr = old ; + } + up(&data->update_lock); + } +} + +void adm1027_alarm_mask(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + + if( ctl_name != ADM1027_SYSCTL_ALARM_MASK ) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = INTMASK_FROM_REG(data->alarm_mask); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 0) { + data->alarm_mask = INTMASK_TO_REG(results[0]); + lm85_write_value(client, ADM1027_REG_INTMASK, + data->alarm_mask); + } + up(&data->update_lock); + } +} + +void adt7463_tmin_ctl(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - ADT7463_SYSCTL_TMIN_CTL1 ; + u16 old ; + + if (nr < 0 || nr > 2) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + old = data->tmin_ctl ; + results[0] = (old & ( 0x2000 << nr )) != 0 ; + results[1] = (old >> (nr*3)) & 0x07 ; + results[2] = (old & ( 0x0400 << nr )) != 0 ; + results[3] = OPPOINT_FROM_REG(data->oppoint[nr]); + *nrels_mag = 4; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + old = data->tmin_ctl ; + if (*nrels_mag > 3) { + data->oppoint[nr] = OPPOINT_TO_REG(results[3]); + lm85_write_value(client, ADT7463_REG_OPPOINT(nr), + data->oppoint[nr]); + }; + if (*nrels_mag > 2) { + if( results[2] ) { + old |= (0x0400 << nr) ; + } else { + old &= ~(0x0400 << nr) ; + } + }; + if (*nrels_mag > 1) { + old &= ~(0x07 << (nr*3)) ; + old |= (results[1] & 0x07) << (nr*3) ; + }; + if (*nrels_mag > 0) { + if( results[0] ) { + old |= 0x2000 << nr ; + } else { + old &= ~(0x2000 << nr) ; + } + lm85_write_value(client, ADT7463_REG_TMIN_CTL, old); + data->tmin_ctl = old ; + } + up(&data->update_lock); + } +} + +void adt7463_therm_signal(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int counts ; + + if (ctl_name != ADT7463_SYSCTL_THERM_SIGNAL) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + /* Don't call update_client here because + * ADT7463_REG_THERM has to be read every + * 5 seconds to prevent lost counts + */ + down(&data->update_lock); + counts = lm85_read_value(client, ADT7463_REG_THERM) & 0xff; + if( data->therm_total < LONG_MAX - 256 ) { + data->therm_total += counts ; + } + if( counts >= 255 ) { + ++data->therm_ovfl ; + } + up(&data->update_lock); + + results[0] = data->therm_limit ; + results[1] = data->therm_total ; + results[2] = data->therm_ovfl ; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + /* therm_total and therm_ovfl are read only */ + if (*nrels_mag > 0) { + data->therm_limit = SENSORS_LIMIT(results[0],0,255); + lm85_write_value(client, ADT7463_REG_THERM_LIMIT, + data->therm_limit); + }; + up(&data->update_lock); + } +} + + +void emc6d100_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm85_data *data = client->data; + int nr = ctl_name - EMC6D100_SYSCTL_IN5 +5; + + if (nr < 5 || nr > 7) + return ; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; /* 1.000 */ + else if (operation == SENSORS_PROC_REAL_READ) { + lm85_update_client(client); + results[0] = INS_FROM_REG(nr,data->in_min[nr]); + results[1] = INS_FROM_REG(nr,data->in_max[nr]); + results[2] = INS_FROM_REG(nr,data->in[nr]); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag > 1) { + data->in_max[nr] = INS_TO_REG(nr,results[1]); + lm85_write_value(client, EMC6D100_REG_IN_MAX(nr), + data->in_max[nr]); + } + if (*nrels_mag > 0) { + data->in_min[nr] = INS_TO_REG(nr,results[0]); + lm85_write_value(client, EMC6D100_REG_IN_MIN(nr), + data->in_min[nr]); + } + up(&data->update_lock); + } +} + + +static int __init sm_lm85_init(void) +{ + printk("lm85: Version %s (%s)\n", LM_VERSION, LM_DATE); + printk("lm85: See http://www.penguincomputing.com/lm_sensors for more info.\n" ); + return i2c_add_driver(&lm85_driver); +} + +static void __exit sm_lm85_exit(void) +{ + i2c_del_driver(&lm85_driver); +} + +/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. + * Thanks to Margit Schubert-While for help with + * post 2.7.0 CVS changes + */ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Pokorny #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include /* Chip configuration settings. These should be set to reflect the HARDWARE configuration of your chip. By default (read: when all of @@ -72,14 +71,6 @@ Set to '1' the appropriate defines, as n them insmod params, but it would be too much work. ;') */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -172,7 +163,7 @@ SENSORS_INSMOD_1(lm87); #define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255)) #define IN_FROM_REG(val,nr) (val) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -213,11 +204,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define LM87_INIT_INT_TEMP_MAX 600 #define LM87_INIT_INT_TEMP_MIN 100 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For each registered LM87, we need to keep some data in memory. That data is pointed to by LM87_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new LM87 client is @@ -260,22 +246,10 @@ struct lm87_data { u8 vrm; /* VRM version * 10 */ }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_lm87_init(void); -static int __init lm87_cleanup(void); - static int lm87_attach_adapter(struct i2c_adapter *adapter); static int lm87_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int lm87_detach_client(struct i2c_client *client); -static int lm87_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm87_inc_use(struct i2c_client *client); -static void lm87_dec_use(struct i2c_client *client); static int lm87_read_value(struct i2c_client *client, u8 register); static int lm87_write_value(struct i2c_client *client, u8 register, @@ -312,18 +286,53 @@ static void lm87_vrm(struct i2c_client * static int lm87_id = 0; static struct i2c_driver LM87_driver = { - /* name */ "LM87 sensor driver", - /* id */ I2C_DRIVERID_LM87, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &lm87_attach_adapter, - /* detach_client */ &lm87_detach_client, - /* command */ &lm87_command, - /* inc_use */ &lm87_inc_use, - /* dec_use */ &lm87_dec_use + .owner = THIS_MODULE, + .name = "LM87 sensor driver", + .id = I2C_DRIVERID_LM87, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm87_attach_adapter, + .detach_client = lm87_detach_client, }; -/* Used by LM87_init/cleanup */ -static int __initdata lm87_initialized = 0; +/* -- SENSORS SYSCTL START -- */ +#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM87_SYSCTL_IN1 1001 +#define LM87_SYSCTL_IN2 1002 +#define LM87_SYSCTL_IN3 1003 +#define LM87_SYSCTL_IN4 1004 +#define LM87_SYSCTL_IN5 1005 +#define LM87_SYSCTL_AIN1 1006 +#define LM87_SYSCTL_AIN2 1007 +#define LM87_SYSCTL_FAN1 1102 +#define LM87_SYSCTL_FAN2 1103 +#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ +#define LM87_SYSCTL_ANALOG_OUT 2002 +#define LM87_SYSCTL_VID 2003 +#define LM87_SYSCTL_VRM 2004 + +#define LM87_ALARM_IN0 0x0001 +#define LM87_ALARM_IN1 0x0002 +#define LM87_ALARM_IN2 0x0004 +#define LM87_ALARM_IN3 0x0008 +#define LM87_ALARM_TEMP1 0x0010 +#define LM87_ALARM_TEMP2 0x0020 +#define LM87_ALARM_TEMP3 0x0020 /* same?? */ +#define LM87_ALARM_FAN1 0x0040 +#define LM87_ALARM_FAN2 0x0080 +#define LM87_ALARM_IN4 0x0100 +#define LM87_ALARM_IN5 0x0200 +#define LM87_ALARM_RESERVED1 0x0400 +#define LM87_ALARM_RESERVED2 0x0800 +#define LM87_ALARM_CHAS 0x1000 +#define LM87_ALARM_THERM_SIG 0x2000 +#define LM87_ALARM_TEMP2_FAULT 0x4000 +#define LM87_ALARM_TEMP3_FAULT 0x08000 + +/* -- SENSORS SYSCTL END -- */ /* The /proc/sys entries */ /* These files are created for each detected LM87. This is just a template; @@ -389,7 +398,7 @@ static ctl_table LM87_dir_table_template {0} }; -int lm87_attach_adapter(struct i2c_adapter *adapter) +static int lm87_attach_adapter(struct i2c_adapter *adapter) { int error; struct i2c_client_address_data lm87_client_data; @@ -465,8 +474,7 @@ static int lm87_detect(struct i2c_adapte /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - LM87_dir_table_template, - THIS_MODULE)) < 0) { + LM87_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -488,7 +496,7 @@ static int lm87_detect(struct i2c_adapte return err; } -int lm87_detach_client(struct i2c_client *client) +static int lm87_detach_client(struct i2c_client *client) { int err; @@ -507,38 +515,18 @@ int lm87_detach_client(struct i2c_client } -/* No commands defined yet */ -int lm87_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void lm87_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void lm87_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -int lm87_read_value(struct i2c_client *client, u8 reg) +static int lm87_read_value(struct i2c_client *client, u8 reg) { return 0xFF & i2c_smbus_read_byte_data(client, reg); } -int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) +static int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* Called when we have found a new LM87. It should set limits, etc. */ -void lm87_init_client(struct i2c_client *client) +static void lm87_init_client(struct i2c_client *client) { struct lm87_data *data = client->data; int vid; @@ -641,15 +629,16 @@ void lm87_init_client(struct i2c_client lm87_write_value(client, LM87_REG_CONFIG, 0x01); } -void lm87_update_client(struct i2c_client *client) +static void lm87_update_client(struct i2c_client *client) { struct lm87_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) /* 1 sec cache */ - || !data->valid) { + if ((jiffies - data->last_updated > HZ) || /* 1 sec cache */ + (jiffies < data->last_updated) || + !data->valid) { for (i = 0; i <= 5; i++) { data->in[i] = lm87_read_value(client,LM87_REG_IN(i)); @@ -1041,44 +1030,20 @@ void lm87_vrm(struct i2c_client *client, } } -int __init sensors_lm87_init(void) +static int __init sm_lm87_init(void) { - int res; - printk("lm87.o version %s (%s)\n", LM_VERSION, LM_DATE); - lm87_initialized = 0; - - if ((res = i2c_add_driver(&LM87_driver))) { - printk - ("lm87.o: Driver registration failed, module not inserted.\n"); - lm87_cleanup(); - return res; - } - lm87_initialized++; - return 0; + return i2c_add_driver(&LM87_driver); } -int __init lm87_cleanup(void) +static void __exit sm_lm87_exit(void) { - int res; - - if (lm87_initialized >= 1) { - if ((res = i2c_del_driver(&LM87_driver))) { - printk - ("lm87.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm87_initialized--; - } - return 0; + i2c_del_driver(&LM87_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE -#ifdef MODULE_LICENSE + MODULE_LICENSE("GPL"); -#endif MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , " @@ -1086,14 +1051,5 @@ MODULE_AUTHOR MODULE_DESCRIPTION("LM87 driver"); -int init_module(void) -{ - return sensors_lm87_init(); -} - -int cleanup_module(void) -{ - return lm87_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_lm87_init); +module_exit(sm_lm87_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm92.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm92.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/lm92.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/lm92.c 2003-08-17 21:26:58.000000000 +0200 @@ -18,9 +18,7 @@ */ #include -#include #include - #include #include #include @@ -29,19 +27,16 @@ #include #include #include - #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* if defined, 4 faults must occur consecutively to set alarm flags */ /* #define ENABLE_FAULT_QUEUE */ -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include - #define LM92_REG_TEMPERATURE 0x00 /* ro, 16-bit */ #define LM92_REG_CONFIGURATION 0x01 /* rw, 8-bit */ -#define LM92_REG_TRIP_HYSTERISIS 0x02 /* rw, 16-bit */ +#define LM92_REG_TRIP_HYSTERESIS 0x02 /* rw, 16-bit */ #define LM92_REG_TRIP_CRITICAL 0x03 /* rw, 16-bit */ #define LM92_REG_TRIP_LOW 0x04 /* rw, 16-bit */ #define LM92_REG_TRIP_HIGH 0x05 /* rw, 16-bit */ @@ -64,6 +59,21 @@ static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results); static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results); +/* -- SENSORS SYSCTL START -- */ +#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ +#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysteresis, input */ + +#define LM92_ALARM_TEMP_HIGH 0x01 +#define LM92_ALARM_TEMP_LOW 0x02 +#define LM92_ALARM_TEMP_CRIT 0x04 +#define LM92_TEMP_HIGH 0x08 +#define LM92_TEMP_LOW 0x10 +#define LM92_TEMP_CRIT 0x20 +#define LM92_TEMP_HYST 0x40 +#define LM92_TEMP_INPUT 0x80 + +/* -- SENSORS SYSCTL END -- */ + static ctl_table lm92_dir_table[] = { {LM92_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm92_temp, NULL}, @@ -134,9 +144,9 @@ static int lm92_read (struct i2c_client lm92_t *data = (lm92_t *) client->data; u16 value[5]; - if (time_after(jiffies, data->timestamp + HZ)) { + if ((jiffies - data->timestamp) > HZ) { if (lm92_read16 (client,LM92_REG_TEMPERATURE,value) < 0 || - lm92_read16 (client,LM92_REG_TRIP_HYSTERISIS,value + 1) < 0 || + lm92_read16 (client,LM92_REG_TRIP_HYSTERESIS,value + 1) < 0 || lm92_read16 (client,LM92_REG_TRIP_CRITICAL,value + 2) < 0 || lm92_read16 (client,LM92_REG_TRIP_LOW,value + 3) < 0 || lm92_read16 (client,LM92_REG_TRIP_HIGH,value + 4) < 0) @@ -167,7 +177,7 @@ static int lm92_write (struct i2c_client LIMIT (data->temp.low); LIMIT (data->temp.high); - if (lm92_write16 (client,LM92_REG_TRIP_HYSTERISIS,((s16) data->temp.hyst << 3)) < 0 || + if (lm92_write16 (client,LM92_REG_TRIP_HYSTERESIS,((s16) data->temp.hyst << 3)) < 0 || lm92_write16 (client,LM92_REG_TRIP_CRITICAL,((s16) data->temp.crit << 3)) < 0 || lm92_write16 (client,LM92_REG_TRIP_LOW,((s16) data->temp.low << 3)) < 0 || lm92_write16 (client,LM92_REG_TRIP_HIGH,((s16) data->temp.high << 3)) < 0) @@ -296,7 +306,7 @@ static int lm92_detect (struct i2c_adapt return (result); } - if ((result = i2c_register_entry (client,client->name,lm92_dir_table,THIS_MODULE)) < 0) { + if ((result = i2c_register_entry (client,client->name,lm92_dir_table)) < 0) { i2c_detach_client (client); kfree (client); up (&mutex); @@ -352,67 +362,35 @@ static int lm92_detach_client (struct i2 return (0); } -static int lm92_command (struct i2c_client *client,unsigned int cmd,void *arg) -{ - return (0); -} - -static void lm92_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif /* #ifdef MODULE */ -} - -static void lm92_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif /* #ifdef MODULE */ -} static struct i2c_driver lm92_driver = { - name: "lm92", - id: I2C_DRIVERID_LM92, - flags: I2C_DF_NOTIFY, - attach_adapter: lm92_attach_adapter, - detach_client: lm92_detach_client, - command: lm92_command, - inc_use: lm92_inc_use, - dec_use: lm92_dec_use + .owner = THIS_MODULE, + .name = "lm92", + .id = I2C_DRIVERID_LM92, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm92_attach_adapter, + .detach_client = lm92_detach_client, }; -int __init sensors_lm92_init (void) +static int __init sm_lm92_init(void) { - int result; - - if ((result = i2c_add_driver (&lm92_driver))) - return (result); - printk ("lm92.o version %s (%s)\n",LM_VERSION,LM_DATE); - - return (0); + return i2c_add_driver(&lm92_driver); } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) -#undef __exit -#define __exit -#endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) */ -static void __exit sensors_lm92_exit (void) +static void __exit sm_lm92_exit(void) { - i2c_del_driver (&lm92_driver); + i2c_del_driver(&lm92_driver); } -EXPORT_NO_SYMBOLS; + MODULE_AUTHOR ("Abraham van der Merwe "); MODULE_DESCRIPTION ("Linux support for LM92 Temperature Sensor"); -#ifdef MODULE_LICENSE MODULE_LICENSE ("GPL"); -#endif /* #ifdef MODULE_LICENSE */ -module_init (sensors_lm92_init); -module_exit (sensors_lm92_exit); +module_init(sm_lm92_init); +module_exit(sm_lm92_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/matorb.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/matorb.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/matorb.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/matorb.c 2003-08-17 21:26:58.000000000 +0200 @@ -22,28 +22,15 @@ #define DEBUG 1 -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2E, SENSORS_I2C_END }; @@ -67,27 +54,12 @@ struct matorb_data { }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_matorb_init(void); -static int __init matorb_cleanup(void); static int matorb_attach_adapter(struct i2c_adapter *adapter); static int matorb_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void matorb_init_client(struct i2c_client *client); static int matorb_detach_client(struct i2c_client *client); -static int matorb_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void matorb_inc_use(struct i2c_client *client); -static void matorb_dec_use(struct i2c_client *client); + static int matorb_write_value(struct i2c_client *client, u8 reg, u16 value); static void matorb_disp(struct i2c_client *client, int operation, @@ -97,16 +69,18 @@ static void matorb_update_client(struct /* This is the driver that will be inserted */ static struct i2c_driver matorb_driver = { - /* name */ "Matrix Orbital LCD driver", - /* id */ I2C_DRIVERID_MATORB, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &matorb_attach_adapter, - /* detach_client */ &matorb_detach_client, - /* command */ &matorb_command, - /* inc_use */ &matorb_inc_use, - /* dec_use */ &matorb_dec_use + .owner = THIS_MODULE, + .name = "Matrix Orbital LCD driver", + .id = I2C_DRIVERID_MATORB, + .flags = I2C_DF_NOTIFY, + .attach_adapter = matorb_attach_adapter, + .detach_client = matorb_detach_client, }; +/* -- SENSORS SYSCTL START -- */ +#define MATORB_SYSCTL_DISP 1000 +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected MATORB. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -118,12 +92,9 @@ static ctl_table matorb_dir_table_templa {0} }; -/* Used by init/cleanup */ -static int __initdata matorb_initialized = 0; - static int matorb_id = 0; -int matorb_attach_adapter(struct i2c_adapter *adapter) +static int matorb_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, matorb_detect); } @@ -189,8 +160,7 @@ int matorb_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - matorb_dir_table_template, - THIS_MODULE)) < 0) { + matorb_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -210,7 +180,7 @@ int matorb_detect(struct i2c_adapter *ad return err; } -int matorb_detach_client(struct i2c_client *client) +static int matorb_detach_client(struct i2c_client *client) { int err; @@ -229,33 +199,11 @@ int matorb_detach_client(struct i2c_clie } -/* No commands defined yet */ -int matorb_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void matorb_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void matorb_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - #if 0 /* All registers are word-sized, except for the configuration register. MATORB uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int matorb_read_value(struct i2c_client *client, u8 reg) +static int matorb_read_value(struct i2c_client *client, u8 reg) { return -1; /* Doesn't support reads */ } @@ -264,7 +212,7 @@ int matorb_read_value(struct i2c_client /* All registers are word-sized, except for the configuration register. MATORB uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int matorb_write_value(struct i2c_client *client, u8 reg, u16 value) +static int matorb_write_value(struct i2c_client *client, u8 reg, u16 value) { if (reg == 0) { return i2c_smbus_write_byte(client, value); @@ -273,19 +221,19 @@ int matorb_write_value(struct i2c_client } } -void matorb_init_client(struct i2c_client *client) +static void matorb_init_client(struct i2c_client *client) { /* Initialize the MATORB chip */ } -void matorb_update_client(struct i2c_client *client) +static void matorb_update_client(struct i2c_client *client) { struct matorb_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting matorb update\n"); @@ -318,54 +266,22 @@ void matorb_disp(struct i2c_client *clie } } -int __init sensors_matorb_init(void) +static int __init sm_matorb_init(void) { - int res; - printk("matorb.o version %s (%s)\n", LM_VERSION, LM_DATE); - matorb_initialized = 0; - if ((res = i2c_add_driver(&matorb_driver))) { - printk - ("matorb.o: Driver registration failed, module not inserted.\n"); - matorb_cleanup(); - return res; - } - matorb_initialized++; - return 0; + return i2c_add_driver(&matorb_driver); } -int __init matorb_cleanup(void) +static void __exit sm_matorb_exit(void) { - int res; - - if (matorb_initialized >= 1) { - if ((res = i2c_del_driver(&matorb_driver))) { - printk - ("matorb.o: Driver deregistration failed, module not removed.\n"); - return res; - } - matorb_initialized--; - } - - return 0; + i2c_del_driver(&matorb_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("MATORB driver"); -int init_module(void) -{ - return sensors_matorb_init(); -} - -int cleanup_module(void) -{ - return matorb_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_matorb_init); +module_exit(sm_matorb_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/maxilife.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/maxilife.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/maxilife.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/maxilife.c 2003-08-17 21:26:58.000000000 +0200 @@ -51,34 +51,21 @@ static const char *version_str = "2.00 29/2/2000 Fons Rademakers"; -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif - #undef AUTODETECT /* try to autodetect MaxiLife version */ /*#define AUTODETECT*/ @@ -134,7 +121,7 @@ SENSORS_INSMOD_1(maxilife); #define FAN_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : \ (val)==0x00 ? -1 : (1171860 / (val))) -extern inline u8 FAN_TO_REG(long rpm) +static inline u8 FAN_TO_REG(long rpm) { if (rpm == 0) return 255; @@ -242,11 +229,6 @@ extern inline u8 FAN_TO_REG(long rpm) (nr)==5 ? ((val) * 823 - 149140) : 0) -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* The following product codenames apply: Cristal/Geronimo: HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath) @@ -289,22 +271,10 @@ struct maxi_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_maxi_init(void); -static int __init maxi_cleanup(void); - static int maxi_attach_adapter(struct i2c_adapter *adapter); static int maxi_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int maxi_detach_client(struct i2c_client *client); -static int maxi_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void maxi_inc_use(struct i2c_client *client); -static void maxi_dec_use(struct i2c_client *client); static int maxi_read_value(struct i2c_client *client, u8 register); static int maxi_read_token(struct i2c_client *client, u16 token); @@ -342,19 +312,14 @@ static void maxi_alarms(struct i2c_clien /* The driver. I choose to use type i2c_driver, as at is identical to the smbus_driver. */ static struct i2c_driver maxi_driver = { - /* name */ "HP MaxiLife driver", - /* id */ I2C_DRIVERID_MAXILIFE, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &maxi_attach_adapter, - /* detach_client */ &maxi_detach_client, - /* command */ &maxi_command, - /* inc_use */ &maxi_inc_use, - /* dec_use */ &maxi_dec_use + .owner = THIS_MODULE, + .name = "HP MaxiLife driver", + .id = I2C_DRIVERID_MAXILIFE, + .flags = I2C_DF_NOTIFY, + .attach_adapter = maxi_attach_adapter, + .detach_client = maxi_detach_client, }; -/* Used by maxi_init/cleanup */ -static int __initdata maxi_initialized = 0; - static int maxi_id = 0; /* Default firmware version. Use module option "maxi_version" @@ -362,6 +327,49 @@ static int maxi_id = 0; static int maxi_version = cristal; /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ +#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ +#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ +#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celcius */ +#define MAXI_SYSCTL_PLL 1301 /* MHz */ +#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ +#define MAXI_SYSCTL_VID2 1402 /* Volts */ +#define MAXI_SYSCTL_VID3 1403 /* Volts */ +#define MAXI_SYSCTL_VID4 1404 /* Volts */ +#define MAXI_SYSCTL_VID5 1405 /* Volts */ +#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ +#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ +#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ +#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ +#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ + +#define MAXI_ALARM_VID4 0x0001 +#define MAXI_ALARM_TEMP2 0x0002 +#define MAXI_ALARM_VID1 0x0004 +#define MAXI_ALARM_VID2 0x0008 +#define MAXI_ALARM_VID3 0x0010 +#define MAXI_ALARM_PLL 0x0080 +#define MAXI_ALARM_TEMP4 0x0100 +#define MAXI_ALARM_TEMP5 0x0200 +#define MAXI_ALARM_FAN1 0x1000 +#define MAXI_ALARM_FAN2 0x2000 +#define MAXI_ALARM_FAN3 0x4000 + +#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ +#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ +#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ +#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected MaxiLife processor. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back @@ -417,7 +425,7 @@ static ctl_table maxi_dir_table_template - maxi_driver is inserted (when this module is loaded), for each available adapter - when a new adapter is inserted (and maxi_driver is still present) */ -int maxi_attach_adapter(struct i2c_adapter *adapter) +static int maxi_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, maxi_detect); } @@ -615,8 +623,7 @@ int maxi_detect(struct i2c_adapter *adap /* Register a new directory entry with module sensors */ if ((err = i2c_register_entry(new_client, type_name, - maxi_dir_table_template, - THIS_MODULE)) < 0) + maxi_dir_table_template)) < 0) goto ERROR4; data->sysctl_id = err; @@ -638,7 +645,7 @@ int maxi_detect(struct i2c_adapter *adap - maxi_driver is removed (when this module is unloaded) - when an adapter is removed which has a maxi client (and maxi_driver is still present). */ -int maxi_detach_client(struct i2c_client *client) +static int maxi_detach_client(struct i2c_client *client) { int err; @@ -654,37 +661,14 @@ int maxi_detach_client(struct i2c_client return 0; } -/* No commands defined yet */ -int maxi_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void maxi_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void maxi_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - /* Read byte from specified register (-1 in case of error, value otherwise). */ -int maxi_read_value(struct i2c_client *client, u8 reg) +static int maxi_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); } /* Read the byte value for a MaxiLife token (-1 in case of error, value otherwise */ -int maxi_read_token(struct i2c_client *client, u16 token) +static int maxi_read_token(struct i2c_client *client, u16 token) { u8 lowToken, highToken; int error, value; @@ -750,7 +734,7 @@ int maxi_read_token(struct i2c_client *c #ifndef NOWRITE /* Write byte to specified register (-1 in case of error, 0 otherwise). */ -int maxi_write_value(struct i2c_client *client, u8 reg, u8 value) +static int maxi_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } @@ -823,7 +807,7 @@ int maxi_write_token_loop(struct i2c_cli } /* Called when we have found a new MaxiLife. It should set limits, etc. */ -void maxi_init_client(struct i2c_client *client) +static void maxi_init_client(struct i2c_client *client) { struct maxi_data *data = client->data; @@ -835,7 +819,7 @@ void maxi_init_client(struct i2c_client } } -void maxi_update_client(struct i2c_client *client) +static void maxi_update_client(struct i2c_client *client) { struct maxi_data *data = client->data; int i; @@ -848,8 +832,8 @@ void maxi_update_client(struct i2c_clien down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("maxilife: Starting MaxiLife update\n"); @@ -985,8 +969,9 @@ void maxi99_update_client(struct i2c_cli /*maxi_write_token_loop(client, MAXI_TOK_LCD_LINE3, 13, "Linux 2.2.13"); */ - if (time_after(jiffies, last_updated[sensor][which] + 2 * HZ) - || !last_updated[sensor][which]) { + if ((jiffies - last_updated[sensor][which] > 2 * HZ) || + (jiffies < last_updated[sensor][which] + || !last_updated[sensor][which])) { int tmp, i; @@ -1386,56 +1371,24 @@ void maxi_alarms(struct i2c_client *clie } } -int __init sensors_maxi_init(void) +static int __init sm_maxilife_init(void) { - int res; - printk("maxilife: Version %s (lm_sensors %s (%s))\n", version_str, LM_VERSION, LM_DATE); - maxi_initialized = 0; - - if ((res = i2c_add_driver(&maxi_driver))) { - printk - ("maxilife: Driver registration failed, module not inserted.\n"); - maxi_cleanup(); - return res; - } - maxi_initialized++; - return 0; + return i2c_add_driver(&maxi_driver); } -int __init maxi_cleanup(void) +static void __exit sm_maxilife_exit(void) { - int res; - - if (maxi_initialized >= 1) { - if ((res = i2c_del_driver(&maxi_driver))) { - printk - ("maxilife: Driver deregistration failed, module not removed.\n"); - return res; - } - maxi_initialized--; - } - return 0; + i2c_del_driver(&maxi_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Fons Rademakers "); MODULE_DESCRIPTION("HP MaxiLife driver"); MODULE_PARM(maxi_version, "i"); MODULE_PARM_DESC(maxi_version, "MaxiLife firmware version"); -int init_module(void) -{ - return sensors_maxi_init(); -} - -int cleanup_module(void) -{ - return maxi_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_maxilife_init); +module_exit(sm_maxilife_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/mtp008.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/mtp008.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/mtp008.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/mtp008.c 2003-08-17 21:26:58.000000000 +0200 @@ -18,33 +18,21 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = {SENSORS_I2C_END}; @@ -132,7 +120,7 @@ SENSORS_INSMOD_1(mtp008); * and the rpm is therefore: * rpm = 1350000 / (count * div) */ -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -251,11 +239,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define MTP008_INIT_TEMP2_OVER 700 /* 70 Celsius */ #define MTP008_INIT_TEMP2_HYST 500 /* 50 Celsius */ -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* * For each registered MTP008, we need to keep some data in memory. The * structure itself is dynamically allocated, at the same time when a new @@ -288,21 +271,10 @@ struct mtp008_data { u8 pwmenable; /* Register 0x57 value */ }; -#ifdef MODULE -static int __init sensors_mtp008_init(void); -#else -extern int __init sensors_mtp008_init(void); -#endif -static int __init mtp008_cleanup(void); - static int mtp008_attach_adapter(struct i2c_adapter *adapter); static int mtp008_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int mtp008_detach_client(struct i2c_client *client); -static int mtp008_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void mtp008_inc_use(struct i2c_client *client); -static void mtp008_dec_use(struct i2c_client *client); static int mtp008_read_value(struct i2c_client *client, u8 register); static int mtp008_write_value(struct i2c_client *client, u8 register, u8 value); @@ -335,18 +307,54 @@ static int mtp008_id = 0; static struct i2c_driver mtp008_driver = { - /* name */ "MTP008 sensor driver", - /* id */ I2C_DRIVERID_MTP008, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &mtp008_attach_adapter, - /* detach_client */ &mtp008_detach_client, - /* command */ &mtp008_command, - /* inc_use */ &mtp008_inc_use, - /* dec_use */ &mtp008_dec_use + .owner = THIS_MODULE, + .name = "MTP008 sensor driver", + .id = I2C_DRIVERID_MTP008, + .flags = I2C_DF_NOTIFY, + .attach_adapter = mtp008_attach_adapter, + .detach_client = mtp008_detach_client, }; -/* Used by mtp008_init/cleanup */ -static int __initdata mtp008_initialized = 0; +/* -- SENSORS SYSCTL START -- */ +#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ +#define MTP008_SYSCTL_IN1 1001 +#define MTP008_SYSCTL_IN2 1002 +#define MTP008_SYSCTL_IN3 1003 +#define MTP008_SYSCTL_IN4 1004 +#define MTP008_SYSCTL_IN5 1005 +#define MTP008_SYSCTL_IN6 1006 +#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MTP008_SYSCTL_FAN2 1102 +#define MTP008_SYSCTL_FAN3 1103 +#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ +#define MTP008_SYSCTL_PWM1 1401 +#define MTP008_SYSCTL_PWM2 1402 +#define MTP008_SYSCTL_PWM3 1403 +#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define MTP008_SYSCTL_SENS2 1502 +#define MTP008_SYSCTL_SENS3 1503 +#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ +#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ + +#define MTP008_ALARM_IN0 0x0001 +#define MTP008_ALARM_IN1 0x0002 +#define MTP008_ALARM_IN2 0x0004 +#define MTP008_ALARM_IN3 0x0008 +#define MTP008_ALARM_IN4 0x0100 +#define MTP008_ALARM_IN5 0x0200 +#define MTP008_ALARM_IN6 0x0400 +#define MTP008_ALARM_FAN1 0x0040 +#define MTP008_ALARM_FAN2 0x0080 +#define MTP008_ALARM_FAN3 0x0800 +#define MTP008_ALARM_TEMP1 0x0010 +#define MTP008_ALARM_TEMP2 0x0100 +#define MTP008_ALARM_TEMP3 0x0200 + +/* -- SENSORS SYSCTL END -- */ /* The /proc/sys entries */ /* These files are created for each detected chip. This is just a template; @@ -410,7 +418,7 @@ static ctl_table mtp008_dir_table_templa * mtp008_driver is inserted (when this module is loaded), for each available * adapter when a new adapter is inserted (and mtp008_driver is still present) */ -int mtp008_attach_adapter(struct i2c_adapter *adapter) +static int mtp008_attach_adapter(struct i2c_adapter *adapter) { struct i2c_client_address_data mtp008_addr_data; @@ -488,8 +496,7 @@ int mtp008_detect(struct i2c_adapter *ad * Register a new directory entry with the sensors module. */ if ((sysid = i2c_register_entry(new_client, type_name, - mtp008_dir_table_template, - THIS_MODULE)) < 0) { + mtp008_dir_table_template)) < 0) { err = sysid; goto ERROR2; } @@ -514,7 +521,7 @@ int mtp008_detect(struct i2c_adapter *ad return err; } -int mtp008_detach_client(struct i2c_client *client) +static int mtp008_detach_client(struct i2c_client *client) { int err; @@ -531,38 +538,19 @@ int mtp008_detach_client(struct i2c_clie return 0; } -/* No commands defined yet */ -int mtp008_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void mtp008_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} -void mtp008_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -int mtp008_read_value(struct i2c_client *client, u8 reg) +static int mtp008_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg) & 0xff; } -int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value) +static int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* Called when we have found a new MTP008. It should set limits, etc. */ -void mtp008_init_client(struct i2c_client *client) +static void mtp008_init_client(struct i2c_client *client) { int vid; u8 save1, save2; @@ -652,7 +640,7 @@ void mtp008_init_client(struct i2c_clien ); } -void mtp008_update_client(struct i2c_client *client) +static void mtp008_update_client(struct i2c_client *client) { int i; u8 inp; @@ -662,8 +650,8 @@ void mtp008_update_client(struct i2c_cli down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting MTP008 update\n"); #endif @@ -762,7 +750,7 @@ void mtp008_update_client(struct i2c_cli up(&data->update_lock); } -void mtp008_getsensortype(struct mtp008_data *data, u8 inp) +static void mtp008_getsensortype(struct mtp008_data *data, u8 inp) { inp &= 0x0f; data->sens[0] = (inp >> 3) + 2; /* 2 or 3 */ @@ -1202,56 +1190,23 @@ void mtp008_sens(struct i2c_client *clie } } -int __init sensors_mtp008_init(void) +static int __init sm_mtp008_init(void) { - int res; - printk("mtp008.o version %s (%s)\n", LM_VERSION, LM_DATE); - mtp008_initialized = 0; - - if ((res = i2c_add_driver(&mtp008_driver))) { - printk("mtp008.o: Driver registration failed, " - "module not inserted.\n"); - mtp008_cleanup(); - return res; - } - mtp008_initialized++; - - return 0; + return i2c_add_driver(&mtp008_driver); } -int __init mtp008_cleanup(void) +static void __exit sm_mtp008_exit(void) { - int res; - - if (mtp008_initialized >= 1) { - if ((res = i2c_del_driver(&mtp008_driver))) { - printk("mtp008.o: Driver deregistration failed, " - "module not removed.\n"); - return res; - } - mtp008_initialized--; - } - return 0; + i2c_del_driver(&mtp008_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Frodo Looijaard , " "Philip Edelbrock , " "and Kris Van Hees "); MODULE_DESCRIPTION("MTP008 driver"); -int init_module(void) -{ - return sensors_mtp008_init(); -} - -int cleanup_module(void) -{ - return mtp008_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_mtp008_init); +module_exit(sm_mtp008_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/pcf8574.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/pcf8574.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/pcf8574.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/pcf8574.c 2003-08-17 21:26:58.000000000 +0200 @@ -38,27 +38,15 @@ */ -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -87,26 +75,11 @@ struct pcf8574_data { u8 read, write; /* Register values */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_pcf8574_init(void); -static int __init pcf8574_cleanup(void); static int pcf8574_attach_adapter(struct i2c_adapter *adapter); static int pcf8574_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int pcf8574_detach_client(struct i2c_client *client); -static int pcf8574_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void pcf8574_inc_use(struct i2c_client *client); -static void pcf8574_dec_use(struct i2c_client *client); + static void pcf8574_read(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void pcf8574_write(struct i2c_client *client, int operation, @@ -116,16 +89,21 @@ static void pcf8574_init_client(struct i /* This is the driver that will be inserted */ static struct i2c_driver pcf8574_driver = { - /* name */ "PCF8574 sensor chip driver", - /* id */ I2C_DRIVERID_PCF8574, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &pcf8574_attach_adapter, - /* detach_client */ &pcf8574_detach_client, - /* command */ &pcf8574_command, - /* inc_use */ &pcf8574_inc_use, - /* dec_use */ &pcf8574_dec_use + .owner = THIS_MODULE, + .name = "PCF8574 sensor chip driver", + .id = I2C_DRIVERID_PCF8574, + .flags = I2C_DF_NOTIFY, + .attach_adapter = pcf8574_attach_adapter, + .detach_client = pcf8574_detach_client, }; + +/* -- SENSORS SYSCTL START -- */ +#define PCF8574_SYSCTL_READ 1000 +#define PCF8574_SYSCTL_WRITE 1001 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected PCF8574. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -139,15 +117,12 @@ static ctl_table pcf8574_dir_table_templ {0} }; -/* Used by init/cleanup */ -static int __initdata pcf8574_initialized = 0; - /* I choose here for semi-static PCF8574 allocation. Complete dynamic allocation could also be used; the code needed for this would probably take more memory than the datastructure takes now. */ static int pcf8574_id = 0; -int pcf8574_attach_adapter(struct i2c_adapter *adapter) +static int pcf8574_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, pcf8574_detect); } @@ -232,8 +207,7 @@ int pcf8574_detect(struct i2c_adapter *a /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - pcf8574_dir_table_template, - THIS_MODULE)) < 0) { + pcf8574_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -256,7 +230,7 @@ int pcf8574_detect(struct i2c_adapter *a } -int pcf8574_detach_client(struct i2c_client *client) +static int pcf8574_detach_client(struct i2c_client *client) { int err; @@ -275,30 +249,8 @@ int pcf8574_detach_client(struct i2c_cli } -/* No commands defined yet */ -int pcf8574_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void pcf8574_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void pcf8574_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* Called when we have found a new PCF8574. */ -void pcf8574_init_client(struct i2c_client *client) +static void pcf8574_init_client(struct i2c_client *client) { struct pcf8574_data *data = client->data; data->write = PCF8574_INIT; @@ -306,14 +258,14 @@ void pcf8574_init_client(struct i2c_clie } -void pcf8574_update_client(struct i2c_client *client) +static void pcf8574_update_client(struct i2c_client *client) { struct pcf8574_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + 5*HZ) - || !data->valid) { + if ((jiffies - data->last_updated > 5*HZ) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting pcf8574 update\n"); @@ -358,54 +310,22 @@ void pcf8574_write(struct i2c_client *cl } -int __init sensors_pcf8574_init(void) +static int __init sm_pcf8574_init(void) { - int res; - printk("pcf8574.o version %s (%s)\n", LM_VERSION, LM_DATE); - pcf8574_initialized = 0; - if ((res = i2c_add_driver(&pcf8574_driver))) { - printk - ("pcf8574.o: Driver registration failed, module not inserted.\n"); - pcf8574_cleanup(); - return res; - } - pcf8574_initialized++; - return 0; + return i2c_add_driver(&pcf8574_driver); } -int __init pcf8574_cleanup(void) +static void __exit sm_pcf8574_exit(void) { - int res; - - if (pcf8574_initialized >= 1) { - if ((res = i2c_del_driver(&pcf8574_driver))) { - printk - ("pcf8574.o: Driver deregistration failed, module not removed.\n"); - return res; - } - pcf8574_initialized--; - } - - return 0; + i2c_del_driver(&pcf8574_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard , Philip Edelbrock , Dan Eaton and Aurelien Jarno "); MODULE_DESCRIPTION("PCF8574 driver"); -int init_module(void) -{ - return sensors_pcf8574_init(); -} - -int cleanup_module(void) -{ - return pcf8574_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_pcf8574_init); +module_exit(sm_pcf8574_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/pcf8591.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/pcf8591.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/pcf8591.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/pcf8591.c 2003-08-17 21:26:58.000000000 +0200 @@ -18,23 +18,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -79,12 +69,6 @@ SENSORS_INSMOD_1(pcf8591); #define REG_TO_SIGNED(reg) (reg & 0x80)?(reg - 256):(reg) /* Convert signed 8 bit value to signed value */ -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif - - struct pcf8591_data { struct semaphore lock; @@ -100,21 +84,10 @@ struct pcf8591_data { u8 aout; }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_pcf8591_init(void); -static int __init pcf8591_cleanup(void); static int pcf8591_attach_adapter(struct i2c_adapter *adapter); static int pcf8591_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int pcf8591_detach_client(struct i2c_client *client); -static int pcf8591_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void pcf8591_inc_use(struct i2c_client *client); -static void pcf8591_dec_use(struct i2c_client *client); static void pcf8591_update_client(struct i2c_client *client); static void pcf8591_init_client(struct i2c_client *client); @@ -131,23 +104,28 @@ static void pcf8591_aout(struct i2c_clie /* This is the driver that will be inserted */ static struct i2c_driver pcf8591_driver = { - /* name */ "PCF8591 sensor chip driver", - /* id */ I2C_DRIVERID_PCF8591, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &pcf8591_attach_adapter, - /* detach_client */ &pcf8591_detach_client, - /* command */ &pcf8591_command, - /* inc_use */ &pcf8591_inc_use, - /* dec_use */ &pcf8591_dec_use + .owner = THIS_MODULE, + .name = "PCF8591 sensor chip driver", + .id = I2C_DRIVERID_PCF8591, + .flags = I2C_DF_NOTIFY, + .attach_adapter = pcf8591_attach_adapter, + .detach_client = pcf8591_detach_client, }; -/* Used by lm78_init/cleanup */ -static int __initdata pcf8591_initialized = 0; - static int pcf8591_id = 0; - /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ +#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ +#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ +#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ +#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ +#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ +#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected PCF8591. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -176,7 +154,7 @@ static ctl_table pcf8591_dir_table_templ * pcf8591_driver is inserted (when this module is loaded), for each available adapter * when a new adapter is inserted (and pcf8591_driver is still present) */ -int pcf8591_attach_adapter(struct i2c_adapter *adapter) +static int pcf8591_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, pcf8591_detect); } @@ -253,8 +231,7 @@ int pcf8591_detect(struct i2c_adapter *a /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - pcf8591_dir_table_template, - THIS_MODULE)) < 0) { + pcf8591_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -276,15 +253,10 @@ int pcf8591_detect(struct i2c_adapter *a return err; } -int pcf8591_detach_client(struct i2c_client *client) +static int pcf8591_detach_client(struct i2c_client *client) { int err; -#ifdef MODULE - if (MOD_IN_USE) - return -EBUSY; -#endif - i2c_deregister_entry(((struct pcf8591_data *) (client->data))-> sysctl_id); @@ -299,30 +271,8 @@ int pcf8591_detach_client(struct i2c_cli return 0; } -/* No commands defined yet */ -int pcf8591_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void pcf8591_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void pcf8591_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* Called when we have found a new PCF8591. */ -void pcf8591_init_client(struct i2c_client *client) +static void pcf8591_init_client(struct i2c_client *client) { struct pcf8591_data *data = client->data; data->control_byte = PCF8591_INIT_CONTROL_BYTE; @@ -331,14 +281,14 @@ void pcf8591_init_client(struct i2c_clie i2c_smbus_write_byte_data(client, data->control_byte, data->aout); } -void pcf8591_update_client(struct i2c_client *client) +static void pcf8591_update_client(struct i2c_client *client) { struct pcf8591_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk(KERN_DEBUG "Starting pcf8591 update\n"); @@ -488,60 +438,22 @@ void pcf8591_aout(struct i2c_client *cli } } -int __init sensors_pcf8591_init(void) +static int __init sm_pcf8591_init(void) { - int res; - printk(KERN_INFO "pcf8591.o version %s (%s)\n", LM_VERSION, LM_DATE); - pcf8591_initialized = 0; - - if ((res = i2c_add_driver(&pcf8591_driver))) { - printk - (KERN_ERR "pcf8591.o: Driver registration failed, module not inserted.\n"); - pcf8591_cleanup(); - return res; - } - pcf8591_initialized++; - return 0; + return i2c_add_driver(&pcf8591_driver); } -int __init pcf8591_cleanup(void) +static void __exit sm_pcf8591_exit(void) { - int res; - - if (pcf8591_initialized >= 1) { - if ((res = i2c_del_driver(&pcf8591_driver))) { - printk - (KERN_ERR "pcf8591.o: Driver deregistration failed, module not removed.\n"); - return res; - } - pcf8591_initialized--; - } - return 0; + i2c_del_driver(&pcf8591_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Aurelien Jarno "); MODULE_DESCRIPTION("PCF8591 driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return sensors_pcf8591_init(); -} - -int cleanup_module(void) -{ - return pcf8591_cleanup(); -} - -#endif /* MODULE */ - - - +module_init(sm_pcf8591_init); +module_exit(sm_pcf8591_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/sensors.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/sensors.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/sensors.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/sensors.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,185 +0,0 @@ -/* - sensors.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - 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. -*/ - -/* Not configurable as a module */ - -#include - -#ifdef CONFIG_SENSORS_ADM1021 -extern int sensors_adm1021_init(void); -#endif -#ifdef CONFIG_SENSORS_ADM1025 -extern int sensors_adm1025_init(void); -#endif -#ifdef CONFIG_SENSORS_ADM9240 -extern int sensors_adm9240_init(void); -#endif -#ifdef CONFIG_SENSORS_BT869 -extern int sensors_bt869_init(void); -#endif -#ifdef CONFIG_SENSORS_DDCMON -extern int sensors_ddcmon_init(void); -#endif -#ifdef CONFIG_SENSORS_DS1621 -extern int sensors_ds1621_init(void); -#endif -#ifdef CONFIG_SENSORS_GL518SM -extern int sensors_gl518sm_init(void); -#endif -#ifdef CONFIG_SENSORS_GL520SM -extern int sensors_gl520_init(void); -#endif -#ifdef CONFIG_SENSORS_LM75 -extern int sensors_lm75_init(void); -#endif -#ifdef CONFIG_SENSORS_LM78 -extern int sensors_lm78_init(void); -#endif -#ifdef CONFIG_SENSORS_LM80 -extern int sensors_lm80_init(void); -#endif -#ifdef CONFIG_SENSORS_LM87 -extern int sensors_lm87_init(void); -#endif -#ifdef CONFIG_SENSORS_LM92 -extern int sensors_lm92_init(void); -#endif -#ifdef CONFIG_SENSORS_MTP008 -extern int sensors_mtp008_init(void); -#endif -#ifdef CONFIG_SENSORS_PCF8574 -extern int sensors_pcf8574_init(void); -#endif -#ifdef CONFIG_SENSORS_PCF8591 -extern int sensors_pcf8591_init(void); -#endif -#ifdef CONFIG_SENSORS_SIS5595 -extern int sensors_sis5595_init(void); -#endif -#ifdef CONFIG_SENSORS_SMSC47M1 -extern int sensors_smsc47m1_init(void); -#endif -#ifdef CONFIG_SENSORS_THMC50 -extern int sensors_thmc50_init(void); -#endif -#ifdef CONFIG_SENSORS_VIA686A -extern int sensors_via686a_init(void); -#endif -#ifdef CONFIG_SENSORS_VT1211 -extern int sensors_vt1211_init(void); -#endif -#ifdef CONFIG_SENSORS_VT8231 -extern int sensors_vt8231_init(void); -#endif -#ifdef CONFIG_SENSORS_W83781D -extern int sensors_w83781d_init(void); -#endif -#ifdef CONFIG_SENSORS_EEPROM -extern int sensors_eeprom_init(void); -#endif -#ifdef CONFIG_SENSORS_LTC1710 -extern int sensors_ltc1710_init(void); -#endif -#ifdef CONFIG_SENSORS_IT87 -extern int sensors_it87_init(void); -#endif - -int __init sensors_init_all(void) -{ -#ifdef CONFIG_SENSORS_ADM1021 - sensors_adm1021_init(); -#endif -#ifdef CONFIG_SENSORS_ADM1025 - sensors_adm1025_init(); -#endif -#ifdef CONFIG_SENSORS_ADM9240 - sensors_adm9240_init(); -#endif -#ifdef CONFIG_SENSORS_BT869 - sensors_bt869_init(); -#endif -#ifdef CONFIG_SENSORS_DDCMON - sensors_ddcmon_init(); -#endif -#ifdef CONFIG_SENSORS_DS1621 - sensors_ds1621_init(); -#endif -#ifdef CONFIG_SENSORS_GL518SM - sensors_gl518sm_init(); -#endif -#ifdef CONFIG_SENSORS_GL520SM - sensors_gl520_init(); -#endif -#ifdef CONFIG_SENSORS_LM75 - sensors_lm75_init(); -#endif -#ifdef CONFIG_SENSORS_LM78 - sensors_lm78_init(); -#endif -#ifdef CONFIG_SENSORS_LM80 - sensors_lm80_init(); -#endif -#ifdef CONFIG_SENSORS_LM87 - sensors_lm87_init(); -#endif -#ifdef CONFIG_SENSORS_LM92 - sensors_lm92_init(); -#endif -#ifdef CONFIG_SENSORS_PCF8574 - sensors_pcf8574_init(); -#endif -#ifdef CONFIG_SENSORS_PCF8591 - sensors_pcf8591_init(); -#endif -#ifdef CONFIG_SENSORS_MTP008 - sensors_mtp008_init(); -#endif -#ifdef CONFIG_SENSORS_SIS5595 - sensors_sis5595_init(); -#endif -#ifdef CONFIG_SENSORS_SMSC47M1 - sensors_smsc47m1_init(); -#endif -#ifdef CONFIG_SENSORS_THMC50 - sensors_thmc50_init(); -#endif -#ifdef CONFIG_SENSORS_VIA686A - sensors_via686a_init(); -#endif -#ifdef CONFIG_SENSORS_VT1211 - sensors_vt1211_init(); -#endif -#ifdef CONFIG_SENSORS_VT8231 - sensors_vt8231_init(); -#endif -#ifdef CONFIG_SENSORS_W83781D - sensors_w83781d_init(); -#endif -#ifdef CONFIG_SENSORS_EEPROM - sensors_eeprom_init(); -#endif -#ifdef CONFIG_SENSORS_LTC1710 - sensors_ltc1710_init(); -#endif -#ifdef CONFIG_SENSORS_IT87 - sensors_it87_init(); -#endif - return 0; -} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/sis5595.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/sis5595.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/sis5595.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/sis5595.c 2003-08-17 21:26:58.000000000 +0200 @@ -45,34 +45,22 @@ 735 0008 0735 */ -#include #include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ @@ -92,22 +80,6 @@ static unsigned int normal_isa_range[] = /* Insmod parameters */ SENSORS_INSMOD_1(sis5595); -#ifndef PCI_DEVICE_ID_SI_540 -#define PCI_DEVICE_ID_SI_540 0x0540 -#endif -#ifndef PCI_DEVICE_ID_SI_550 -#define PCI_DEVICE_ID_SI_550 0x0550 -#endif -#ifndef PCI_DEVICE_ID_SI_630 -#define PCI_DEVICE_ID_SI_630 0x0630 -#endif -#ifndef PCI_DEVICE_ID_SI_730 -#define PCI_DEVICE_ID_SI_730 0x0730 -#endif -#ifndef PCI_DEVICE_ID_SI_5598 -#define PCI_DEVICE_ID_SI_5598 0x5598 -#endif - static int blacklist[] = { PCI_DEVICE_ID_SI_540, PCI_DEVICE_ID_SI_550, @@ -175,7 +147,7 @@ static int blacklist[] = { #define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) #define IN_FROM_REG(val) (((val) * 16) / 10) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -235,11 +207,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define SIS5595_INIT_TEMP_OVER 600 #define SIS5595_INIT_TEMP_HYST 100 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For the SIS5595, we need to keep some data in memory. That data is pointed to by sis5595_list[NR]->data. The structure itself is dynamically allocated, at the time when the new sis5595 client is @@ -268,22 +235,10 @@ struct sis5595_data { static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_sis5595_init(void); -static int __init sis5595_cleanup(void); - static int sis5595_attach_adapter(struct i2c_adapter *adapter); static int sis5595_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int sis5595_detach_client(struct i2c_client *client); -static int sis5595_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void sis5595_inc_use(struct i2c_client *client); -static void sis5595_dec_use(struct i2c_client *client); static int sis5595_read_value(struct i2c_client *client, u8 register); static int sis5595_write_value(struct i2c_client *client, u8 register, @@ -309,20 +264,40 @@ static int sis5595_id = 0; /* The driver. I choose to use type i2c_driver, as at is identical to both smbus_driver and isa_driver, and clients could be of either kind */ static struct i2c_driver sis5595_driver = { - /* name */ "SiS 5595", - /* id */ I2C_DRIVERID_SIS5595, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &sis5595_attach_adapter, - /* detach_client */ &sis5595_detach_client, - /* command */ &sis5595_command, - /* inc_use */ &sis5595_inc_use, - /* dec_use */ &sis5595_dec_use + .owner = THIS_MODULE, + .name = "SiS 5595", + .id = I2C_DRIVERID_SIS5595, + .flags = I2C_DF_NOTIFY, + .attach_adapter = sis5595_attach_adapter, + .detach_client = sis5595_detach_client, }; -/* Used by sis5595_init/cleanup */ -static int __initdata sis5595_initialized = 0; - /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ +#define SIS5595_SYSCTL_IN1 1001 +#define SIS5595_SYSCTL_IN2 1002 +#define SIS5595_SYSCTL_IN3 1003 +#define SIS5595_SYSCTL_IN4 1004 +#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SIS5595_SYSCTL_FAN2 1102 +#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ + +#define SIS5595_ALARM_IN0 0x01 +#define SIS5595_ALARM_IN1 0x02 +#define SIS5595_ALARM_IN2 0x04 +#define SIS5595_ALARM_IN3 0x08 +#define SIS5595_ALARM_BTI 0x20 +#define SIS5595_ALARM_FAN1 0x40 +#define SIS5595_ALARM_FAN2 0x80 +#define SIS5595_ALARM_IN4 0x8000 +#define SIS5595_ALARM_TEMP 0x8000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected SIS5595. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -353,13 +328,13 @@ static ctl_table sis5595_dir_table_templ }; /* This is called when the module is loaded */ -int sis5595_attach_adapter(struct i2c_adapter *adapter) +static int sis5595_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, sis5595_detect); } /* Locate SiS bridge and correct base address for SIS5595 */ -int sis5595_find_sis(int *address) +static int sis5595_find_sis(int *address) { u16 val; int *i; @@ -498,8 +473,7 @@ int sis5595_detect(struct i2c_adapter *a /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry((struct i2c_client *) new_client, type_name, - sis5595_dir_table_template, - THIS_MODULE)) < 0) { + sis5595_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -517,7 +491,7 @@ int sis5595_detect(struct i2c_adapter *a return err; } -int sis5595_detach_client(struct i2c_client *client) +static int sis5595_detach_client(struct i2c_client *client) { int err; @@ -536,31 +510,11 @@ int sis5595_detach_client(struct i2c_cli return 0; } -/* No commands defined yet */ -int sis5595_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void sis5595_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void sis5595_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* ISA access must be locked explicitly. There are some ugly typecasts here, but the good news is - they should nowhere else be necessary! */ -int sis5595_read_value(struct i2c_client *client, u8 reg) +static int sis5595_read_value(struct i2c_client *client, u8 reg) { int res; @@ -571,7 +525,7 @@ int sis5595_read_value(struct i2c_client return res; } -int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) +static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) { down(&(((struct sis5595_data *) (client->data))->lock)); outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); @@ -581,7 +535,7 @@ int sis5595_write_value(struct i2c_clien } /* Called when we have found a new SIS5595. It should set limits, etc. */ -void sis5595_init_client(struct i2c_client *client) +static void sis5595_init_client(struct i2c_client *client) { struct sis5595_data *data = client->data; @@ -628,15 +582,15 @@ void sis5595_init_client(struct i2c_clie } -void sis5595_update_client(struct i2c_client *client) +static void sis5595_update_client(struct i2c_client *client) { struct sis5595_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { for (i = 0; i <= data->maxins; i++) { data->in[i] = @@ -832,12 +786,11 @@ void sis5595_fan_div(struct i2c_client * } } -int __init sensors_sis5595_init(void) +static int __init sm_sis5595_init(void) { - int res, addr; + int addr; printk("sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE); - sis5595_initialized = 0; if (sis5595_find_sis(&addr)) { printk("sis5595.o: SIS5595 not detected, module not inserted.\n"); @@ -845,46 +798,18 @@ int __init sensors_sis5595_init(void) } normal_isa[0] = addr; - if ((res = i2c_add_driver(&sis5595_driver))) { - printk - ("sis5595.o: Driver registration failed, module not inserted.\n"); - sis5595_cleanup(); - return res; - } - sis5595_initialized++; - return 0; + return i2c_add_driver(&sis5595_driver); } -int __init sis5595_cleanup(void) +static void __exit sm_sis5595_exit(void) { - int res; - - if (sis5595_initialized >= 1) { - if ((res = i2c_del_driver(&sis5595_driver))) { - printk - ("sis5595.o: Driver deregistration failed, module not removed.\n"); - return res; - } - sis5595_initialized--; - } - return 0; + i2c_del_driver(&sis5595_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Kyösti Mälkki "); MODULE_DESCRIPTION("SiS 5595 Sensor device"); -int init_module(void) -{ - return sensors_sis5595_init(); -} - -int cleanup_module(void) -{ - return sis5595_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_sis5595_init); +module_exit(sm_sis5595_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/smsc47m1.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/smsc47m1.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/smsc47m1.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/smsc47m1.c 2003-08-17 21:26:58.000000000 +0200 @@ -19,29 +19,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" static int force_addr = 0; MODULE_PARM(force_addr, "i"); @@ -110,7 +100,7 @@ superio_exit(void) #define SMSC47M1_REG_FAN(nr) (0x58 + (nr)) #define SMSC47M1_REG_FAN_MIN(nr) (0x5a + (nr)) -extern inline u8 MIN_TO_REG(long rpm, int div) +static inline u8 MIN_TO_REG(long rpm, int div) { if (rpm == 0) return 0; @@ -131,11 +121,6 @@ extern inline u8 MIN_TO_REG(long rpm, in #define SMSC47M1_INIT_FAN_MIN_1 3000 #define SMSC47M1_INIT_FAN_MIN_2 3000 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - struct smsc47m1_data { struct semaphore lock; int sysctl_id; @@ -151,22 +136,11 @@ struct smsc47m1_data { u8 pwm[2]; /* Register value (bit 7 is enable) */ }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_smsc47m1_init(void); -static int __init smsc47m1_cleanup(void); static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); static int smsc47m1_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int smsc47m1_detach_client(struct i2c_client *client); -static int smsc47m1_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void smsc47m1_inc_use(struct i2c_client *client); -static void smsc47m1_dec_use(struct i2c_client *client); static int smsc47m1_read_value(struct i2c_client *client, u8 register); static int smsc47m1_write_value(struct i2c_client *client, u8 register, @@ -188,17 +162,26 @@ static void smsc47m1_pwm(struct i2c_clie static int smsc47m1_id = 0; static struct i2c_driver smsc47m1_driver = { - /* name */ "SMSC47M1xx fan driver", - /* id */ I2C_DRIVERID_SMSC47M1, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &smsc47m1_attach_adapter, - /* detach_client */ &smsc47m1_detach_client, - /* command */ &smsc47m1_command, - /* inc_use */ &smsc47m1_inc_use, - /* dec_use */ &smsc47m1_dec_use + .owner = THIS_MODULE, + .name = "SMSC47M1xx fan driver", + .id = I2C_DRIVERID_SMSC47M1, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47m1_attach_adapter, + .detach_client = smsc47m1_detach_client, }; -static int __initdata smsc47m1_initialized = 0; +/* -- SENSORS SYSCTL START -- */ +#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SMSC47M1_SYSCTL_FAN2 1102 +#define SMSC47M1_SYSCTL_PWM1 1401 +#define SMSC47M1_SYSCTL_PWM2 1402 +#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ + +#define SMSC47M1_ALARM_FAN1 0x0001 +#define SMSC47M1_ALARM_FAN2 0x0002 + +/* -- SENSORS SYSCTL END -- */ static ctl_table smsc47m1_dir_table_template[] = { {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, @@ -216,12 +199,12 @@ static ctl_table smsc47m1_dir_table_temp {0} }; -int smsc47m1_attach_adapter(struct i2c_adapter *adapter) +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, smsc47m1_detect); } -int smsc47m1_find(int *address) +static int smsc47m1_find(int *address) { u16 val; @@ -303,8 +286,7 @@ int smsc47m1_detect(struct i2c_adapter * if ((i = i2c_register_entry((struct i2c_client *) new_client, type_name, - smsc47m1_dir_table_template, - THIS_MODULE)) < 0) { + smsc47m1_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -321,7 +303,7 @@ int smsc47m1_detect(struct i2c_adapter * return err; } -int smsc47m1_detach_client(struct i2c_client *client) +static int smsc47m1_detach_client(struct i2c_client *client) { int err; @@ -340,26 +322,7 @@ int smsc47m1_detach_client(struct i2c_cl return 0; } -int smsc47m1_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void smsc47m1_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void smsc47m1_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -int smsc47m1_read_value(struct i2c_client *client, u8 reg) +static int smsc47m1_read_value(struct i2c_client *client, u8 reg) { int res; @@ -367,13 +330,13 @@ int smsc47m1_read_value(struct i2c_clien return res; } -int smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) +static int smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) { outb_p(value, client->addr + reg); return 0; } -void smsc47m1_init_client(struct i2c_client *client) +static void smsc47m1_init_client(struct i2c_client *client) { /* configure pins for tach function */ smsc47m1_write_value(client, SMSC47M1_REG_TPIN1, 0x05); @@ -384,15 +347,15 @@ void smsc47m1_init_client(struct i2c_cli MIN_TO_REG(SMSC47M1_INIT_FAN_MIN_2, 2)); } -void smsc47m1_update_client(struct i2c_client *client) +static void smsc47m1_update_client(struct i2c_client *client) { struct smsc47m1_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { for (i = 1; i <= 2; i++) { data->fan[i - 1] = smsc47m1_read_value(client, SMSC47M1_REG_FAN(i)); @@ -517,12 +480,11 @@ void smsc47m1_pwm(struct i2c_client *cli } } -int __init sensors_smsc47m1_init(void) +static int __init sm_smsc47m1_init(void) { - int res, addr; + int addr; printk("smsc47m1.o version %s (%s)\n", LM_VERSION, LM_DATE); - smsc47m1_initialized = 0; if (smsc47m1_find(&addr)) { printk("smsc47m1.o: SMSC47M1xx not detected, module not inserted.\n"); @@ -530,49 +492,19 @@ int __init sensors_smsc47m1_init(void) } normal_isa[0] = addr; - if ((res = i2c_add_driver(&smsc47m1_driver))) { - printk - ("smsc47m1.o: Driver registration failed, module not inserted.\n"); - smsc47m1_cleanup(); - return res; - } - smsc47m1_initialized++; - return 0; + return i2c_add_driver(&smsc47m1_driver); } -int __init smsc47m1_cleanup(void) +static void __exit sm_smsc47m1_exit(void) { - int res; - - if (smsc47m1_initialized >= 1) { - if ((res = i2c_del_driver(&smsc47m1_driver))) { - printk - ("smsc47m1.o: Driver deregistration failed, module not removed.\n"); - return res; - } - smsc47m1_initialized--; - } - return 0; + i2c_del_driver(&smsc47m1_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Mark D. Studebaker "); MODULE_DESCRIPTION("SMSC47M110x Fan sensors"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return sensors_smsc47m1_init(); -} - -int cleanup_module(void) -{ - return smsc47m1_cleanup(); -} -#endif /* MODULE */ +module_init(sm_smsc47m1_init); +module_exit(sm_smsc47m1_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/thmc50.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/thmc50.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/thmc50.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/thmc50.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,27 +21,15 @@ #define DEBUG 1 -#include #include #include #include -#include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" +#include #include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -101,27 +89,12 @@ struct thmc50_data { inter, inter_mask, die_code, analog_out; /* Register values */ }; -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_thmc50_init(void); -static int __init thmc50_cleanup(void); static int thmc50_attach_adapter(struct i2c_adapter *adapter); static int thmc50_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static void thmc50_init_client(struct i2c_client *client); static int thmc50_detach_client(struct i2c_client *client); -static int thmc50_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void thmc50_inc_use(struct i2c_client *client); -static void thmc50_dec_use(struct i2c_client *client); + static int thmc50_read_value(struct i2c_client *client, u8 reg); static int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value); @@ -143,16 +116,25 @@ static void thmc50_update_client(struct /* This is the driver that will be inserted */ static struct i2c_driver thmc50_driver = { - /* name */ "THMC50 sensor chip driver", - /* id */ I2C_DRIVERID_THMC50, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &thmc50_attach_adapter, - /* detach_client */ &thmc50_detach_client, - /* command */ &thmc50_command, - /* inc_use */ &thmc50_inc_use, - /* dec_use */ &thmc50_dec_use + .owner = THIS_MODULE, + .name = "THMC50 sensor chip driver", + .id = I2C_DRIVERID_THMC50, + .flags = I2C_DF_NOTIFY, + .attach_adapter = thmc50_attach_adapter, + .detach_client = thmc50_detach_client, }; +/* -- SENSORS SYSCTL START -- */ + +#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celcius */ +#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celcius */ +#define THMC50_SYSCTL_INTER 1202 +#define THMC50_SYSCTL_INTER_MASK 1203 +#define THMC50_SYSCTL_DIE_CODE 1204 +#define THMC50_SYSCTL_ANALOG_OUT 1205 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected THMC50. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -174,12 +156,10 @@ static ctl_table thmc50_dir_table_templa {0} }; -/* Used by init/cleanup */ -static int __initdata thmc50_initialized = 0; static int thmc50_id = 0; -int thmc50_attach_adapter(struct i2c_adapter *adapter) +static int thmc50_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, thmc50_detect); } @@ -271,8 +251,7 @@ int thmc50_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry(new_client, type_name, - thmc50_dir_table_template, - THIS_MODULE)) < 0) { + thmc50_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -293,7 +272,7 @@ int thmc50_detect(struct i2c_adapter *ad return err; } -int thmc50_detach_client(struct i2c_client *client) +static int thmc50_detach_client(struct i2c_client *client) { int err; @@ -312,30 +291,10 @@ int thmc50_detach_client(struct i2c_clie } -/* No commands defined yet */ -int thmc50_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void thmc50_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void thmc50_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - /* All registers are word-sized, except for the configuration register. THMC50 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int thmc50_read_value(struct i2c_client *client, u8 reg) +static int thmc50_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); } @@ -343,12 +302,12 @@ int thmc50_read_value(struct i2c_client /* All registers are word-sized, except for the configuration register. THMC50 uses a high-byte first convention, which is exactly opposite to the usual practice. */ -int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value) +static int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value) { return i2c_smbus_write_byte_data(client, reg, value); } -void thmc50_init_client(struct i2c_client *client) +static void thmc50_init_client(struct i2c_client *client) { /* Initialize the THMC50 chip */ thmc50_write_value(client, THMC50_REG_TEMP_OS, @@ -358,14 +317,14 @@ void thmc50_init_client(struct i2c_clien thmc50_write_value(client, THMC50_REG_CONF, 1); } -void thmc50_update_client(struct i2c_client *client) +static void thmc50_update_client(struct i2c_client *client) { struct thmc50_data *data = client->data; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting thmc50 update\n"); @@ -527,54 +486,23 @@ void thmc50_analog_out(struct i2c_client -int __init sensors_thmc50_init(void) +static int __init sm_thmc50_init(void) { - int res; - printk("thmc50.o version %s (%s)\n", LM_VERSION, LM_DATE); - thmc50_initialized = 0; - if ((res = i2c_add_driver(&thmc50_driver))) { - printk - ("thmc50.o: Driver registration failed, module not inserted.\n"); - thmc50_cleanup(); - return res; - } - thmc50_initialized++; - return 0; + + return i2c_add_driver(&thmc50_driver); } -int __init thmc50_cleanup(void) +static void __exit sm_thmc50_exit(void) { - int res; - - if (thmc50_initialized >= 1) { - if ((res = i2c_del_driver(&thmc50_driver))) { - printk - ("thmc50.o: Driver deregistration failed, module not removed.\n"); - return res; - } - thmc50_initialized--; - } - - return 0; + i2c_del_driver(&thmc50_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR ("Frodo Looijaard and Philip Edelbrock "); MODULE_DESCRIPTION("THMC50 driver"); -int init_module(void) -{ - return sensors_thmc50_init(); -} - -int cleanup_module(void) -{ - return thmc50_cleanup(); -} - -#endif /* MODULE */ +module_init(sm_thmc50_init); +module_exit(sm_thmc50_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/via686a.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/via686a.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/via686a.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/via686a.c 2003-08-17 21:26:58.000000000 +0200 @@ -30,39 +30,18 @@ See doc/chips/via686a for details. Warning - only supports a single device. */ -#include + #include #include -#include -#include -#include #include -#include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include +#include #include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -#ifndef PCI_DEVICE_ID_VIA_82C686_4 -#define PCI_DEVICE_ID_VIA_82C686_4 0x3057 -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ @@ -127,7 +106,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e // 10 comparator mode- like 00, but ignores hysteresis // 11 same as 00 #define VIA686A_REG_TEMP_MODE 0x4b -// We'll just assume that you want to set all 3 simulataneously: +// We'll just assume that you want to set all 3 simultaneously: #define VIA686A_TEMP_MODE_MASK 0x3F #define VIA686A_TEMP_MODE_CONTINUOUS (0x00) @@ -150,7 +129,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e // // These get us close, but they don't completely agree with what my BIOS // says- they are all a bit low. But, it all we have to go on... -extern inline u8 IN_TO_REG(long val, int inNum) +static inline u8 IN_TO_REG(long val, int inNum) { // to avoid floating point, we multiply everything by 100. // val is guaranteed to be positive, so we can achieve the effect of @@ -175,7 +154,7 @@ extern inline u8 IN_TO_REG(long val, int / 1000, 0, 255); } -extern inline long IN_FROM_REG(u8 val, int inNum) +static inline long IN_FROM_REG(u8 val, int inNum) { // to avoid floating point, we multiply everything by 100. // val is guaranteed to be positive, so we can achieve the effect of @@ -195,7 +174,7 @@ extern inline long IN_FROM_REG(u8 val, i // Higher register values = slower fans (the fan's strobe gates a counter). // But this chip saturates back at 0, not at 255 like all the other chips. // So, 0 means 0 RPM -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 0; @@ -303,7 +282,7 @@ static const u8 viaLUT[] = // No interpolation here. Just check the limits and go. // The +5 effectively rounds off properly and the +50 is because // the temps start at -50 -extern inline u8 TEMP_TO_REG(long val) +static inline u8 TEMP_TO_REG(long val) { return (u8) SENSORS_LIMIT(viaLUT[((val <= -500) ? 0 : (val >= 1100) ? 160 : @@ -318,7 +297,7 @@ extern inline u8 TEMP_TO_REG(long val) /* for 10-bit temperature readings */ // You might _think_ this is too long to inline, but's it's really only // called once... -extern inline long TEMP_FROM_REG10(u16 val) +static inline long TEMP_FROM_REG10(u16 val) { // the temp values are already *10, so we don't need to do that. long temp; @@ -387,11 +366,6 @@ extern inline long TEMP_FROM_REG10(u16 v #define VIA686A_INIT_TEMP_OVER 600 #define VIA686A_INIT_TEMP_HYST 500 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* For the VIA686A, we need to keep some data in memory. That data is pointed to by via686a_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new via686a client is @@ -418,29 +392,16 @@ struct via686a_data { static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_via686a_init(void); -static int __init via686a_cleanup(void); - static int via686a_attach_adapter(struct i2c_adapter *adapter); static int via686a_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int via686a_detach_client(struct i2c_client *client); -static int via686a_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void via686a_inc_use(struct i2c_client *client); -static void via686a_dec_use(struct i2c_client *client); static int via686a_read_value(struct i2c_client *client, u8 register); static void via686a_write_value(struct i2c_client *client, u8 register, u8 value); static void via686a_update_client(struct i2c_client *client); static void via686a_init_client(struct i2c_client *client); -static int via686a_find(int *address); static void via686a_in(struct i2c_client *client, int operation, @@ -459,20 +420,46 @@ static int via686a_id = 0; /* The driver. I choose to use type i2c_driver, as at is identical to both smbus_driver and isa_driver, and clients could be of either kind */ static struct i2c_driver via686a_driver = { - /* name */ "VIA 686A", - /* id */ I2C_DRIVERID_VIA686A, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &via686a_attach_adapter, - /* detach_client */ &via686a_detach_client, - /* command */ &via686a_command, - /* inc_use */ &via686a_inc_use, - /* dec_use */ &via686a_dec_use + .owner = THIS_MODULE, + .name = "VIA 686A", + .id = I2C_DRIVERID_VIA686A, + .flags = I2C_DF_NOTIFY, + .attach_adapter = via686a_attach_adapter, + .detach_client = via686a_detach_client, }; -/* Used by via686a_init/cleanup */ -static int __initdata via686a_initialized = 0; + /* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define VIA686A_SYSCTL_IN0 1000 +#define VIA686A_SYSCTL_IN1 1001 +#define VIA686A_SYSCTL_IN2 1002 +#define VIA686A_SYSCTL_IN3 1003 +#define VIA686A_SYSCTL_IN4 1004 +#define VIA686A_SYSCTL_FAN1 1101 +#define VIA686A_SYSCTL_FAN2 1102 +#define VIA686A_SYSCTL_TEMP 1200 +#define VIA686A_SYSCTL_TEMP2 1201 +#define VIA686A_SYSCTL_TEMP3 1202 +#define VIA686A_SYSCTL_FAN_DIV 2000 +#define VIA686A_SYSCTL_ALARMS 2001 + +#define VIA686A_ALARM_IN0 0x01 +#define VIA686A_ALARM_IN1 0x02 +#define VIA686A_ALARM_IN2 0x04 +#define VIA686A_ALARM_IN3 0x08 +#define VIA686A_ALARM_TEMP 0x10 +#define VIA686A_ALARM_FAN1 0x40 +#define VIA686A_ALARM_FAN2 0x80 +#define VIA686A_ALARM_IN4 0x100 +#define VIA686A_ALARM_TEMP2 0x800 +#define VIA686A_ALARM_CHAS 0x1000 +#define VIA686A_ALARM_TEMP3 0x8000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected VIA686A. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -518,38 +505,11 @@ static inline void via686a_write_value(s } /* This is called when the module is loaded */ -int via686a_attach_adapter(struct i2c_adapter *adapter) +static int via686a_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, via686a_detect); } -/* Locate chip and get correct base address */ -int via686a_find(int *address) -{ - u16 val; - - if (!pci_present()) - return -ENODEV; - - if (!(s_bridge = pci_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C686_4, - NULL))) - return -ENODEV; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_BASE_REG, &val)) - return -ENODEV; - *address = val & ~(VIA686A_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("via686a.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - return 0; -} - int via686a_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind) { @@ -625,8 +585,7 @@ int via686a_detect(struct i2c_adapter *a /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry((struct i2c_client *) new_client, type_name, - via686a_dir_table_template, - THIS_MODULE)) < 0) { + via686a_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -645,7 +604,7 @@ int via686a_detect(struct i2c_adapter *a return err; } -int via686a_detach_client(struct i2c_client *client) +static int via686a_detach_client(struct i2c_client *client) { int err; @@ -664,24 +623,8 @@ int via686a_detach_client(struct i2c_cli return 0; } -/* No commands defined yet */ -int via686a_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void via686a_inc_use(struct i2c_client *client) -{ - MOD_INC_USE_COUNT; -} - -void via686a_dec_use(struct i2c_client *client) -{ - MOD_DEC_USE_COUNT; -} - /* Called when we have found a new VIA686A. Set limits, etc. */ -void via686a_init_client(struct i2c_client *client) +static void via686a_init_client(struct i2c_client *client) { int i; @@ -735,15 +678,15 @@ void via686a_init_client(struct i2c_clie !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); } -void via686a_update_client(struct i2c_client *client) +static void via686a_update_client(struct i2c_client *client) { struct via686a_data *data = client->data; int i; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || + time_before(jiffies, data->last_updated) || !data->valid) { for (i = 0; i <= 4; i++) { data->in[i] = @@ -813,8 +756,8 @@ void via686a_update_client(struct i2c_cl large enough (by checking the incoming value of *nrels). This is not very good practice, but as long as you put less than about 5 values in results, you can assume it is large enough. */ -void via686a_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +static void via686a_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) { struct via686a_data *data = client->data; int nr = ctl_name - VIA686A_SYSCTL_IN0; @@ -940,59 +883,67 @@ void via686a_fan_div(struct i2c_client * } } -int __init sensors_via686a_init(void) -{ - int res, addr; - printk("via686a.o version %s (%s)\n", LM_VERSION, LM_DATE); - via686a_initialized = 0; - - if (via686a_find(&addr)) { - printk("via686a.o: No Via 686A sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - if ((res = i2c_add_driver(&via686a_driver))) { - printk("via686a.o: Driver registration failed.\n"); - via686a_cleanup(); - return res; - } - via686a_initialized++; - return 0; -} +static struct pci_device_id via686a_pci_ids[] __devinitdata = { + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; -int __init via686a_cleanup(void) +static int __devinit via686a_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int res; - - if (via686a_initialized >= 1) { - if ((res = i2c_del_driver(&via686a_driver))) { - printk - ("via686a.o: Driver deregistration failed.\n"); - return res; - } - via686a_initialized--; - } - return 0; -} - -EXPORT_NO_SYMBOLS; + u16 val; + int addr = 0; -#ifdef MODULE - -MODULE_AUTHOR - ("Kyösti Mälkki , Mark Studebaker , Bob Dougherty "); -MODULE_DESCRIPTION("VIA 686A Sensor device"); + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, VIA686A_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(VIA686A_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + printk("via686a.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + printk("via686a.o: No Via 686A sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + s_bridge = dev; + return i2c_add_driver(&via686a_driver); +} + +static void __devexit via686a_pci_remove(struct pci_dev *dev) +{ + i2c_del_driver(&via686a_driver); +} + +static struct pci_driver via686a_pci_driver = { + .name = "via686a", + .id_table = via686a_pci_ids, + .probe = via686a_pci_probe, + .remove = __devexit_p(via686a_pci_remove), +}; -int init_module(void) +static int __init sm_via686a_init(void) { - return sensors_via686a_init(); + printk("via686a.o version %s (%s)\n", LM_VERSION, LM_DATE); + return pci_module_init(&via686a_pci_driver); } -int cleanup_module(void) +static void __exit sm_via686a_exit(void) { - return via686a_cleanup(); + pci_unregister_driver(&via686a_pci_driver); } -#endif /* MODULE */ +MODULE_AUTHOR("Kyösti Mälkki , " + "Mark Studebaker " + "and Bob Dougherty "); +MODULE_DESCRIPTION("VIA 686A Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_via686a_init); +module_exit(sm_via686a_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/vt1211.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/vt1211.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/vt1211.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/vt1211.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,30 +21,20 @@ /* Supports VIA VT1211 Super I/O sensors via ISA (LPC) accesses only. */ -#include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include -#include +#include #include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include static int force_addr = 0; MODULE_PARM(force_addr, "i"); @@ -178,7 +168,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e /********* FAN RPM CONVERSIONS ********/ /* But this chip saturates back at 0, not at 255 like all the other chips. So, 0 means 0 RPM */ -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 0; @@ -189,11 +179,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define MIN_TO_REG(a,b) FAN_TO_REG(a,b) #define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div))) -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - struct vt1211_data { struct semaphore lock; int sysctl_id; @@ -219,22 +204,10 @@ struct vt1211_data { u8 uch_config; }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_vt1211_init(void); -static int __init vt1211_cleanup(void); - static int vt1211_attach_adapter(struct i2c_adapter *adapter); static int vt1211_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int vt1211_detach_client(struct i2c_client *client); -static int vt1211_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void vt1211_inc_use(struct i2c_client *client); -static void vt1211_dec_use(struct i2c_client *client); static inline int vt_rdval(struct i2c_client *client, u8 register); static inline void vt1211_write_value(struct i2c_client *client, u8 register, @@ -266,17 +239,59 @@ static void vt1211_temp(struct i2c_clien static int vt1211_id = 0; static struct i2c_driver vt1211_driver = { - /* name */ "VT1211 sensors driver", - /* id */ I2C_DRIVERID_VT1211, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &vt1211_attach_adapter, - /* detach_client */ &vt1211_detach_client, - /* command */ &vt1211_command, - /* inc_use */ &vt1211_inc_use, - /* dec_use */ &vt1211_dec_use + .owner = THIS_MODULE, + .name = "VT1211 sensors driver", + .id = I2C_DRIVERID_VT1211, + .flags = I2C_DF_NOTIFY, + .attach_adapter = vt1211_attach_adapter, + .detach_client = vt1211_detach_client, }; -static int __initdata vt1211_initialized = 0; +/* -- SENSORS SYSCTL START -- */ +#define VT1211_SYSCTL_IN0 1000 +#define VT1211_SYSCTL_IN1 1001 +#define VT1211_SYSCTL_IN2 1002 +#define VT1211_SYSCTL_IN3 1003 +#define VT1211_SYSCTL_IN4 1004 +#define VT1211_SYSCTL_IN5 1005 +#define VT1211_SYSCTL_IN6 1006 +#define VT1211_SYSCTL_FAN1 1101 +#define VT1211_SYSCTL_FAN2 1102 +#define VT1211_SYSCTL_TEMP 1200 +#define VT1211_SYSCTL_TEMP2 1201 +#define VT1211_SYSCTL_TEMP3 1202 +#define VT1211_SYSCTL_TEMP4 1203 +#define VT1211_SYSCTL_TEMP5 1204 +#define VT1211_SYSCTL_TEMP6 1205 +#define VT1211_SYSCTL_TEMP7 1206 +#define VT1211_SYSCTL_VID 1300 +#define VT1211_SYSCTL_PWM1 1401 +#define VT1211_SYSCTL_PWM2 1402 +#define VT1211_SYSCTL_VRM 1600 +#define VT1211_SYSCTL_UCH 1700 +#define VT1211_SYSCTL_FAN_DIV 2000 +#define VT1211_SYSCTL_ALARMS 2001 + +#define VT1211_ALARM_IN1 0x01 +#define VT1211_ALARM_IN2 0x02 +#define VT1211_ALARM_IN5 0x04 +#define VT1211_ALARM_IN3 0x08 +#define VT1211_ALARM_TEMP 0x10 +#define VT1211_ALARM_FAN1 0x40 +#define VT1211_ALARM_FAN2 0x80 +#define VT1211_ALARM_IN4 0x100 +#define VT1211_ALARM_IN6 0x200 +#define VT1211_ALARM_TEMP2 0x800 +#define VT1211_ALARM_CHAS 0x1000 +#define VT1211_ALARM_TEMP3 0x8000 +/* duplicates */ +#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP +#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 +#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 +#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 +#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 + +/* -- SENSORS SYSCTL END -- */ static ctl_table vt1211_dir_table_template[] = { {VT1211_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, @@ -328,12 +343,12 @@ static ctl_table vt1211_dir_table_templa {0} }; -int vt1211_attach_adapter(struct i2c_adapter *adapter) +static int vt1211_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, vt1211_detect); } -int vt1211_find(int *address) +static int vt1211_find(int *address) { u16 val; @@ -422,8 +437,7 @@ int vt1211_detect(struct i2c_adapter *ad if ((i = i2c_register_entry((struct i2c_client *) new_client, type_name, - vt1211_dir_table_template, - THIS_MODULE)) < 0) { + vt1211_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -440,7 +454,7 @@ int vt1211_detect(struct i2c_adapter *ad return err; } -int vt1211_detach_client(struct i2c_client *client) +static int vt1211_detach_client(struct i2c_client *client) { int err; @@ -459,25 +473,6 @@ int vt1211_detach_client(struct i2c_clie return 0; } -int vt1211_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void vt1211_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void vt1211_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - static inline int vt_rdval(struct i2c_client *client, u8 reg) { return (inb_p(client->addr + reg)); @@ -488,7 +483,7 @@ static inline void vt1211_write_value(st outb_p(value, client->addr + reg); } -void vt1211_init_client(struct i2c_client *client) +static void vt1211_init_client(struct i2c_client *client) { struct vt1211_data *data = client->data; @@ -498,15 +493,15 @@ void vt1211_init_client(struct i2c_clien vt1211_write_value(client, VT1211_REG_TEMP2_CONFIG, 0); } -void vt1211_update_client(struct i2c_client *client) +static void vt1211_update_client(struct i2c_client *client) { struct vt1211_data *data = client->data; int i, j; down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { data->uch_config = vt_rdval(client, VT1211_REG_UCH_CONFIG); for (i = 0; i <= 6; i++) { if(ISVOLT(i, data->uch_config)) { @@ -800,12 +795,11 @@ void vt1211_uch(struct i2c_client *clien } } -int __init sensors_vt1211_init(void) +static int __init sm_vt1211_init(void) { - int res, addr; + int addr; printk("vt1211.o version %s (%s)\n", LM_VERSION, LM_DATE); - vt1211_initialized = 0; if (vt1211_find(&addr)) { printk("vt1211.o: VT1211 not detected, module not inserted.\n"); @@ -813,49 +807,19 @@ int __init sensors_vt1211_init(void) } normal_isa[0] = addr; - if ((res = i2c_add_driver(&vt1211_driver))) { - printk - ("vt1211.o: Driver registration failed, module not inserted.\n"); - vt1211_cleanup(); - return res; - } - vt1211_initialized++; - return 0; + return i2c_add_driver(&vt1211_driver); } -int __init vt1211_cleanup(void) +static void __exit sm_vt1211_exit(void) { - int res; - - if (vt1211_initialized >= 1) { - if ((res = i2c_del_driver(&vt1211_driver))) { - printk - ("vt1211.o: Driver deregistration failed, module not removed.\n"); - return res; - } - vt1211_initialized--; - } - return 0; + i2c_del_driver(&vt1211_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Mark D. Studebaker "); MODULE_DESCRIPTION("VT1211 sensors"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return sensors_vt1211_init(); -} - -int cleanup_module(void) -{ - return vt1211_cleanup(); -} -#endif /* MODULE */ +module_init(sm_vt1211_init); +module_exit(sm_vt1211_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/vt8231.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/vt8231.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/vt8231.c 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/vt8231.c 2003-08-17 21:26:58.000000000 +0200 @@ -21,31 +21,22 @@ /* Supports VIA VT8231 Super I/O embedded sensors */ -#include #include #include #include #include #include #include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include -#include +#include #include +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif static int force_addr = 0; MODULE_PARM(force_addr, "i"); @@ -136,7 +127,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e /********* FAN RPM CONVERSIONS ********/ /* But this chip saturates back at 0, not at 255 like all the other chips. So, 0 means 0 RPM */ -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 0; @@ -147,11 +138,6 @@ extern inline u8 FAN_TO_REG(long rpm, in #define MIN_TO_REG(a,b) FAN_TO_REG(a,b) #define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div))) -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - struct vt8231_data { struct semaphore lock; int sysctl_id; @@ -177,22 +163,10 @@ struct vt8231_data { u8 uch_config; }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_vt8231_init(void); -static int __init vt8231_cleanup(void); - static int vt8231_attach_adapter(struct i2c_adapter *adapter); static int vt8231_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int vt8231_detach_client(struct i2c_client *client); -static int vt8231_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void vt8231_inc_use(struct i2c_client *client); -static void vt8231_dec_use(struct i2c_client *client); static inline int vt_rdval(struct i2c_client *client, u8 register); static inline void vt8231_write_value(struct i2c_client *client, u8 register, @@ -224,17 +198,59 @@ static void vt8231_temp(struct i2c_clien static int vt8231_id = 0; static struct i2c_driver vt8231_driver = { - /* name */ "VT8231 sensors driver", - /* id */ I2C_DRIVERID_VT8231, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &vt8231_attach_adapter, - /* detach_client */ &vt8231_detach_client, - /* command */ &vt8231_command, - /* inc_use */ &vt8231_inc_use, - /* dec_use */ &vt8231_dec_use + .owner = THIS_MODULE, + .name = "VT8231 sensors driver", + .id = I2C_DRIVERID_VT8231, + .flags = I2C_DF_NOTIFY, + .attach_adapter = vt8231_attach_adapter, + .detach_client = vt8231_detach_client, }; -static int __initdata vt8231_initialized = 0; +/* -- SENSORS SYSCTL START -- */ +#define VT8231_SYSCTL_IN0 1000 +#define VT8231_SYSCTL_IN1 1001 +#define VT8231_SYSCTL_IN2 1002 +#define VT8231_SYSCTL_IN3 1003 +#define VT8231_SYSCTL_IN4 1004 +#define VT8231_SYSCTL_IN5 1005 +#define VT8231_SYSCTL_IN6 1006 +#define VT8231_SYSCTL_FAN1 1101 +#define VT8231_SYSCTL_FAN2 1102 +#define VT8231_SYSCTL_TEMP 1200 +#define VT8231_SYSCTL_TEMP2 1201 +#define VT8231_SYSCTL_TEMP3 1202 +#define VT8231_SYSCTL_TEMP4 1203 +#define VT8231_SYSCTL_TEMP5 1204 +#define VT8231_SYSCTL_TEMP6 1205 +#define VT8231_SYSCTL_TEMP7 1206 +#define VT8231_SYSCTL_VID 1300 +#define VT8231_SYSCTL_PWM1 1401 +#define VT8231_SYSCTL_PWM2 1402 +#define VT8231_SYSCTL_VRM 1600 +#define VT8231_SYSCTL_UCH 1700 +#define VT8231_SYSCTL_FAN_DIV 2000 +#define VT8231_SYSCTL_ALARMS 2001 + +#define VT8231_ALARM_IN1 0x01 +#define VT8231_ALARM_IN2 0x02 +#define VT8231_ALARM_IN5 0x04 +#define VT8231_ALARM_IN3 0x08 +#define VT8231_ALARM_TEMP 0x10 +#define VT8231_ALARM_FAN1 0x40 +#define VT8231_ALARM_FAN2 0x80 +#define VT8231_ALARM_IN4 0x100 +#define VT8231_ALARM_IN6 0x200 +#define VT8231_ALARM_TEMP2 0x800 +#define VT8231_ALARM_CHAS 0x1000 +#define VT8231_ALARM_TEMP3 0x8000 +/* duplicates */ +#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP +#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN1 +#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN2 +#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN3 +#define VT8231_ALARM_TEMP7 VT8231_ALARM_IN4 + +/* -- SENSORS SYSCTL END -- */ static ctl_table vt8231_dir_table_template[] = { {VT8231_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, @@ -288,13 +304,13 @@ static ctl_table vt8231_dir_table_templa static struct pci_dev *s_bridge; -int vt8231_attach_adapter(struct i2c_adapter *adapter) +static int vt8231_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, vt8231_detect); } /* Locate chip and get correct base address */ -int vt8231_find(int *address) +static int vt8231_find(int *address) { u16 val; @@ -391,8 +407,7 @@ int vt8231_detect(struct i2c_adapter *ad /* Register a new directory entry with module sensors */ if ((i = i2c_register_entry((struct i2c_client *) new_client, type_name, - vt8231_dir_table_template, - THIS_MODULE)) < 0) { + vt8231_dir_table_template)) < 0) { err = i; goto ERROR4; } @@ -410,7 +425,7 @@ int vt8231_detect(struct i2c_adapter *ad return err; } -int vt8231_detach_client(struct i2c_client *client) +static int vt8231_detach_client(struct i2c_client *client) { int err; @@ -429,24 +444,6 @@ int vt8231_detach_client(struct i2c_clie return 0; } -int vt8231_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void vt8231_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void vt8231_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} static inline int vt_rdval(struct i2c_client *client, u8 reg) { @@ -458,7 +455,7 @@ static inline void vt8231_write_value(st outb_p(value, client->addr + reg); } -void vt8231_init_client(struct i2c_client *client) +static void vt8231_init_client(struct i2c_client *client) { struct vt8231_data *data = client->data; @@ -468,7 +465,7 @@ void vt8231_init_client(struct i2c_clien vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0); } -void vt8231_update_client(struct i2c_client *client) +static void vt8231_update_client(struct i2c_client *client) { struct vt8231_data *data = client->data; int i, j; @@ -770,12 +767,11 @@ void vt8231_uch(struct i2c_client *clien } } -int __init sensors_vt8231_init(void) +static int __init sm_vt8231_init(void) { - int res, addr; + int addr; printk("vt8231.o version %s (%s)\n", LM_VERSION, LM_DATE); - vt8231_initialized = 0; if (vt8231_find(&addr)) { printk("vt8231.o: VT8231 not detected, module not inserted.\n"); @@ -783,49 +779,18 @@ int __init sensors_vt8231_init(void) } normal_isa[0] = addr; - if ((res = i2c_add_driver(&vt8231_driver))) { - printk - ("vt8231.o: Driver registration failed, module not inserted.\n"); - vt8231_cleanup(); - return res; - } - vt8231_initialized++; - return 0; -} + return i2c_add_driver(&vt8231_driver);} -int __init vt8231_cleanup(void) +static void __exit sm_vt8231_exit(void) { - int res; - - if (vt8231_initialized >= 1) { - if ((res = i2c_del_driver(&vt8231_driver))) { - printk - ("vt8231.o: Driver deregistration failed, module not removed.\n"); - return res; - } - vt8231_initialized--; - } - return 0; + i2c_del_driver(&vt8231_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Mark D. Studebaker "); MODULE_DESCRIPTION("VT8231 sensors"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - -int init_module(void) -{ - return sensors_vt8231_init(); -} - -int cleanup_module(void) -{ - return vt8231_cleanup(); -} -#endif /* MODULE */ +module_init(sm_vt8231_init); +module_exit(sm_vt8231_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/w83781d.c linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/w83781d.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/sensors/w83781d.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/sensors/w83781d.c 2003-08-17 21:26:58.000000000 +0200 @@ -1,7 +1,7 @@ /* w83781d.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard , + Copyright (c) 1998 - 2003 Frodo Looijaard , Philip Edelbrock , and Mark Studebaker @@ -26,38 +26,27 @@ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA as99127f 7 3 1? 3 0x30 0x12c3 yes no asb100 "bach" (type_name = as99127f) 0x30 0x0694 yes no - w83781d 7 3 0 3 0x10 0x5ca3 yes yes w83627hf 9 3 2 3 0x20 0x5ca3 yes yes(LPC) + w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + w83781d 7 3 0 3 0x10 0x5ca3 yes yes w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + w83791d 10 5 5 3 0x70 0x5ca3 yes no */ -#include #include #include -#include #include -#include -#include -#include #include #include -#define LM_DATE "20021208" -#define LM_VERSION "2.7.0" -#include -#include +#include #include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0)) -#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) -#endif - -#ifndef THIS_MODULE -#define THIS_MODULE NULL -#endif +#include +#include +#define LM_DATE "20030714" +#define LM_VERSION "2.8.0" +#include /* RT Table support #defined so we can take it out if it gets bothersome */ #define W83781D_RT 1 @@ -69,7 +58,7 @@ static unsigned int normal_isa[] = { 0x0 static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf); +SENSORS_INSMOD_7(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf, w83791d); SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ "{bus, clientaddr, subclientaddr1, subclientaddr2}"); @@ -95,8 +84,17 @@ MODULE_PARM_DESC(init, "Set to zero to b #define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ (0x550 + (nr) - 7)) -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) +#define W83791D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ + (0xb4 + (((nr) - 7) * 2))) +#define W83791D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ + (0xb5 + (((nr) - 7) * 2))) +#define W83791D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ + (0xb0 + (nr) - 7)) + +#define W83781D_REG_FAN_MIN(nr) ((nr < 4) ? (0x3a + (nr)) : \ + (0xba + (nr) - 4)) +#define W83781D_REG_FAN(nr) ((nr < 4) ? (0x27 + (nr)) : \ + (0xbc + (nr) - 4)) #define W83781D_REG_TEMP2 0x0150 #define W83781D_REG_TEMP3 0x0250 @@ -142,10 +140,23 @@ MODULE_PARM_DESC(init, "Set to zero to b #define W83781D_REG_PWM4 0x5F #define W83781D_REG_PWMCLK12 0x5C #define W83781D_REG_PWMCLK34 0x45C + +#define W83791D_REG_PWM1 0x88 /* 782d and 783s/627hf datasheets disagree */ + /* on which is which; */ +#define W83791D_REG_PWM2 0x89 /* We follow the 782d convention here, */ + /* However 782d is probably wrong. */ +#define W83791D_REG_PWM3 0x98 + static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, W83781D_REG_PWM3, W83781D_REG_PWM4 }; + +static const u8 regpwm_w83791d[] = { W83791D_REG_PWM1, W83791D_REG_PWM2, + W83791D_REG_PWM3 +}; + #define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) +#define W83791D_REG_PWM(nr) (regpwm_w83791d[(nr) - 1]) #define W83781D_REG_I2C_ADDR 0x48 #define W83781D_REG_I2C_SUBADDR 0x4A @@ -170,7 +181,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x #define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) #define IN_FROM_REG(val) (((val) * 16) / 10) -extern inline u8 FAN_TO_REG(long rpm, int div) +static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; @@ -204,7 +215,7 @@ extern inline u8 FAN_TO_REG(long rpm, in #define DIV_FROM_REG(val) (1 << (val)) -extern inline u8 DIV_TO_REG(long val, enum chips type) +static inline u8 DIV_TO_REG(long val, enum chips type) { int i; val = SENSORS_LIMIT(val, 1, @@ -227,6 +238,7 @@ extern inline u8 DIV_TO_REG(long val, en #define W83781D_INIT_IN_6 (((-500) * -604)/909) #define W83781D_INIT_IN_7 (((500) * 100)/168) #define W83781D_INIT_IN_8 300 +#define W83781D_INIT_IN_9 250 /* 2.5 Volt for the DDR interface. */ /* Initial limits for 782d/783s negative voltages */ /* Note level shift. Change min/max below if you change these. */ #define W83782D_INIT_IN_5 ((((-1200) + 1491) * 100)/514) @@ -288,6 +300,12 @@ extern inline u8 DIV_TO_REG(long val, en #define W83781D_INIT_IN_MAX_8 \ (W83781D_INIT_IN_8 + W83781D_INIT_IN_8 * W83781D_INIT_IN_PERCENTAGE \ / 100) +#define W83781D_INIT_IN_MIN_9 \ + (W83781D_INIT_IN_9 - W83781D_INIT_IN_9 * W83781D_INIT_IN_PERCENTAGE \ + / 100) +#define W83781D_INIT_IN_MAX_9 \ + (W83781D_INIT_IN_9 + W83781D_INIT_IN_9 * W83781D_INIT_IN_PERCENTAGE \ + / 100) /* Initial limits for 782d/783s negative voltages */ /* These aren't direct multiples because of level shift */ /* Beware going negative - check */ @@ -315,11 +333,6 @@ extern inline u8 DIV_TO_REG(long val, en #define W83781D_INIT_TEMP3_OVER 600 #define W83781D_INIT_TEMP3_HYST 500 -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - /* There are some complications in a module like this. First off, W83781D chips may be both present on the SMBus and the ISA bus, and we have to handle those cases separately at some places. Second, there might be several @@ -351,11 +364,11 @@ struct w83781d_data { struct i2c_client *lm75; /* for secondary I2C addresses */ /* pointer to array of 2 subclients */ - u8 in[9]; /* Register value - 8 & 9 for 782D only */ - u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ - u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ + u8 in[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ + u8 in_max[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ + u8 in_min[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ + u8 fan[5]; /* Register value - 4 & 5 for 791D only */ + u8 fan_min[5]; /* Register value - 4 & 5 for 791D only */ u8 temp; u8 temp_over; /* Register value */ u8 temp_hyst; /* Register value */ @@ -381,22 +394,10 @@ struct w83781d_data { }; -#ifdef MODULE -static -#else -extern -#endif -int __init sensors_w83781d_init(void); -static int __init w83781d_cleanup(void); - static int w83781d_attach_adapter(struct i2c_adapter *adapter); static int w83781d_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind); static int w83781d_detach_client(struct i2c_client *client); -static int w83781d_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void w83781d_inc_use(struct i2c_client *client); -static void w83781d_dec_use(struct i2c_client *client); static int w83781d_read_value(struct i2c_client *client, u16 register); static int w83781d_write_value(struct i2c_client *client, u16 register, @@ -436,20 +437,72 @@ static u16 swap_bytes(u16 val); static int w83781d_id = 0; static struct i2c_driver w83781d_driver = { - /* name */ "W83781D sensor driver", - /* id */ I2C_DRIVERID_W83781D, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &w83781d_attach_adapter, - /* detach_client */ &w83781d_detach_client, - /* command */ &w83781d_command, - /* inc_use */ &w83781d_inc_use, - /* dec_use */ &w83781d_dec_use + .owner = THIS_MODULE, + .name = "W83781D sensor driver", + .id = I2C_DRIVERID_W83781D, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83781d_attach_adapter, + .detach_client = w83781d_detach_client, }; -/* Used by w83781d_init/cleanup */ -static int __initdata w83781d_initialized = 0; - /* The /proc/sys entries */ +/* -- SENSORS SYSCTL START -- */ + +#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ +#define W83781D_SYSCTL_IN1 1001 +#define W83781D_SYSCTL_IN2 1002 +#define W83781D_SYSCTL_IN3 1003 +#define W83781D_SYSCTL_IN4 1004 +#define W83781D_SYSCTL_IN5 1005 +#define W83781D_SYSCTL_IN6 1006 +#define W83781D_SYSCTL_IN7 1007 +#define W83781D_SYSCTL_IN8 1008 +#define W83781D_SYSCTL_IN9 1009 +#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ +#define W83781D_SYSCTL_FAN2 1102 +#define W83781D_SYSCTL_FAN3 1103 +#define W83781D_SYSCTL_FAN4 1104 +#define W83781D_SYSCTL_FAN5 1105 + +#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ +#define W83781D_SYSCTL_VRM 1301 +#define W83781D_SYSCTL_PWM1 1401 +#define W83781D_SYSCTL_PWM2 1402 +#define W83781D_SYSCTL_PWM3 1403 +#define W83781D_SYSCTL_PWM4 1404 +#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define W83781D_SYSCTL_SENS2 1502 +#define W83781D_SYSCTL_SENS3 1503 +#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ +#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ +#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ +#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ +#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ + +#define W83781D_ALARM_IN0 0x0001 +#define W83781D_ALARM_IN1 0x0002 +#define W83781D_ALARM_IN2 0x0004 +#define W83781D_ALARM_IN3 0x0008 +#define W83781D_ALARM_IN4 0x0100 +#define W83781D_ALARM_IN5 0x0200 +#define W83781D_ALARM_IN6 0x0400 +#define W83782D_ALARM_IN7 0x10000 +#define W83782D_ALARM_IN8 0x20000 +#define W83781D_ALARM_FAN1 0x0040 +#define W83781D_ALARM_FAN2 0x0080 +#define W83781D_ALARM_FAN3 0x0800 +#define W83781D_ALARM_TEMP1 0x0010 +#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ +#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ +#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ +#define W83781D_ALARM_CHAS 0x1000 + +/* -- SENSORS SYSCTL END -- */ + /* These files are created for each detected chip. This is just a template; though at first sight, you might think we could use a statically allocated list, we need some way to get back to the parent - which @@ -569,7 +622,7 @@ static ctl_table w83782d_isa_dir_table_t &i2c_sysctl_real, NULL, &w83781d_in}, {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, +{W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &w83781d_fan}, {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &w83781d_fan}, @@ -663,6 +716,66 @@ static ctl_table w83782d_i2c_dir_table_t {0} }; +/* w83791D has 10 voltages 5 fans and 3 temps. 2 of the temps are on other + devices. */ +static ctl_table w83791d_dir_table_template[] = { + {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_in}, + {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_fan}, + {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_fan}, + {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_fan}, + {W83781D_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_fan}, + {W83781D_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_fan}, + {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_temp}, + {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_temp_add}, + {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_temp_add}, + {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_vid}, + {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_fan_div}, + {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_alarms}, + {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_beep}, + {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_pwm}, + {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_pwm}, + {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_pwm}, + {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_pwm}, + {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &w83781d_vrm}, + {0} +}; + static ctl_table w83783s_dir_table_template[] = { {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &w83781d_in}, @@ -757,13 +870,13 @@ static ctl_table w83697hf_dir_table_temp * w83781d_driver is inserted (when this module is loaded), for each available adapter * when a new adapter is inserted (and w83781d_driver is still present) */ -int w83781d_attach_adapter(struct i2c_adapter *adapter) +static int w83781d_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, w83781d_detect); } -int w83781d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) +static int w83781d_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) { int i, val1 = 0, val2, id; struct i2c_client *new_client; @@ -779,10 +892,11 @@ int w83781d_detect(struct i2c_adapter *a I2C_FUNC_SMBUS_BYTE_DATA)) goto ERROR0; - if (is_isa) { - if (check_region(address, W83781D_EXTENT)) - goto ERROR0; - } + if (is_isa) { + if (!request_region(address, W83781D_EXTENT, "w83781d")) + goto ERROR0; + release_region(address, W83781D_EXTENT); + } /* Probe whether there is anything available on this address. Already done for SMBus clients */ @@ -885,6 +999,8 @@ int w83781d_detect(struct i2c_adapter *a kind = w83783s; else if (val1 == 0x20 && vendid == winbond) kind = w83627hf; + else if (val1 == 0x70 && vendid == winbond) + kind = w83791d; else if (val1 == 0x30 && vendid == asus && !is_isa) kind = as99127f; else if (val1 == 0x60 && vendid == winbond && is_isa) @@ -917,6 +1033,9 @@ int w83781d_detect(struct i2c_adapter *a } else if (kind == w83697hf) { type_name = "w83697hf"; client_name = "W83697HF chip"; + } else if (kind == w83791d) { + type_name = "w83791d"; + client_name = "W83791D chip"; } else { #ifdef DEBUG printk(KERN_ERR "w83781d.o: Internal error: unknown kind (%d)?!?", @@ -991,6 +1110,9 @@ int w83781d_detect(struct i2c_adapter *a client_name = "W83627HF subclient"; else if (kind == as99127f) client_name = "AS99127F subclient"; + else if (kind == w83791d) + client_name = "W83791D subclient"; + for (i = 0; i <= 1; i++) { data->lm75[i].data = NULL; /* store all data in w83781d */ @@ -1024,10 +1146,11 @@ int w83781d_detect(struct i2c_adapter *a w83783s_dir_table_template : (kind == w83697hf) ? w83697hf_dir_table_template : - (is_isa || kind == w83627hf) ? + (kind == w83791d ) ? + w83791d_dir_table_template : + (is_isa || kind == w83627hf) ? w83782d_isa_dir_table_template : - w83782d_i2c_dir_table_template, - THIS_MODULE)) < 0) { + w83782d_i2c_dir_table_template)) < 0) { err = i; goto ERROR7; } @@ -1066,7 +1189,7 @@ int w83781d_detect(struct i2c_adapter *a return err; } -int w83781d_detach_client(struct i2c_client *client) +static int w83781d_detach_client(struct i2c_client *client) { int err; @@ -1098,27 +1221,7 @@ int w83781d_detach_client(struct i2c_cli return 0; } -/* No commands defined yet */ -int w83781d_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void w83781d_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void w83781d_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) +static inline u16 swap_bytes(u16 val) { return (val >> 8) | (val << 8); } @@ -1129,7 +1232,7 @@ u16 swap_bytes(u16 val) would slow down the W83781D access and should not be necessary. There are some ugly typecasts here, but the good news is - they should nowhere else be necessary! */ -int w83781d_read_value(struct i2c_client *client, u16 reg) +static int w83781d_read_value(struct i2c_client *client, u16 reg) { int res, word_sized, bank; struct i2c_client *cl; @@ -1205,7 +1308,7 @@ int w83781d_read_value(struct i2c_client return res; } -int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) +static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) { int word_sized, bank; struct i2c_client *cl; @@ -1274,7 +1377,7 @@ int w83781d_write_value(struct i2c_clien } /* Called when we have found a new W83781D. It should set limits, etc. */ -void w83781d_init_client(struct i2c_client *client) +static void w83781d_init_client(struct i2c_client *client) { struct w83781d_data *data = client->data; int vid = 0, i, p; @@ -1303,7 +1406,11 @@ void w83781d_init_client(struct i2c_clie vid = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x0f; vid |= (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) << 4; + if (type == w83791d) { + data->vrm = 92; + } else { data->vrm = DEFAULT_VRM; + } vid = vid_from_reg(vid, data->vrm); } @@ -1354,6 +1461,48 @@ void w83781d_init_client(struct i2c_clie #endif /* W83781D_RT */ if(init) { + if (type == w83791d) { + w83781d_write_value(client, W83791D_REG_IN_MIN(0), + IN_TO_REG(W83781D_INIT_IN_MIN_0)); + w83781d_write_value(client, W83791D_REG_IN_MAX(0), + IN_TO_REG(W83781D_INIT_IN_MAX_0)); + w83781d_write_value(client, W83791D_REG_IN_MIN(1), + IN_TO_REG(W83781D_INIT_IN_MIN_1)); + w83781d_write_value(client, W83791D_REG_IN_MAX(1), + IN_TO_REG(W83781D_INIT_IN_MAX_1)); + w83781d_write_value(client, W83791D_REG_IN_MIN(2), + IN_TO_REG(W83781D_INIT_IN_MIN_2)); + w83781d_write_value(client, W83791D_REG_IN_MAX(2), + IN_TO_REG(W83781D_INIT_IN_MAX_2)); + w83781d_write_value(client, W83791D_REG_IN_MIN(3), + IN_TO_REG(W83781D_INIT_IN_MIN_3)); + w83781d_write_value(client, W83791D_REG_IN_MAX(3), + IN_TO_REG(W83781D_INIT_IN_MAX_3)); + w83781d_write_value(client, W83791D_REG_IN_MIN(4), + IN_TO_REG(W83781D_INIT_IN_MIN_4)); + w83781d_write_value(client, W83791D_REG_IN_MAX(4), + IN_TO_REG(W83781D_INIT_IN_MAX_4)); + w83781d_write_value(client, W83791D_REG_IN_MIN(5), + IN_TO_REG(W83781D_INIT_IN_MIN_5)); + w83781d_write_value(client, W83791D_REG_IN_MAX(5), + IN_TO_REG(W83781D_INIT_IN_MAX_5)); + w83781d_write_value(client, W83791D_REG_IN_MIN(6), + IN_TO_REG(W83781D_INIT_IN_MIN_6)); + w83781d_write_value(client, W83791D_REG_IN_MAX(6), + IN_TO_REG(W83781D_INIT_IN_MAX_6)); + w83781d_write_value(client, W83791D_REG_IN_MIN(7), + IN_TO_REG(W83781D_INIT_IN_MIN_7)); + w83781d_write_value(client, W83791D_REG_IN_MAX(7), + IN_TO_REG(W83781D_INIT_IN_MAX_7)); + w83781d_write_value(client, W83791D_REG_IN_MIN(8), + IN_TO_REG(W83781D_INIT_IN_MIN_8)); + w83781d_write_value(client, W83791D_REG_IN_MAX(8), + IN_TO_REG(W83781D_INIT_IN_MAX_8)); + w83781d_write_value(client, W83791D_REG_IN_MIN(9), + IN_TO_REG(W83781D_INIT_IN_MIN_9)); + w83781d_write_value(client, W83791D_REG_IN_MAX(9), + IN_TO_REG(W83781D_INIT_IN_MAX_9)); + } else { w83781d_write_value(client, W83781D_REG_IN_MIN(0), IN_TO_REG(W83781D_INIT_IN_MIN_0)); w83781d_write_value(client, W83781D_REG_IN_MAX(0), @@ -1412,6 +1561,8 @@ void w83781d_init_client(struct i2c_clie w83781d_write_value(client, W83781D_REG_VBAT, (w83781d_read_value(client, W83781D_REG_VBAT) | 0x01)); } + } + w83781d_write_value(client, W83781D_REG_FAN_MIN(1), FAN_TO_REG(W83781D_INIT_FAN_MIN_1, 2)); w83781d_write_value(client, W83781D_REG_FAN_MIN(2), @@ -1478,127 +1629,133 @@ void w83781d_init_client(struct i2c_clie | 0x01); } -void w83781d_update_client(struct i2c_client *client) +static void w83781d_update_client(struct i2c_client *client) { - struct w83781d_data *data = client->data; - int i, j; + struct w83781d_data *data = client->data; + int i; - down(&data->update_lock); + down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - -#ifdef DEBUG - printk(KERN_DEBUG "Starting device update\n"); -#endif - for (i = 0; i <= 8; i++) { - if ((data->type == w83783s || data->type == w83697hf) - && (i == 1)) - continue; /* 783S has no in1 */ - data->in[i] = - w83781d_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, - W83781D_REG_IN_MAX(i)); - if ((data->type != w83782d) && (data->type != w83697hf) - && (data->type != w83627hf) && (i == 6)) - break; - } - /* PWM2 pin shared with FAN3 */ - j = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG) & 0x10; - data->pwmenable[1] = (!j) && - (w83781d_read_value(client, W83781D_REG_PWMCLK12) & 0x08); - for (i = 1; i <= 3; i++) { - if(i == 3 && !j) { - data->fan[2] = 255; - data->fan_min[2] = 255; - break; - } - data->fan[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83781d_read_value(client, - W83781D_REG_FAN_MIN(i)); - } - if (data->type != w83781d) { - for (i = 1; i <= 4; i++) { - data->pwm[i - 1] = - w83781d_read_value(client, - W83781D_REG_PWM(i)); - if (((data->type == w83783s) - || (data->type == w83627hf) - || (data->type == as99127f) - || (data->type == w83697hf) - || ((data->type == w83782d) - && i2c_is_isa_client(client))) - && i == 2) - break; - } - } - - data->temp = w83781d_read_value(client, W83781D_REG_TEMP); - data->temp_over = - w83781d_read_value(client, W83781D_REG_TEMP_OVER); - data->temp_hyst = - w83781d_read_value(client, W83781D_REG_TEMP_HYST); - data->temp_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP2); - data->temp_add_over[0] = - w83781d_read_value(client, W83781D_REG_TEMP2_OVER); - data->temp_add_hyst[0] = - w83781d_read_value(client, W83781D_REG_TEMP2_HYST); - if (data->type != w83783s && data->type != w83697hf) { - data->temp_add[1] = - w83781d_read_value(client, W83781D_REG_TEMP3); - data->temp_add_over[1] = - w83781d_read_value(client, W83781D_REG_TEMP3_OVER); - data->temp_add_hyst[1] = - w83781d_read_value(client, W83781D_REG_TEMP3_HYST); - } - i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - if (data->type != w83697hf) { - data->vid = i & 0x0f; - data->vid |= - (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) - << 4; - } - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - } - if ((data->type != w83781d) && (data->type != as99127f)) { - i = w83781d_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; - } - data->alarms = - w83781d_read_value(client, - W83781D_REG_ALARM1) + - (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); - if ((data->type == w83782d) || (data->type == w83627hf)) { - data->alarms |= - w83781d_read_value(client, - W83781D_REG_ALARM3) << 16; - } - i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beeps = ((i & 0x7f) << 8) + - w83781d_read_value(client, W83781D_REG_BEEP_INTS1); - if ((data->type != w83781d) && (data->type != as99127f)) { - data->beeps |= - w83781d_read_value(client, - W83781D_REG_BEEP_INTS3) << 16; - } - data->last_updated = jiffies; - data->valid = 1; - } + if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || + time_before(jiffies, data->last_updated) || !data->valid) { + pr_debug(KERN_DEBUG "Starting device update\n"); + + for (i = 0; i <= 9; i++) { + if ((data->type == w83783s || data->type == w83697hf) + && (i == 1)) + continue; /* 783S has no in1 */ + if (data->type == w83791d) { + data->in[i] = + w83781d_read_value(client, W83791D_REG_IN(i)); + data->in_min[i] = + w83781d_read_value(client, + W83791D_REG_IN_MIN(i)); + data->in_max[i] = + w83781d_read_value(client, + W83791D_REG_IN_MAX(i)); + } else { + data->in[i] = + w83781d_read_value(client, W83781D_REG_IN(i)); + data->in_min[i] = + w83781d_read_value(client, + W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83781d_read_value(client, + W83781D_REG_IN_MAX(i)); + } + if ((data->type != w83782d) && (data->type != w83697hf) + && (data->type != w83627hf) && (i == 6) + && (data->type != w83791d)) + break; + + if (data->type != w83791d && i == 8) + break; + } + for (i = 1; i <= 5; i++) { + data->fan[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN(i)); + data->fan_min[i - 1] = + w83781d_read_value(client, + W83781D_REG_FAN_MIN(i)); + if (data->type != w83791d && i == 3) break; + } + if (data->type != w83781d) { + for (i = 1; i <= 4; i++) { + data->pwm[i - 1] = + w83781d_read_value(client, + W83781D_REG_PWM(i)); + if (((data->type == w83783s) + || (data->type == w83627hf) + || (data->type == as99127f) + || (data->type == w83697hf) + || ((data->type == w83782d) + && i2c_is_isa_client(client))) + && i == 2) + break; + } + } + + data->temp = w83781d_read_value(client, W83781D_REG_TEMP); + data->temp_over = + w83781d_read_value(client, W83781D_REG_TEMP_OVER); + data->temp_hyst = + w83781d_read_value(client, W83781D_REG_TEMP_HYST); + data->temp_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP2); + data->temp_add_over[0] = + w83781d_read_value(client, W83781D_REG_TEMP2_OVER); + data->temp_add_hyst[0] = + w83781d_read_value(client, W83781D_REG_TEMP2_HYST); + if (data->type != w83783s && data->type != w83697hf) { + data->temp_add[1] = + w83781d_read_value(client, W83781D_REG_TEMP3); + data->temp_add_over[1] = + w83781d_read_value(client, W83781D_REG_TEMP3_OVER); + data->temp_add_hyst[1] = + w83781d_read_value(client, W83781D_REG_TEMP3_HYST); + } + i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); + if (data->type != w83697hf) { + data->vid = i & 0x0f; + data->vid |= + (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) + << 4; + } + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83781d_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; + } + if ((data->type != w83781d) && (data->type != as99127f)) { + i = w83781d_read_value(client, W83781D_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (i >> 5) & 0x04; + } + data->alarms = + w83781d_read_value(client, + W83781D_REG_ALARM1) + + (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); + if ((data->type == w83782d) || (data->type == w83627hf)) { + data->alarms |= + w83781d_read_value(client, + W83781D_REG_ALARM3) << 16; + } + i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); + data->beep_enable = i >> 7; + data->beeps = ((i & 0x7f) << 8) + + w83781d_read_value(client, W83781D_REG_BEEP_INTS1); + if ((data->type != w83781d) && (data->type != as99127f) + && (data->type != w83791d)) { + data->beeps |= + w83781d_read_value(client, + W83781D_REG_BEEP_INTS3) << 16; + } + data->last_updated = jiffies; + data->valid = 1; + } up(&data->update_lock); } @@ -1617,8 +1774,8 @@ void w83781d_update_client(struct i2c_cl large enough (by checking the incoming value of *nrels). This is not very good practice, but as long as you put less than about 5 values in results, you can assume it is large enough. */ -void w83781d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +static void w83781d_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) { struct w83781d_data *data = client->data; int nr = ctl_name - W83781D_SYSCTL_IN0; @@ -2016,8 +2173,8 @@ void w83781d_sens(struct i2c_client *cli } #ifdef W83781D_RT -void w83781d_rt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +static void w83781d_rt(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) { struct w83781d_data *data = client->data; int nr = 1 + ctl_name - W83781D_SYSCTL_RT1; @@ -2044,59 +2201,24 @@ void w83781d_rt(struct i2c_client *clien } #endif -int __init sensors_w83781d_init(void) +static int __init sm_w83781d_init(void) { - int res; - printk(KERN_INFO "w83781d.o version %s (%s)\n", LM_VERSION, LM_DATE); - w83781d_initialized = 0; - - if ((res = i2c_add_driver(&w83781d_driver))) { - printk - (KERN_ERR "w83781d.o: Driver registration failed, module not inserted.\n"); - w83781d_cleanup(); - return res; - } - w83781d_initialized++; - return 0; + return i2c_add_driver(&w83781d_driver); } -int __init w83781d_cleanup(void) +static void __exit sm_w83781d_exit(void) { - int res; - - if (w83781d_initialized >= 1) { - if ((res = i2c_del_driver(&w83781d_driver))) { - printk - (KERN_ERR "w83781d.o: Driver deregistration failed, module not removed.\n"); - return res; - } - w83781d_initialized--; - } - return 0; + i2c_del_driver(&w83781d_driver); } -EXPORT_NO_SYMBOLS; -#ifdef MODULE MODULE_AUTHOR("Frodo Looijaard , " "Philip Edelbrock , " "and Mark Studebaker "); MODULE_DESCRIPTION("W83781D driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif - - -int init_module(void) -{ - return sensors_w83781d_init(); -} - -int cleanup_module(void) -{ - return w83781d_cleanup(); -} -#endif /* MODULE */ +module_init(sm_w83781d_init); +module_exit(sm_w83781d_exit); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/drivers/usb/usbkbd.c linux-2.4.20-wolk4.7-fullkernel/drivers/usb/usbkbd.c --- linux-2.4.20-wolk4.6-fullkernel/drivers/usb/usbkbd.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/drivers/usb/usbkbd.c 2003-08-17 21:26:24.000000000 +0200 @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/Config.in linux-2.4.20-wolk4.7-fullkernel/fs/Config.in --- linux-2.4.20-wolk4.6-fullkernel/fs/Config.in 2003-08-05 22:23:15.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/Config.in 2003-08-17 21:31:42.000000000 +0200 @@ -58,6 +58,8 @@ tristate 'NTFS file system support (read dep_mbool ' NTFS debugging support' CONFIG_NTFS_DEBUG $CONFIG_NTFS_FS dep_mbool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL +tristate 'NetWare 3/4/5 file system support (NWFS)' CONFIG_NWFS_FS + tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS bool '/proc file system support' CONFIG_PROC_FS @@ -161,6 +163,15 @@ if [ "$CONFIG_NET" = "y" ]; then dep_tristate 'FTP file system support' CONFIG_FTP_FS $CONFIG_EXPERIMENTAL $CONFIG_INET + dep_tristate 'Secure SHell Filesystem support (shfs/sshfs)' CONFIG_SH_FS $CONFIG_EXPERIMENTAL $CONFIG_INET + if [ "$CONFIG_SH_FS" != "n" ]; then + choice ' Debug Level' \ + "DISABLED CONFIG_SH_FS_DEBUG0 + VERBOSE CONFIG_SH_FS_DEBUG1 \ + ALLOC_DEBUG CONFIG_SH_FS_DEBUG2 \ + DEBUG CONFIG_SH_FS_DEBUG3" DISABLED + fi + endmenu else diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/Makefile linux-2.4.20-wolk4.7-fullkernel/fs/Makefile --- linux-2.4.20-wolk4.6-fullkernel/fs/Makefile 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/Makefile 2003-08-17 21:31:42.000000000 +0200 @@ -47,7 +47,7 @@ subdir-$(CONFIG_VFAT_FS) += vfat subdir-$(CONFIG_BFS_FS) += bfs subdir-$(CONFIG_ISO9660_FS) += isofs subdir-$(CONFIG_CD_FS) += cdfs -subdir-$(CONFIG_CIFS) += cifs +subdir-$(CONFIG_CIFS) += cifs subdir-$(CONFIG_DEVFS_FS) += devfs subdir-$(CONFIG_HFS_FS) += hfs subdir-$(CONFIG_HFSPLUS_FS) += hfsplus @@ -61,6 +61,7 @@ subdir-$(CONFIG_SMB_FS) += smbfs subdir-$(CONFIG_NCP_FS) += ncpfs subdir-$(CONFIG_HPFS_FS) += hpfs subdir-$(CONFIG_NTFS_FS) += ntfs +subdir-$(CONFIG_NWFS_FS) += nwfs subdir-$(CONFIG_UFS_FS) += ufs subdir-$(CONFIG_EFS_FS) += efs subdir-$(CONFIG_JFFS_FS) += jffs @@ -82,6 +83,7 @@ subdir-$(CONFIG_XFS_FS) += xfs subdir-$(CONFIG_OCFS_FS) += ocfs subdir-$(CONFIG_BADFS_FS) += badfs subdir-$(CONFIG_FTP_FS) += ftpfs +subdir-$(CONFIG_SH_FS) += shfs subdir-$(CONFIG_LUFS_FS) += lufs subdir-$(CONFIG_EVFS_FS) += evfs diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/binfmt_elf.c linux-2.4.20-wolk4.7-fullkernel/fs/binfmt_elf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/binfmt_elf.c 2003-08-04 23:06:39.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/binfmt_elf.c 2003-08-17 21:31:36.000000000 +0200 @@ -83,13 +83,13 @@ static struct linux_binfmt elf_format = #define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) -static unsigned long set_brk(unsigned long start, unsigned long end) +static void set_brk(unsigned long start, unsigned long end) { start = ELF_PAGEALIGN(start); end = ELF_PAGEALIGN(end); if (end <= start) - return 0; - return do_brk(start, end - start); + return; + do_brk(start, end - start); #ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC if (current->flags & PF_PAX_RANDEXEC) @@ -326,7 +326,6 @@ static unsigned long load_elf_interp(str elf_type |= MAP_FIXED; map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); - error = map_addr; if (BAD_ADDR(map_addr)) goto out_close; @@ -365,11 +364,8 @@ static unsigned long load_elf_interp(str elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ - if (last_bss > elf_bss) { - error = do_brk(elf_bss, last_bss - elf_bss); - if (BAD_ADDR(error)) - goto out_close; - } + if (last_bss > elf_bss) + do_brk(elf_bss, last_bss - elf_bss); *interp_load_addr = load_addr; error = ((unsigned long) interp_elf_ex->e_entry) + load_addr; @@ -386,6 +382,7 @@ static unsigned long load_aout_interp(st unsigned long text_data, elf_entry = ~0UL; char * addr; loff_t offset; + int retval; current->mm->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; @@ -407,9 +404,11 @@ static unsigned long load_aout_interp(st } do_brk(0, text_data); + retval = -ENOEXEC; if (!interpreter->f_op || !interpreter->f_op->read) goto out; - if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) + retval = interpreter->f_op->read(interpreter, addr, text_data, &offset); + if (retval < 0) goto out; flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); @@ -452,7 +451,7 @@ static int load_elf_binary(struct linux_ struct elfhdr interp_elf_ex; struct exec interp_ex; char passed_fileno[6]; - struct files_struct *files, *ftmp; + struct files_struct *files; #ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC unsigned long load_addr_random = 0UL; @@ -493,6 +492,10 @@ static int load_elf_binary(struct linux_ files = current->files; /* Refcounted so ok */ if(unshare_files() < 0) goto out_free_ph; + if (files == current->files) { + put_files_struct(files); + files = NULL; + } /* exec will make our files private anyway, but for the a.out loader stuff we need to do it earlier */ @@ -615,7 +618,11 @@ static int load_elf_binary(struct linux_ goto out_free_dentry; /* Discard our unneeded old files struct */ - put_files_struct(files); + if (files) { + steal_locks(files); + put_files_struct(files); + files = NULL; + } /* OK, This is the point of no return */ current->mm->start_data = 0; @@ -674,7 +681,6 @@ static int load_elf_binary(struct linux_ delta = (unsigned long) arc4random(); current->mm->delta_stack = pax_delta_mask(delta, PAX_DELTA_STACK_LSB(current), PAX_DELTA_STACK_LEN(current)); -#undef pax_delta_mask } #endif @@ -717,11 +723,7 @@ static int load_elf_binary(struct linux_ /* There was a PT_LOAD segment with p_memsz > p_filesz before this one. Map anonymous pages, if needed, and clear the area. */ - error = set_brk (elf_bss + load_bias, elf_brk + load_bias); - /* here retval is zero */ - if (BAD_ADDR(error)) - goto out_free_dentry; - + set_brk (elf_bss + load_bias, elf_brk + load_bias); nbyte = ELF_PAGEOFFSET(elf_bss); if (nbyte) { nbyte = ELF_MIN_ALIGN - nbyte; @@ -779,9 +781,8 @@ static int load_elf_binary(struct linux_ } #endif - /* here retval is zero */ if (BAD_ADDR(error)) - goto out_free_dentry; + continue; /* PaX: mirror at a randomized base */ down_write(¤t->mm->mmap_sem); @@ -821,9 +822,8 @@ static int load_elf_binary(struct linux_ #endif { error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); - /* here retval is zero */ if (BAD_ADDR(error)) - goto out_free_dentry; + continue; } if (!load_addr_set) { @@ -865,13 +865,21 @@ static int load_elf_binary(struct linux_ start_data += load_bias; end_data += load_bias; +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + { + unsigned long delta; + + delta = (unsigned long) arc4random(); + + elf_brk += pax_delta_mask(delta, 4, PAGE_SHIFT); + } +#undef pax_delta_mask +#endif + /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections */ - error = set_brk(elf_bss, elf_brk); - /* here retval is zero */ - if (BAD_ADDR(error)) - goto out; + set_brk(elf_bss, elf_brk); padzero(elf_bss); @@ -883,16 +891,16 @@ static int load_elf_binary(struct linux_ elf_entry = load_elf_interp(&interp_elf_ex, interpreter, &interp_load_addr); + if (BAD_ADDR(elf_entry)) { + printk(KERN_ERR "Unable to load interpreter\n"); + send_sig(SIGSEGV, current, 0); + retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + goto out_free_dentry; + } allow_write_access(interpreter); fput(interpreter); kfree(elf_interpreter); - - /* here retval is zero */ - if (BAD_ADDR(elf_entry)) { - printk(KERN_WARNING "Unable to load interpreter\n"); - goto out_free_ph; - } } kfree(elf_phdata); @@ -961,25 +969,24 @@ static int load_elf_binary(struct linux_ start_thread(regs, elf_entry, bprm->p); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); - /* here retval is zero */ - steal_locks(files, current->files); + retval = 0; out: return retval; /* error cleanup */ out_free_dentry: allow_write_access(interpreter); - if (interpreter) - fput(interpreter); + fput(interpreter); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); out_free_file: sys_close(elf_exec_fileno); out_free_fh: - ftmp = current->files; - current->files = files; - put_files_struct(ftmp); + if (files) { + put_files_struct(current->files); + current->files = files; + } out_free_ph: kfree(elf_phdata); goto out; @@ -1049,11 +1056,8 @@ static int load_elf_library(struct file len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; - if (bss > len) { - error = do_brk(len, bss - len); - if (BAD_ADDR(error)) - goto out_free_ph; - } + if (bss > len) + do_brk(len, bss - len); error = 0; out_free_ph: diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/binfmt_som.c linux-2.4.20-wolk4.7-fullkernel/fs/binfmt_som.c --- linux-2.4.20-wolk4.6-fullkernel/fs/binfmt_som.c 2002-12-18 01:03:59.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/binfmt_som.c 2003-08-17 21:31:35.000000000 +0200 @@ -213,7 +213,7 @@ do_load_som_binary(struct linux_binprm * (char *) hpuxhdr, size); if (retval < 0) goto out_free; - +#error "Fix security hole before enabling me" retval = get_unused_fd(); if (retval < 0) goto out_free; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/buffer.c linux-2.4.20-wolk4.7-fullkernel/fs/buffer.c --- linux-2.4.20-wolk4.6-fullkernel/fs/buffer.c 2003-08-04 23:06:39.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/buffer.c 2003-08-17 21:31:46.000000000 +0200 @@ -901,7 +901,7 @@ void end_buffer_io_async(struct buffer_h spin_unlock_irqrestore(&page_uptodate_lock, flags); /* - * if none of the buffers had errors and all were uptodate + * If none of the buffers had errors and all were uptodate * then we can set the page uptodate: */ if (fullup && !PageError(page)) @@ -1340,10 +1340,11 @@ void set_bh_page (struct buffer_head *bh if (offset >= PAGE_SIZE) BUG(); - /* - * page_address will return NULL anyways for highmem pages - */ - bh->b_data = page_address(page) + offset; + if (PageHighMem(page)) { + bh->b_data = (char *)offset; + } else { + bh->b_data = page_address(page) + offset; + } bh->b_page = page; } EXPORT_SYMBOL(set_bh_page); @@ -1429,7 +1430,7 @@ no_grow: */ void discard_buffer(struct buffer_head * bh) { - if (buffer_mapped(bh) || buffer_delay(bh)) { + if (buffer_mapped(bh)) { mark_buffer_clean(bh); lock_buffer(bh); clear_bit(BH_Uptodate, &bh->b_state); @@ -1783,7 +1784,7 @@ static int __block_prepare_write(struct set_bit(BH_Uptodate, &bh->b_state); continue; } - if (!buffer_uptodate(bh) && !buffer_delay(bh) && + if (!buffer_uptodate(bh) && (block_start < from || block_end > to)) { ll_rw_block(READ, 1, &bh); *wait_bh++=bh; @@ -2193,7 +2194,7 @@ int block_truncate_page(struct address_s if (Page_Uptodate(page)) set_bit(BH_Uptodate, &bh->b_state); - if (!buffer_uptodate(bh) && !buffer_delay(bh)) { + if (!buffer_uptodate(bh)) { err = -EIO; ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); @@ -2325,7 +2326,7 @@ int generic_direct_IO(int rw, struct ino bh.b_size = blocksize; bh.b_page = NULL; - if (((loff_t) blocknr) * blocksize >= inode->i_size) + if (((loff_t) (blocknr + 1)) * blocksize > inode->i_size) beyond_eof = 1; /* Only allow get_block to create new blocks if we are safely diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/AUTHORS linux-2.4.20-wolk4.7-fullkernel/fs/cifs/AUTHORS --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/AUTHORS 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/AUTHORS 2003-08-17 21:27:53.000000000 +0200 @@ -19,4 +19,11 @@ Patch Contributors ------------------ Zwane Mwaikambo Andi Kleen +Amrut Joshi + +Test case and Bug Report contributors +------------------------------------- +Thanks to those in the community who have submitted detailed bug reports +and debug of problems they have found: Jochen Dolze, David Blaine, +Rene Scharfe, Martin Josefsson, Alexander Wild and others. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/CHANGES linux-2.4.20-wolk4.7-fullkernel/fs/cifs/CHANGES --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/CHANGES 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/CHANGES 2003-08-17 21:27:53.000000000 +0200 @@ -1,3 +1,72 @@ +Version 0.87 +------------ +Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix +allocation size miscalculation. After oplock token lost do not read through +cache. + +Version 0.86 +------------ +Fix oops on empty file readahead. Fix for file size handling for locally cached files. + +Version 0.85 +------------ +Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files +during auto reconnection to server after server recovered from failure. + +Version 0.84 +------------ +Finish support for Linux 2.5 open/create changes, which removes the +redundant NTCreate/QPathInfo/close that was sent during file create. +Enable oplock by default. Enable packet signing by default (needed to +access many recent Windows servers) + +Version 0.83 +------------ +Fix oops when mounting to long server names caused by inverted parms to kmalloc. +Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled +we will choose a cifs user session (smb uid) that better matches the local +uid if a) the mount uid does not match the current uid and b) we have another +session to the same server (ip address) for a different mount which +matches the current local uid. + +Version 0.82 +------------ +Add support for mknod of block or character devices. Fix oplock +code (distributed caching) to properly send response to oplock +break from server. + +Version 0.81 +------------ +Finish up CIFS packet digital signing for the default +NTLM security case. This should help Windows 2003 +network interoperability since it is common for +packet signing to be required now. Fix statfs (stat -f) +which recently started returning errors due to +invalid value (-1 instead of 0) being set in the +struct kstatfs f_ffiles field. + +Version 0.80 +----------- +Fix oops on stopping oplock thread when removing cifs when +built as module. + +Version 0.79 +------------ +Fix mount options for ro (readonly), uid, gid and file and directory mode. + +Version 0.78 +------------ +Fix errors displayed on failed mounts to be more understandable. +Fixed various incorrect or misleading smb to posix error code mappings. + +Version 0.77 +------------ +Fix display of NTFS DFS junctions to display as symlinks. +They are the network equivalent. Fix oops in +cifs_partialpagewrite caused by missing spinlock protection +of openfile linked list. Allow writebehind caching errors to +be returned to the application at file close. + Version 0.76 ------------ Clean up options displayed in /proc/mounts by show_options to diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/Makefile linux-2.4.20-wolk4.7-fullkernel/fs/cifs/Makefile --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/Makefile 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/Makefile 2003-08-17 21:27:53.000000000 +0200 @@ -3,7 +3,7 @@ # O_TARGET := cifs.o -obj-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o +obj-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o cifsencrypt.o obj-m := $(O_TARGET) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/README linux-2.4.20-wolk4.7-fullkernel/fs/cifs/README --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/README 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/README 2003-08-17 21:27:53.000000000 +0200 @@ -1,5 +1,5 @@ -This is the CIFS VFS support for Linux. It supports many advanced network filesystem -features such as heirarchical dfs like filesystem, hardlinks, locking and more. +The CIFS VFS support for Linux supports many advanced network filesystem +features such as heirarchical dfs like namespace, hardlinks, locking and more. It was designed to comply with the SNIA CIFS Technical Reference (which supersedes the 1992 X/Open SMB Standard) as well as to perform best practice practical interoperability with Windows 2000, Windows XP, Samba and equivalent @@ -9,43 +9,65 @@ For questions or bug reports please cont Build instructions: ================== -Get the kernel source e.g. http://linux.bkbits.net/linux-2.5 or http://www.kernel.org -http://cifs.bkbits.net/linux-2.4 -make menuconfig (or make xconfig) -select cifs from within the network filesystem choices -save and exit -make dep -make modules (or "make" if you did not select CIFS VFS to be built as a module) +For Linux 2.4: +1a) Get the linux kernel source with cifs vfs already in it +from bitkeeper via bk://cifs.bkbits.net/linux-2.4 +or +1b) Get the kernel source (e.g.from http://www.kernel.org) +and download the cifs vfs source (see the project page +at http://us1.samba.org/samba/Linux_CIFS_client.html) +and change directory into the top of the kernel directory +then patch the kernel (e.g. "patch -p1 < cifs_24.patch") +to add the cifs vfs to your kernel configure options if +it has not already been added (e.g. current SuSE and UL +users do not need to do not need that patch since the cifs vfs is +already in the kernel configure menu) and then +mkdir linux/fs/cifs and then copy the current cifs vfs files from +the cifs download to your kernel build directory e.g. + cp /fs/cifs/* to /fs/cifs +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make dep +6) make modules (or "make" if CIFS VFS not to be built as a module) + +For Linux 2.5: +1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper +at bk://linux.bkbits.net/linux-2.5) and change directory into the top +of the kernel directory tree (e.g. /usr/src/linux-2.5.73) +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make + Installation instructions: ========================= -If you have built the CIFS vfs as module (successfully)you -simply type "make modules_install" (or if you prefer manually copy the file to +If you have built the CIFS vfs as module (successfully) simply +type "make modules_install" (or if you prefer, manually copy the file to the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). If you have built the CIFS vfs into the kernel itself, follow the instructions for your distribution on how to install a new kernel (usually you would simply type "make install"). -If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on the -CIFS VFS web site) copy it to the directory /sbin (or the same directory in which -mount.smbfs resides). Although no helper software is required, the installation -of mount.cifs is recommended. Eventually the Samba 3.0 utility program "net" +If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on +the CIFS VFS web site) copy it to the same directory in which mount.smbfs and +similar files reside (usually /sbin). Although the helper software is required, +mount.cifs is recommended. Eventually the Samba 3.0 utility program "net" may also be helpful since it may someday provide easier mount syntax for users used to Windows e.g. net use -and there will likely be other helper programs available ala smbmount to provide -additional optional function in the future. Note that running Winbind on all -of your Linux clients is useful in mapping Uids and Gids consistently to the -proper network user. +Note that running Winbind on all of your Linux clients is useful in +in mapping Uids and Gids consistently to the proper network user. Samba Considerations ==================== To get the maximum benefit from the CIFS VFS, we recommend using a server that -supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or Samba 3.0) -but the CIFS vfs works fine with a wide variety of CIFS servers. Note that the -uid, gid and file permissions will display default values if you do not have -a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or +supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or +Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or later). To enable the Unix CIFS Extensions in the Samba server, add the line: unix extensions = yes to your smb.conf file on the server. Note that the following smb.conf settings are @@ -54,8 +76,9 @@ or Linux: case sensitive = yes delete readonly = yes Some administrators also change the "map archive" and the "create mask" parameters -from their defaults. For more information on these see the manual pages -("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the +from their default values. Creating special devices (mknod) remotely may require +specifying a mkdev function to Samba. For more information on these see the manual +pages ("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the smbfs vfs, does not read the smb.conf on the client system (the few optional settings are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete open files (required for strict @@ -81,15 +104,83 @@ either "pure-TCP" (port 445 TCP/IP CIFS "Netbios-Over-TCP/IP." Neither of these is likely to be a problem as most servers support this. IPv6 support is planned for the future. +CIFS VFS Mount Options +====================== +A partial list of the supported mount options follows: + user The user name to use when trying to establish + the CIFS session. + password The user password. If the mount helper is + installed, the user will be prompted for password + if it is not supplied. + ip The ip address of the target server + unc The target server Universal Network Name (export) to + mount. + domain Set the SMB/CIFS workgroup name prepended to the + username during CIFS session establishment + uid If CIFS Unix extensions are not supported by the server + this overrides the default uid for inodes. + gid If CIFS Unix extensions are not supported by the server + this overrides the default gid for inodes. + file_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for file inodes. + dir_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for directory inodes. + port attempt to contact the server on this tcp port, before + trying the usual ports (port 445, then 139). + rsize default read size + wsize default write size + rw mount the network share read-write (note that the + server may still consider the share read-only) + ro mount network share read-only + version used to distinguish different versions of the + mount helper utility (not typically needed) + Misc /proc/fs/cifs Flags and Debug Info ======================================= -Various experimental features and tracing can be enabled by changing flags in /proc/fs/cifs (after -the cifs module has been installed or built into the kernel, e.g. insmod cifs). To enable -a feature you can set it to 1 e.g. to enable tracing to the kernel message log you can do -"echo 1 > /proc/fs/cifs/cifsFYI" and "echo 1 > /proc/fs/cifs/traceSMB" -Also note that "cat /proc/fs/cifs/DebugData" will display some information about the currently -active sessions and the shares that are mounted. Currently the ntlmv2 enablement and packet -signing will not work since they the implementation is not quite complete, so do not enable +Informational pseudo-files: + DebugData Displays information about active CIFS sessions + SimultaneousOps Counter which holds maximum number of + simultaneous outstanding SMB/CIFS requests. + Stats Lists summary resource usage information + +Configuration pseudo-files: + MultiuserMount If set to one, more than one CIFS session to + the same server ip address can be established + if more than one uid accesses the same mount + point and if the uids user/password mapping + information is available. (default is 0) + PacketSigningEnabled If set to one, cifs packet signing is enabled + and will be used if the server requires + it. If set to two, cifs packet signing is + required even if the server considers packet + signing optional. (default 1) + cifsFYI If set to one, additional debug information is + logged to the system error log. (default 0) + ExtendedSecurity If set to one, SPNEGO session establishment + is allowed which enables more advanced + secure CIFS session establishment (default 0) + NTLMV2Enabled If set to one, more secure password hashes + are used when the server supports them and + when kerberos is not negotiated (default 0) + traceSMB If set to one, debug information is logged to the + system error log with the start of smb requests + and responses (default 0) + LookupCacheEnable If set to one, inode information is kept cached + for one second improving performance of lookups + (default 1) + OplockEnabled If set to one, safe distributed caching enabled. + (default 1) + +These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs +(after the cifs module has been installed or built into the kernel, e.g. insmod cifs). +To enable a feature set it to 1 e.g. to enable tracing to the kernel message log +type: + echo 1 > /proc/fs/cifs/cifsFYI +and for more extensive tracing including the start of smb requests and responses + echo 1 > /proc/fs/cifs/traceSMB +Also note that "cat /proc/fs/cifs/DebugData" will display some information about the +active sessions and the shares that are mounted. NTLMv2 enablement and packet +signing will not work since they the implementation is not quite complete. Do not enable these flags unless you are doing specific testing. Enabling extended security works to Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/TODO linux-2.4.20-wolk4.7-fullkernel/fs/cifs/TODO --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/TODO 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/TODO 2003-08-17 21:27:53.000000000 +0200 @@ -1,4 +1,4 @@ -version 0.6.5 February 15, 2003 +version 0.8.1 July 4th, 2003 A Partial List of Known Problems and Missing Features ===================================================== @@ -17,10 +17,14 @@ c) multi-user mounts - multiplexed sessi d) Kerberos/SPNEGO session setup support - (started) -e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented) +e) NTLMv2 authentication (mostly implemented) -f) oplock support (ie safe CIFS distributed file caching) is not quite complete. -In addition Directory entry caching relies on a 1 second timer, rather than +f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup +used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM + and raw NTLMSSP already. This is important when enabling + extended security and mounting to Windows 2003 Servers + +f) Directory entry caching relies on a 1 second timer, rather than using FindNotify or equivalent. - (started) g) There may be a few additional changes that could be done to take advantage @@ -42,17 +46,17 @@ extra copy in/out of the socket buffers m) finish support for IPv6 -n) send oplock break response when sent (oplock currently disabled in -/proc/fs/cifs) - -o) remove calls to set end of file by name when we already have file open -(use the existing handle since some servers only support that and it -reduces the oplock breaks coming from windows). Piggyback identical -file opens on top of each other by incrementing reference count rather +o) Better optimize open (and pathbased setfilesize) to reduce the +oplock breaks coming from windows srv. Piggyback identical file +opens on top of each other by incrementing reference count rather than resending (helps reduce server resource utilization and avoid spurious oplock breaks). -KNOWN BUGS (updated March 7, 2003) +p) Improve performance of readpages by sending more than one read +at a time when 8 pages or more are requested. + + +KNOWN BUGS (updated July 4th, 2003) ==================================== 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that @@ -60,14 +64,19 @@ support the CIFS Unix extensions but Sam symlink text beginning with slash 2) delete of file with read-only attribute set will fail (may be ok) 3) mount helper syntax not quite matching man page +4) follow_link and readdir code does not follow dfs junctions +but recognizes them +5) create of new files to FAT partitions on Windows servers can +succeed but still return access denied (appears to be Windows +not client problem). NTFS partitions do not have this problem. Misc testing to do ================= 1) check out max path names and max path name components against various server types. -2) Run dbench +2) Run dbench. Modify file portion of ltp so it can run against a mounted network +share and run it against cifs vfs. -3) Finish FSX testing on SMP now that we workaround the Samba bug +3) Additional performance testing and optimization using iozone and similar tools. -4) Additional performance testing and optimization diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/asn1.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/asn1.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/asn1.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/asn1.c 2003-08-17 21:27:53.000000000 +0200 @@ -432,7 +432,7 @@ static int compare_oid(unsigned long *oid1, unsigned int oid1len, unsigned long *oid2, unsigned int oid2len) { - int i; + unsigned int i; if (oid1len != oid2len) return 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifs_debug.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifs_debug.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifs_debug.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifs_debug.c 2003-08-17 21:27:53.000000000 +0200 @@ -90,8 +90,8 @@ cifs_debug_data_read(char *buf, char **b ses->serverOS, ses->serverNOS, ses->capabilities); buf += length; if(ses->server) - buf += sprintf(buf, "\tLocal Users To Same Server: %d ", - atomic_read(&ses->server->socketUseCount)); + buf += sprintf(buf, "\tLocal Users To Same Server: %d SecMode: 0x%x", + atomic_read(&ses->server->socketUseCount),ses->server->secMode); } read_unlock(&GlobalSMBSeslock); sprintf(buf, "\n"); @@ -591,6 +591,8 @@ packet_signing_enabled_write(struct file sign_CIFS_PDUs = 0; else if (c == '1' || c == 'y' || c == 'Y') sign_CIFS_PDUs = 1; + else if (c == '2') + sign_CIFS_PDUs = 2; return count; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifs_fs_sb.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifs_fs_sb.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifs_fs_sb.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifs_fs_sb.h 2003-08-17 21:27:53.000000000 +0200 @@ -24,5 +24,9 @@ struct cifs_sb_info { struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; + uid_t mnt_uid; + gid_t mnt_gid; + mode_t mnt_file_mode; + mode_t mnt_dir_mode; }; #endif /* _CIFS_FS_SB_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifs_unicode.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifs_unicode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifs_unicode.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifs_unicode.c 2003-08-17 21:27:53.000000000 +0200 @@ -34,7 +34,7 @@ void toUpper(const struct nls_table *n, char *mixed_string) { - int i; + unsigned int i; char temp; for (i = 0; i < strlen(mixed_string); i++) { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsencrypt.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsencrypt.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsencrypt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsencrypt.c 2003-08-17 21:27:53.000000000 +0200 @@ -0,0 +1,201 @@ +/* + * fs/cifs/cifsencrypt.c + * + * Copyright (c) International Business Machines Corp., 2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * 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.1 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 + */ + +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifs_debug.h" +#include "md5.h" +#include "cifs_unicode.h" + +/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ +/* the 16 byte signature must be allocated by the caller */ +/* Note we only use the 1st eight bytes */ +/* Note that the smb header signature field on input contains the + sequence number before this function is called */ + +extern void mdfour(unsigned char *out, unsigned char *in, int n); +extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); + +static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) +{ + struct MD5Context context; + + if((cifs_pdu == NULL) || (signature == NULL)) + return -EINVAL; + + MD5Init(&context); + MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); + MD5Final(signature,&context); + return 0; +} + +int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, + __u32 * pexpected_response_sequence_number) +{ + int rc = 0; + char smb_signature[20]; + + /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ + /* BB remember to add code to save expected sequence number in midQ entry BB */ + + if((cifs_pdu == NULL) || (ses == NULL)) + return -EINVAL; + + if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) + return rc; + + write_lock(&GlobalMid_Lock); + cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); + cifs_pdu->Signature.Sequence.Reserved = 0; + + *pexpected_response_sequence_number = ses->sequence_number++; + ses->sequence_number++; + write_unlock(&GlobalMid_Lock); + + rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); + if(rc) + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + else + memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); + + return rc; +} + +int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, + __u32 expected_sequence_number) +{ + unsigned int rc; + char server_response_sig[8]; + char what_we_think_sig_should_be[20]; + + if((cifs_pdu == NULL) || (mac_key == NULL)) + return -EINVAL; + + if (cifs_pdu->Command == SMB_COM_NEGOTIATE) + return 0; + + /* BB what if signatures are supposed to be on for session but server does not + send one? BB */ + /* BB also do not verify oplock breaks for signature */ + + /* Do not need to verify session setups with signature "BSRSPYL " */ + if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) + cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); + + expected_sequence_number = cpu_to_le32(expected_sequence_number); + + /* save off the origiginal signature so we can modify the smb and check + its signature against what the server sent */ + memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); + + cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.Reserved = 0; + + rc = cifs_calculate_signature(cifs_pdu, mac_key, + what_we_think_sig_should_be); + + if(rc) + return rc; + + +/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ + + if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) + return -EACCES; + else + return 0; + +} + +/* We fill in key by putting in 40 byte array which was allocated by caller */ +int cifs_calculate_mac_key(char * key, const char * rn, const char * password) +{ + char temp_key[16]; + if ((key == NULL) || (rn == NULL) || (password == NULL)) + return -EINVAL; + + E_md4hash(password, temp_key); + mdfour(key,temp_key,16); + memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); + return 0; +} + +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) +{ + char temp_hash[16]; + struct HMACMD5Context ctx; + char * ucase_buf; + wchar_t * unicode_buf; + unsigned int i,user_name_len,dom_name_len; + + if(ses) + return -EINVAL; + + E_md4hash(ses->password_with_pad, temp_hash); + + hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); + user_name_len = strlen(ses->userName); + if(user_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + dom_name_len = strlen(ses->domainName); + if(dom_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + + + ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); + unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); + + for(i=0;icharset2upper[(int)ses->userName[i]]; + ucase_buf[i] = 0; + user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + unicode_buf[user_name_len] = 0; + user_name_len++; + + for(i=0;icharset2upper[(int)ses->domainName[i]]; + ucase_buf[i] = 0; + dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + + unicode_buf[user_name_len + dom_name_len] = 0; + hmac_md5_update((const unsigned char *) unicode_buf, + (user_name_len+dom_name_len)*2,&ctx); + + hmac_md5_final(ses->mac_signing_key,&ctx); + kfree(ucase_buf); + kfree(unicode_buf); + return 0; +} +void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) +{ + struct HMACMD5Context context; + memcpy(v2_session_response + 8, ses->server->cryptKey,8); + /* gen_blob(v2_session_response + 16); */ + hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); + + hmac_md5_update(ses->server->cryptKey,8,&context); +/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ + + + hmac_md5_final(v2_session_response,&context); +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsfs.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsfs.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsfs.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsfs.c 2003-08-17 21:27:53.000000000 +0200 @@ -47,12 +47,12 @@ extern struct file_system_type cifs_fs_t int cifsFYI = 0; int cifsERROR = 1; int traceSMB = 0; -unsigned int oplockEnabled = 0; +unsigned int oplockEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; unsigned int extended_security = 0; unsigned int ntlmv2_support = 0; -unsigned int sign_CIFS_PDUs = 0; +unsigned int sign_CIFS_PDUs = 1; unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; struct task_struct * oplockThread = NULL; @@ -62,6 +62,9 @@ extern int cifs_umount(struct super_bloc void cifs_proc_init(void); void cifs_proc_clean(void); +static DECLARE_COMPLETION(cifs_oplock_exited); + + struct super_block * cifs_read_super(struct super_block *sb, void *data, int silent) { @@ -85,10 +88,10 @@ cifs_read_super(struct super_block *sb, sb->s_magic = CIFS_MAGIC_NUMBER; sb->s_op = &cifs_super_ops; - if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) - sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; - else - sb->s_blocksize = CIFSMaximumBufferSize; +/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) + sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ + + sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ inode = iget(sb, ROOT_I); @@ -154,7 +157,7 @@ cifs_statfs(struct super_block *sb, stru able to support more than this, but best to be safe since Win2k and others can not handle very long filenames */ buf->f_files = 0; /* undefined */ - buf->f_ffree = -1; /* unlimited */ + buf->f_ffree = 0; /* unlimited */ rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); @@ -181,21 +184,22 @@ kmem_cache_t *cifs_oplock_cachep; static struct inode * cifs_alloc_inode(struct super_block *sb) { - struct cifsInodeInfo *cifs_inode; - cifs_inode = - (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep, - SLAB_KERNEL); - if (!cifs_inode) - return NULL; - cifs_inode->cifsAttrs = 0x20; /* default */ - atomic_set(&cifs_inode->inUse, 0); - cifs_inode->time = 0; - if(oplockEnabled) { - cifs_inode->clientCanCacheRead = 1; - cifs_inode->clientCanCacheAll = 1; - } - INIT_LIST_HEAD(&cifs_inode->openFileList); - return &cifs_inode->vfs_inode; + struct cifsInodeInfo *cifs_inode; + cifs_inode = + (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep, + SLAB_KERNEL); + if (!cifs_inode) + return NULL; + cifs_inode->cifsAttrs = 0x20; /* default */ + atomic_set(&cifs_inode->inUse, 0); + cifs_inode->time = 0; + /* Until the file is open and we have gotten oplock + info back from the server, can not assume caching of + file data or metadata */ + cifs_inode->clientCanCacheRead = FALSE; + cifs_inode->clientCanCacheAll = FALSE; + INIT_LIST_HEAD(&cifs_inode->openFileList); + return &cifs_inode->vfs_inode; } static void @@ -220,7 +224,7 @@ cifs_show_options(struct seq_file *s, st if (cifs_sb) { if (cifs_sb->tcon) { seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); - if (cifs_sb->tcon->ses->userName) + if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName)) seq_printf(s, ",username=%s", cifs_sb->tcon->ses->userName); if(cifs_sb->tcon->ses->domainName) @@ -243,7 +247,9 @@ struct super_operations cifs_super_ops = .delete_inode = cifs_delete_inode, *//* Do not need the above two functions unless later we add lazy close of inodes or unless the kernel forgets to call us with the same number of releases (closes) as opens */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) .show_options = cifs_show_options, +#endif /* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ }; @@ -272,6 +278,27 @@ cifs_get_sb(struct file_system_type *fs_ return sb; } +ssize_t +cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, + loff_t * poffset) +{ + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) + return generic_file_read(file,read_data,read_size,poffset); + else + return cifs_read(file,read_data,read_size,poffset); +} + +ssize_t +cifs_write_wrapper(struct file * file, const char *write_data, + size_t write_size, loff_t * poffset) +{ + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) /* check caching for write */ + return generic_file_write(file,write_data, write_size,poffset); + else + return cifs_write(file,write_data,write_size,poffset); +} + + static struct file_system_type cifs_fs_type = { .owner = THIS_MODULE, .name = "cifs", @@ -296,6 +323,7 @@ struct inode_operations cifs_dir_inode_o .revalidate = cifs_revalidate, .setattr = cifs_setattr, .symlink = cifs_symlink, + .mknod = cifs_mknod, }; struct inode_operations cifs_file_inode_ops = { @@ -334,7 +362,7 @@ struct file_operations cifs_file_ops = { .release = cifs_close, .lock = cifs_lock, .fsync = cifs_fsync, - .flush = cifs_flush, + .flush = cifs_flush, .mmap = cifs_file_mmap, /* .sendfile = generic_file_sendfile,*/ }; @@ -425,46 +453,57 @@ cifs_destroy_mids(void) "cifs_destroy_mids: error not all structures were freed\n"); if (kmem_cache_destroy(cifs_oplock_cachep)) printk(KERN_WARNING - "error not all oplock structures were freed\n");} + "error not all oplock structures were freed\n"); +} static int cifs_oplock_thread(void * dummyarg) { struct list_head * tmp; + struct list_head * tmp1; struct oplock_q_entry * oplock_item; - struct file * pfile; struct cifsTconInfo *pTcon; - int rc; + struct inode * inode; + __u16 netfid; + int rc = 0; daemonize(); - + sprintf(current->comm,"cifsoplockd"); oplockThread = current; - while (1) { + do { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(100*HZ); /* BB add missing code */ - cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */ write_lock(&GlobalMid_Lock); - list_for_each(tmp, &GlobalOplock_Q) { - oplock_item = list_entry(tmp, struct - oplock_q_entry, + list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) { + oplock_item = list_entry(tmp, struct oplock_q_entry, qhead); if(oplock_item) { pTcon = oplock_item->tcon; - pfile = oplock_item->file_to_flush; - cFYI(1,("process item on queue"));/* BB remove */ + inode = oplock_item->pinode; + netfid = oplock_item->netfid; DeleteOplockQEntry(oplock_item); write_unlock(&GlobalMid_Lock); - rc = filemap_fdatasync(pfile->f_dentry->d_inode->i_mapping); - cFYI(1,("Oplock flush file %p rc %d",pfile,rc)); - /* send oplock break */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); + if(rc) + CIFS_I(inode)->write_behind_rc + = rc; +#else + filemap_fdatasync(pinode->i_mapping); +#endif + rc = CIFSSMBLock(0, pTcon, + netfid, + 0 /* len */ , 0 /* offset */, 0, + 0, LOCKING_ANDX_OPLOCK_RELEASE, + 0 /* wait flag */); + cFYI(1,("Oplock release rc = %d ",rc)); write_lock(&GlobalMid_Lock); } else break; - cFYI(1,("next time through list")); /* BB remove */ } write_unlock(&GlobalMid_Lock); - cFYI(1,("next time through while loop")); /* BB remove */ - } + } while(!signal_pending(current)); + complete_and_exit (&cifs_oplock_exited, 0); } static int __init @@ -526,8 +565,10 @@ exit_cifs(void) /* cifs_destroy_inodecache();*/ cifs_destroy_mids(); cifs_destroy_request_bufs(); - if(oplockThread) - send_sig(SIGKILL, oplockThread, 1); + if(oplockThread) { + send_sig(SIGTERM, oplockThread, 1); + wait_for_completion(&cifs_oplock_exited); + } } MODULE_AUTHOR("Steve French "); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsfs.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsfs.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsfs.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsfs.h 2003-08-17 21:27:53.000000000 +0200 @@ -50,6 +50,7 @@ extern int cifs_create(struct inode *, s extern struct dentry *cifs_lookup(struct inode *, struct dentry *); extern int cifs_unlink(struct inode *, struct dentry *); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); +extern int cifs_mknod(struct inode *, struct dentry *, int, int); extern int cifs_mkdir(struct inode *, struct dentry *, int); extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rename(struct inode *, struct dentry *, struct inode *, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsglob.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsglob.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsglob.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsglob.h 2003-08-17 21:27:53.000000000 +0200 @@ -149,11 +149,14 @@ struct cifsSesInfo { struct TCP_Server_Info *server; /* pointer to server info */ atomic_t inUse; /* # of CURRENT users of this ses */ enum statusEnum status; + __u32 sequence_number; /* needed for CIFS PDU signature */ __u16 ipc_tid; /* special tid for connection to IPC share */ + char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; char *serverOS; /* name of operating system underlying the server */ char *serverNOS; /* name of network operating system that the server is running */ char *serverDomain; /* security realm of server */ - int Suid; /* needed for user level security */ + int Suid; /* remote smb uid */ + uid_t linux_uid; /* local Linux uid */ int capabilities; char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ char userName[MAX_USERNAME_SIZE + 1]; @@ -204,7 +207,8 @@ struct cifsFileInfo { __u16 netfid; /* file id from remote */ /* BB add lock scope info here if needed */ ; /* lock scope id (0 if none) */ - struct file * pfile; /* needed for writepage */ + struct file * pfile; /* needed for writepage */ + struct inode * pInode; /* needed for oplock break */ int endOfSearch:1; /* we have reached end of search */ int closePend:1; /* file is marked to close */ int emptyDir:1; @@ -221,6 +225,7 @@ struct cifsInodeInfo { struct list_head lockList; /* BB add in lists for dirty pages - i.e. write caching info for oplock */ struct list_head openFileList; + int write_behind_rc; __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ unsigned long time; /* jiffies of last update/check of inode */ @@ -245,6 +250,7 @@ struct mid_q_entry { struct list_head qhead; /* mids waiting on reply from this server */ __u16 mid; /* multiplex id */ __u16 pid; /* process id */ + __u32 sequence_number; /* for CIFS signing */ __u16 command; /* smb command code */ struct timeval when_sent; /* time when smb sent */ struct cifsSesInfo *ses; /* smb was sent to this server */ @@ -255,8 +261,9 @@ struct mid_q_entry { struct oplock_q_entry { struct list_head qhead; - struct file * file_to_flush; + struct inode * pinode; struct cifsTconInfo * tcon; + __u16 netfid; }; #define MID_FREE 0 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifspdu.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifspdu.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifspdu.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifspdu.h 2003-08-17 21:27:53.000000000 +0200 @@ -307,7 +307,13 @@ struct smb_hdr { __u8 Flags; __u16 Flags2; /* note: le */ __u16 PidHigh; /* note: le */ - __u8 SecuritySignature[8]; /* note le */ + union { + struct { + __u32 SequenceNumber; /* le */ + __u32 Reserved; /* zero */ + } Sequence; + __u8 SecuritySignature[8]; /* le */ + } Signature; __u8 pad[2]; __u16 Tid; __u16 Pid; /* note: le */ @@ -627,6 +633,12 @@ typedef struct smb_com_open_req { /* als char fileName[1]; } OPEN_REQ; +/* open response: oplock levels */ +#define OPLOCK_NONE 0 +#define OPLOCK_EXCLUSIVE 1 +#define OPLOCK_BATCH 2 +#define OPLOCK_READ 3 /* level 2 oplock */ + typedef struct smb_com_open_rsp { struct smb_hdr hdr; /* wct = 34 BB */ __u8 AndXCommand; @@ -1263,6 +1275,7 @@ typedef struct dfs_referral_level_3 { __u16 ServerType; /* 0x0001 = CIFS server */ __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ __u16 TimeToLive; + __u16 Proximity; __u16 DfsPathOffset; __u16 DfsAlternatePathOffset; __u16 NetworkAddressOffset; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsproto.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsproto.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifsproto.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifsproto.h 2003-08-17 21:27:53.000000000 +0200 @@ -49,7 +49,7 @@ extern int SendReceive(const unsigned in extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); -extern int smbCalcSize(struct smb_hdr *ptr); +extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int map_smb_to_linux_error(struct smb_hdr *smb); @@ -57,7 +57,7 @@ extern void header_assemble(struct smb_h const struct cifsTconInfo *, int /* length of fixed section (word count) in two byte units */ ); -struct oplock_q_entry * AllocOplockQEntry(struct file *,struct cifsTconInfo *); +struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); void DeleteOplockQEntry(struct oplock_q_entry *); extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(time_t); @@ -68,7 +68,8 @@ extern void RevUcode_to_Ucode_with_Len(c extern void Ucode_to_RevUcode_with_Len(char *Unicode, char *revUnicodeName, int Len); extern int cifs_get_inode_info(struct inode **pinode, - const unsigned char *search_path, + const unsigned char *search_path, + FILE_ALL_INFO * pfile_info, struct super_block *sb); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, @@ -79,8 +80,7 @@ extern int setup_session(unsigned int xi struct nls_table * nls_info); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *session_key, char *ntlm_session_key, - const struct nls_table *); + char *ntlm_session_key, const struct nls_table *); extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *SecurityBlob,int SecurityBlobLength, const struct nls_table *); @@ -89,8 +89,7 @@ extern int CIFSNTLMSSPNegotiateSessSetup const struct nls_table *); extern int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *ntlm_session_key, - char *lanman_session_key,int ntlmv2_flag, - const struct nls_table *); + int ntlmv2_flag, const struct nls_table *); extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const char *tree, struct cifsTconInfo *tcon, @@ -127,13 +126,15 @@ extern int CIFSSMBUnixQPathInfo(const in extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, unsigned char **targetUNCs, - int *number_of_UNC_in_array, + unsigned int *number_of_UNC_in_array, const struct nls_table *nls_codepage); extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage); - +extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, unsigned char ** preferrals); extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct statfs *FSData, const struct nls_table *nls_codepage); @@ -155,7 +156,7 @@ extern int CIFSSMBSetFileSize(const int __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, char *full_path, __u64 mode, __u64 uid, - __u64 gid, const struct nls_table *nls_codepage); + __u64 gid, dev_t dev, const struct nls_table *nls_codepage); extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, const char *newName, @@ -195,7 +196,7 @@ extern int CIFSSMBQueryReparseLinkInfo(c extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, - __u16 * netfid, int *pOplock, + __u16 * netfid, int *pOplock, FILE_ALL_INFO *, const struct nls_table *nls_codepage); extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, const int smb_file_id); @@ -224,7 +225,12 @@ extern void tconInfoFree(struct cifsTcon extern int cifs_demultiplex_thread(struct TCP_Server_Info *); extern int cifs_reconnect(struct TCP_Server_Info *server); -/* BB routines below not implemented yet BB */ +extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); +extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key, + __u32 expected_sequence_number); +extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); +extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); +extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); extern int CIFSBuildServerList(int xid, char *serverBufferList, int recordlength, int *entries, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifssmb.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifssmb.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/cifssmb.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/cifssmb.c 2003-08-17 21:27:53.000000000 +0200 @@ -106,9 +106,6 @@ CIFSSMBNegotiate(unsigned int xid, struc pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; if (extended_security) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - if (sign_CIFS_PDUs) { - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - } pSMB->ByteCount = strlen(protocols[0].name) + 1; strncpy(pSMB->DialectsArray, protocols[0].name, 30); @@ -182,7 +179,11 @@ CIFSSMBNegotiate(unsigned int xid, struc cERROR(1, ("Server requires /proc/fs/cifs/PacketSigningEnabled")); server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 1) { + if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } + } if (pSMB) buf_release(pSMB); @@ -260,10 +261,13 @@ CIFSSMBLogoff(const int xid, struct cifs up(&ses->sesSem); return -EBUSY; } - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */, (void **) &pSMB, (void **) &smb_buffer_response); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if (rc) { up(&ses->sesSem); return rc; @@ -419,7 +423,8 @@ int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, __u16 * netfid, - int *pOplock, const struct nls_table *nls_codepage) + int *pOplock, FILE_ALL_INFO * pfile_info, + const struct nls_table *nls_codepage) { int rc = -EACCES; OPEN_REQ *pSMB = NULL; @@ -476,16 +481,23 @@ CIFSSMBOpen(const int xid, struct cifsTc pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + /* long_op set to 1 to allow for oplock break timeouts */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); + (struct smb_hdr *) pSMBr, &bytes_returned, 1); if (rc) { cFYI(1, ("Error in Open = %d", rc)); } else { *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ *netfid = pSMBr->Fid; /* cifs fid stays in le */ /* Do we care about the CreateAction in any cases? */ - - /* BB add code to update inode file sizes from create response */ + if(pfile_info) { + memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime, + 36 /* CreationTime to Attributes */); + /* the file_info buf is endian converted by caller */ + pfile_info->AllocationSize = pSMBr->AllocationSize; + pfile_info->EndOfFile = pSMBr->EndOfFile; + pfile_info->NumberOfLinks = cpu_to_le32(1); + } } if (pSMB) buf_release(pSMB); @@ -618,6 +630,7 @@ CIFSSMBLock(const int xid, struct cifsTc LOCK_REQ *pSMB = NULL; LOCK_RSP *pSMBr = NULL; int bytes_returned; + int timeout = 0; cFYI(1, ("In CIFSSMBLock")); @@ -626,6 +639,9 @@ CIFSSMBLock(const int xid, struct cifsTc if (rc) return rc; + if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) + timeout = -1; /* no response expected */ + pSMB->NumberOfLocks = cpu_to_le32(numLock); pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock); pSMB->LockType = lockType; @@ -640,7 +656,7 @@ CIFSSMBLock(const int xid, struct cifsTc pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); + (struct smb_hdr *) pSMBr, &bytes_returned, timeout); if (rc) { cERROR(1, ("Send error in Lock = %d", rc)); @@ -1227,11 +1243,12 @@ CIFSSMBQPathInfo(const int xid, struct c /* BB also check enough total bytes returned */ if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) rc = -EIO; /* bad smb */ - else { + else if (pFindData){ memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + pSMBr->DataOffset, sizeof (FILE_ALL_INFO)); - } + } else + rc = -ENOMEM; } if (pSMB) buf_release(pSMB); @@ -1625,15 +1642,18 @@ int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, unsigned char **targetUNCs, - int *number_of_UNC_in_array, + unsigned int *number_of_UNC_in_array, const struct nls_table *nls_codepage) { /* TRANS2_GET_DFS_REFERRAL */ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; + struct dfs_referral_level_3 * referrals = NULL; int rc = 0; int bytes_returned; int name_len; + unsigned int i; + char * temp; *number_of_UNC_in_array = 0; *targetUNCs = NULL; @@ -1654,8 +1674,6 @@ CIFSGetDFSRefer(const int xid, struct ci if (ses->capabilities & CAP_DFS) { pSMB->hdr.Flags2 |= SMBFLG2_DFS; } - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; @@ -1701,6 +1719,76 @@ CIFSGetDFSRefer(const int xid, struct ci cFYI(1, ("Send error in GetDFSRefer = %d", rc)); } else { /* decode response */ /* BB Add logic to parse referrals here */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + cFYI(1, + ("Decoding GetDFSRefer response. BCC: %d Offset %d", + pSMBr->ByteCount, pSMBr->DataOffset)); + if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof start of data block */ + + pSMBr->DataOffset + + (char *) &pSMBr->hdr.Protocol); + cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive)); + /* BB This field is actually two bytes in from start of + data block so we could do safety check that DataBlock + begins at address of pSMBr->NumberOfReferrals */ + *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals); + + /* BB Fix below so can return more than one referral */ + if(*number_of_UNC_in_array > 1) + *number_of_UNC_in_array = 1; + + /* get the length of the strings describing refs */ + name_len = 0; + for(i=0;i<*number_of_UNC_in_array;i++) { + /* make sure that DfsPathOffset not past end */ + referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset); + if(referrals->DfsPathOffset > pSMBr->DataCount) { + /* if invalid referral, stop here and do + not try to copy any more */ + *number_of_UNC_in_array = i; + break; + } + temp = ((char *)referrals) + referrals->DfsPathOffset; + + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount); + } else { + name_len += strnlen(temp,pSMBr->DataCount); + } + referrals++; + /* BB add check that referral pointer does not fall off end PDU */ + + } + /* BB add check for name_len bigger than bcc */ + *targetUNCs = + kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL); + /* copy the ref strings */ + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof data hdr */ + + pSMBr->DataOffset + + (char *) &pSMBr->hdr.Protocol); + + for(i=0;i<*number_of_UNC_in_array;i++) { + temp = ((char *)referrals) + referrals->DfsPathOffset; + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + cifs_strfromUCS_le(*targetUNCs, + (wchar_t *) temp, name_len, nls_codepage); + } else { + strncpy(*targetUNCs,temp,name_len); + } + /* BB update target_uncs pointers */ + referrals++; + } + temp = *targetUNCs; + temp[name_len] = 0; + } + } if (pSMB) buf_release(pSMB); @@ -2227,7 +2315,7 @@ CIFSSMBSetTimes(int xid, struct cifsTcon int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, char *fileName, __u64 mode, __u64 uid, __u64 gid, - const struct nls_table *nls_codepage) + dev_t device, const struct nls_table *nls_codepage) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -2286,6 +2374,9 @@ CIFSSMBUnixSetPerms(const int xid, struc pSMB->hdr.smb_buf_length += pSMB->ByteCount; data_offset->Uid = cpu_to_le64(uid); data_offset->Gid = cpu_to_le64(gid); + /* better to leave device as zero when it is */ + data_offset->DevMajor = cpu_to_le64(MAJOR(device)); + data_offset->DevMinor = cpu_to_le64(MINOR(device)); data_offset->Permissions = cpu_to_le64(mode); pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/connect.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/connect.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/connect.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/connect.c 2003-08-17 21:27:53.000000000 +0200 @@ -53,7 +53,7 @@ struct smb_vol { char *UNC; char *UNCip; uid_t linux_uid; - uid_t linux_gid; + gid_t linux_gid; mode_t file_mode; mode_t dir_mode; int rw; @@ -136,8 +136,8 @@ cifs_reconnect(struct TCP_Server_Info *s int cifs_demultiplex_thread(struct TCP_Server_Info *server) { - int length, total_read; - unsigned int pdu_length; + int length; + unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; struct msghdr smb_msg; mm_segment_t temp_fs; @@ -150,6 +150,8 @@ cifs_demultiplex_thread(struct TCP_Serve char *temp; daemonize(); + sprintf(current->comm,"cifsd"); + /* allow_signal(SIGKILL);*/ server->tsk = current; /* save process info to wake at shutdown */ @@ -200,7 +202,7 @@ cifs_demultiplex_thread(struct TCP_Serve continue; } pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); - cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length)); /* BB */ + cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length)); temp = (char *) smb_buffer; if (length > 3) { @@ -251,7 +253,7 @@ cifs_demultiplex_thread(struct TCP_Serve /* iov.iov_base = smb_buffer+total_read; iov.iov_len = pdu_length-total_read; */ length = sock_recvmsg(csocket, &smb_msg, - pdu_length - total_read, 0); + pdu_length - total_read, 0); /* cERROR(1,("For iovlen %d Length received: %d with total read %d", iov.iov_len, length,total_read)); */ if (length == 0) { @@ -332,8 +334,9 @@ cifs_demultiplex_thread(struct TCP_Serve kfree(server); } else /* BB need to more gracefully handle the rare negative session response case because response will be still outstanding */ - cERROR(1, ("There are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!")); /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ -/* BB Need to fix bug in error path above - perhaps wait until smb requests + cERROR(1, ("Active MIDs in queue while exiting - can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!")); + /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ + /* BB Need to fix bug in error path above - perhaps wait until smb requests time out and then free the tcp per server struct BB */ read_unlock(&GlobalSMBSeslock); @@ -346,10 +349,15 @@ parse_mount_options(char *options, char { char *value; char *data; + int temp_len; memset(vol,0,sizeof(struct smb_vol)); vol->linux_uid = current->uid; /* current->euid instead? */ vol->linux_gid = current->gid; + vol->dir_mode = S_IRWXUGO; + /* 2767 perms indicate mandatory locking support */ + vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + vol->rw = TRUE; if (!options) @@ -398,8 +406,9 @@ parse_mount_options(char *options, char "CIFS: invalid path to network resource\n"); return 1; /* needs_arg; */ } - if (strnlen(value, 300) < 300) { - vol->UNC = value; + if ((temp_len = strnlen(value, 300)) < 300) { + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); + strcpy(vol->UNC,value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; @@ -464,6 +473,8 @@ parse_mount_options(char *options, char /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; + } else if (strnicmp(data, "ro", 2) == 0) { + vol->rw = FALSE; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); } @@ -472,8 +483,9 @@ parse_mount_options(char *options, char printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); return 1; } - if (strnlen(devname, 300) < 300) { - vol->UNC = devname; + if ((temp_len = strnlen(devname, 300)) < 300) { + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); + strcpy(vol->UNC,devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; @@ -572,10 +584,31 @@ int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage) { + unsigned char *referrals = NULL; + unsigned int num_referrals; + int rc = 0; + + rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, + &num_referrals, &referrals); + + /* BB Add in code to: if valid refrl, if not ip address contact + the helper that resolves tcp names, mount to it, try to + tcon to it unmount it if fail */ + + /* BB free memory for referrals string BB */ + + return rc; +} + +int +get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, unsigned char ** preferrals) +{ char *temp_unc; int rc = 0; - int num_referrals = 0; - unsigned char *referrals = NULL; + + *pnum_referrals = 0; if (pSesInfo->ipc_tid == 0) { temp_unc = kmalloc(2 /* for slashes */ + @@ -594,17 +627,15 @@ connect_to_dfs_path(int xid, struct cifs kfree(temp_unc); } if (rc == 0) - rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &referrals, - &num_referrals, nls_codepage); - - return -ENODEV; /* BB remove and add return code processing */ + rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, + pnum_referrals, nls_codepage); + return rc; } int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) { int rc = 0; - char session_key[CIFS_SESSION_KEY_SIZE]; char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; int ntlmv2_flag = FALSE; @@ -612,6 +643,7 @@ int setup_session(unsigned int xid, stru if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ rc = CIFSSMBNegotiate(xid, pSesInfo); pSesInfo->capabilities = pSesInfo->server->capabilities; + pSesInfo->sequence_number = 0; if (!rc) { cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", pSesInfo->server->secMode, @@ -635,35 +667,46 @@ int setup_session(unsigned int xid, stru nls_info); if (!rc) { if(ntlmv2_flag) { - cFYI(1,("Able to use the more secure NTLM version 2 password hash")); - /* SMBNTv2encrypt( ...); */ /* BB fix this up - - and note that Samba client equivalent looks wrong */ - } else + char * v2_response; + cFYI(1,("Can use more secure NTLM version 2 password hash")); + CalcNTLMv2_partial_mac_key(pSesInfo, + nls_info); + v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); + if(v2_response) { + CalcNTLMv2_response(pSesInfo,v2_response); +/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + kfree(v2_response); + /* BB Put dummy sig in SessSetup PDU? */ + } else + rc = -ENOMEM; + + } else { SMBNTencrypt(pSesInfo->password_with_pad, - pSesInfo->server->cryptKey,ntlm_session_key); + pSesInfo->server->cryptKey, + ntlm_session_key); - /* for better security the weaker lanman hash not sent - in AuthSessSetup so why bother calculating it */ - /* toUpper(nls_info, - password_with_pad); - SMBencrypt(password_with_pad, - pSesInfo->server->cryptKey, session_key); */ + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, + pSesInfo->password_with_pad); + } + /* for better security the weaker lanman hash not sent + in AuthSessSetup so we no longer calculate it */ rc = CIFSNTLMSSPAuthSessSetup(xid, - pSesInfo, - ntlm_session_key, - session_key, - ntlmv2_flag, - nls_info); + pSesInfo, + ntlm_session_key, + ntlmv2_flag, + nls_info); } } else { /* old style NTLM 0.12 session setup */ SMBNTencrypt(pSesInfo->password_with_pad, pSesInfo->server->cryptKey, ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, pSesInfo->password_with_pad); rc = CIFSSessSetup(xid, pSesInfo, - session_key, - ntlm_session_key, - nls_info); + ntlm_session_key, nls_info); } if (rc) { cERROR(1,("Send error in SessSetup = %d",rc)); @@ -792,6 +835,8 @@ cifs_mount(struct super_block *sb, struc cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); if(parse_mount_options(mount_data, devname, &volume_info)) { + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return -EINVAL; } @@ -817,7 +862,7 @@ cifs_mount(struct super_block *sb, struc FreeXid(xid); return -EINVAL; } - /* BB add support to use the multiuser_mount flag BB */ + existingCifsSes = find_tcp_session(sin_server.sin_addr.s_addr, volume_info.username, &srvTcp); @@ -832,6 +877,8 @@ cifs_mount(struct super_block *sb, struc ("Error connecting to IPv4 socket. Aborting operation")); if(csocket != NULL) sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return rc; } @@ -840,6 +887,8 @@ cifs_mount(struct super_block *sb, struc if (srvTcp == NULL) { rc = -ENOMEM; sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return rc; } else { @@ -879,6 +928,7 @@ cifs_mount(struct super_block *sb, struc if (volume_info.domainname) strncpy(pSesInfo->domainName, volume_info.domainname,MAX_USERNAME_SIZE); + pSesInfo->linux_uid = volume_info.linux_uid; rc = setup_session(xid,pSesInfo, cifs_sb->local_nls); if(!rc) @@ -900,8 +950,11 @@ cifs_mount(struct super_block *sb, struc cifs_sb->rsize = PAGE_CACHE_SIZE; cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); } - - + cifs_sb->mnt_uid = volume_info.linux_uid; + cifs_sb->mnt_gid = volume_info.linux_gid; + cifs_sb->mnt_file_mode = volume_info.file_mode; + cifs_sb->mnt_dir_mode = volume_info.dir_mode; + cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); @@ -923,6 +976,8 @@ cifs_mount(struct super_block *sb, struc "", cifs_sb-> local_nls); + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return -ENODEV; } else { @@ -975,7 +1030,8 @@ cifs_mount(struct super_block *sb, struc if (tcon->ses->capabilities & CAP_UNIX) CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); } - + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return rc; } @@ -983,7 +1039,6 @@ cifs_mount(struct super_block *sb, struc int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, char session_key[CIFS_SESSION_KEY_SIZE], - char session_key2[CIFS_SESSION_KEY_SIZE], const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; @@ -1040,9 +1095,9 @@ CIFSSessSetup(unsigned int xid, struct c pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); - /* memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); + /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; */ - memcpy(bcc_ptr, (char *) session_key2, CIFS_SESSION_KEY_SIZE); + memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { @@ -1053,7 +1108,7 @@ CIFSSessSetup(unsigned int xid, struct c if(user == NULL) bytes_returned = 0; /* skill null user */ else - bytes_returned = + bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ @@ -1253,7 +1308,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st int bytes_returned = 0; int len; - cFYI(1, ("In v2 sesssetup ")); + cFYI(1, ("In spnego sesssetup ")); smb_buffer = buf_get(); if (smb_buffer == 0) { @@ -1561,7 +1616,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i SecurityBlob->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | - NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_128; + /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; + if(sign_CIFS_PDUs) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; if(ntlmv2_support) SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; /* setup pointers to domain name and workstation name */ @@ -1681,6 +1738,17 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i CIFS_CRYPTO_KEY_SIZE); if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) *pNTLMv2_flag = TRUE; + + if((SecurityBlob2->NegotiateFlags & + NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + || (sign_CIFS_PDUs > 1)) + ses->server->secMode |= + SECMODE_SIGN_REQUIRED; + if ((SecurityBlob2->NegotiateFlags & + NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs)) + ses->server->secMode |= + SECMODE_SIGN_ENABLED; + if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = @@ -1824,7 +1892,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *ntlm_session_key, char *lanman_session_key, int ntlmv2_flag, + char *ntlm_session_key, int ntlmv2_flag, const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; @@ -1890,7 +1958,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi SecurityBlob->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | - 0x80000000 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_128; + 0x80000000 | NTLMSSP_NEGOTIATE_128; + if(sign_CIFS_PDUs) + SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; if(ntlmv2_flag) SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; @@ -2273,7 +2343,7 @@ CIFSTCon(unsigned int xid, struct cifsSe length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); /* skip service field (NB: this field is always ASCII) */ bcc_ptr += length + 1; - strncpy(tcon->treeName, tree, MAX_TREE_SIZE); + strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { length = UniStrnlen((wchar_t *) bcc_ptr, 512); if (((long) bcc_ptr + (2 * length)) - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/dir.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/dir.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/dir.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/dir.c 2003-08-17 21:27:53.000000000 +0200 @@ -123,11 +123,13 @@ cifs_create(struct inode *inode, struct { int rc = -ENOENT; int xid; - int oplock = REQ_OPLOCK; + int oplock = 0; /* no sense requested oplock if we are just going to + immediately close the file */ __u16 fileHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; + FILE_ALL_INFO * buf = NULL; struct inode *newinode = NULL; xid = GetXid(); @@ -137,46 +139,96 @@ cifs_create(struct inode *inode, struct full_path = build_path_from_dentry(direntry); - /* BB add processing for setting the equivalent of mode - e.g. via CreateX with ACLs */ + /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ - rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, GENERIC_ALL - /* 0x20197 was used previously */ , CREATE_NOT_DIR, - &fileHandle, &oplock, cifs_sb->local_nls); + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, + GENERIC_ALL, CREATE_NOT_DIR, + &fileHandle, &oplock, buf, cifs_sb->local_nls); if (rc) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { + /* BB for case of overwriting existing file can we use the inode that was + passed in rather than creating new one?? */ if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb); else rc = cifs_get_inode_info(&newinode, full_path, - inode->i_sb); + buf, inode->i_sb); if (rc != 0) { cFYI(1,("Create worked but get_inode_info failed with rc = %d", rc)); - /* close handle */ } else { direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); } - /* BB check oplock state before deciding to call following */ -/* if(*oplock) - save off handle in inode and dontdoclose */ - - CIFSSMBClose(xid, pTcon, fileHandle); - /* BB In the future chain close with the NTCreateX to narrow window */ - - if(newinode) - newinode->i_mode = mode; - } + + CIFSSMBClose(xid, pTcon, fileHandle); + + if(newinode) { + newinode->i_mode = mode; + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, + (__u64)-1, + (__u64)-1, + 0 /* dev */, + cifs_sb->local_nls); + else { /* BB implement via Windows security descriptors */ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + /* in the meantime could set r/o dos attribute when perms are eg: + mode & 0222 == 0 */ + } + } + } + + if (buf) + kfree(buf); if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); return rc; } +int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number) +{ + int rc = -EPERM; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode * newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + full_path = build_path_from_dentry(direntry); + + if (pTcon->ses->capabilities & CAP_UNIX) { + rc = CIFSSMBUnixSetPerms(xid, pTcon, + full_path, mode, current->euid, current->egid, + device_number, cifs_sb->local_nls); + if(!rc) { + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb); + direntry->d_op = &cifs_dentry_ops; + if(rc == 0) + d_instantiate(direntry, newinode); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + + struct dentry * cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) { @@ -211,7 +263,7 @@ cifs_lookup(struct inode *parent_dir_ino rc = cifs_get_inode_info_unix(&newInode, full_path, parent_dir_inode->i_sb); else - rc = cifs_get_inode_info(&newInode, full_path, + rc = cifs_get_inode_info(&newInode, full_path, NULL, parent_dir_inode->i_sb); if ((rc == 0) && (newInode != NULL)) { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/file.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/file.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/file.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/file.c 2003-08-17 21:27:53.000000000 +0200 @@ -49,6 +49,7 @@ cifs_open(struct inode *inode, struct fi int desiredAccess = 0x20197; int disposition = FILE_OPEN; __u16 netfid; + FILE_ALL_INFO * buf = NULL; xid = GetXid(); @@ -86,20 +87,22 @@ cifs_open(struct inode *inode, struct fi if (file->f_flags & O_CREAT) disposition = FILE_OVERWRITE; - /* BB first check if file has batch oplock (or oplock ?) */ - - /* BB finish adding in oplock support BB */ if (oplockEnabled) oplock = REQ_OPLOCK; else oplock = FALSE; /* BB pass O_SYNC flag through on file attributes .. BB */ + + /* Also refresh inode by passing in file_info buf returned by SMBOpen + and calling get_inode_info with returned buf (at least + helps non-Unix server case */ + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, - CREATE_NOT_DIR, &netfid, &oplock, cifs_sb->local_nls); + CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); if (rc) { cFYI(1, ("cifs_open returned 0x%x ", rc)); - cFYI(1, ("oplock: %d ", oplock)); + cFYI(1, ("oplock: %d ", oplock)); } else { file->private_data = kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); @@ -110,17 +113,37 @@ cifs_open(struct inode *inode, struct fi pCifsFile->netfid = netfid; pCifsFile->pid = current->pid; pCifsFile->pfile = file; /* needed for writepage */ + pCifsFile->pInode = inode; + spin_lock(&files_lock); + write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist,&pTcon->openFileList); pCifsInode = CIFS_I(file->f_dentry->d_inode); - if(pCifsInode->openFileList.next) + if(pCifsInode) { + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, + full_path, inode->i_sb); + else + rc = cifs_get_inode_info(&file->f_dentry->d_inode, + full_path, buf, inode->i_sb); + list_add(&pCifsFile->flist,&pCifsInode->openFileList); + if(oplock == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if(oplock == OPLOCK_READ) + pCifsInode->clientCanCacheRead = TRUE; + } + write_unlock(&GlobalSMBSeslock); + spin_unlock(&files_lock); if(file->f_flags & O_CREAT) { /* time to set mode which we can not set earlier due to problems creating new read-only files */ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, + (__u64)-1, + (__u64)-1, + 0 /* dev */, cifs_sb->local_nls); else {/* BB implement via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ @@ -131,6 +154,8 @@ cifs_open(struct inode *inode, struct fi } } + if (buf) + kfree(buf); if (full_path) kfree(full_path); FreeXid(xid); @@ -152,21 +177,27 @@ int reopen_files(struct cifsTconInfo * p { int rc = 0; struct cifsFileInfo *open_file = NULL; - struct file * file = NULL; + struct file * file = NULL; struct list_head *tmp; + struct list_head *tmp1; /* list all files open on tree connection */ - list_for_each(tmp, &pTcon->openFileList) { - open_file = list_entry(tmp,struct cifsFileInfo, flist); + read_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, tlist); if(open_file) { if(open_file->search_resume_name) { kfree(open_file->search_resume_name); } file = open_file->pfile; + list_del(&open_file->flist); + list_del(&open_file->tlist); kfree(open_file); if(file) { file->private_data = NULL; + read_unlock(&GlobalSMBSeslock); rc = cifs_open(file->f_dentry->d_inode,file); + read_lock(&GlobalSMBSeslock); if(rc) { cFYI(1,("reconnecting file %s failed with %d", file->f_dentry->d_name.name,rc)); @@ -177,6 +208,7 @@ int reopen_files(struct cifsTconInfo * p } } } + read_unlock(&GlobalSMBSeslock); return rc; } @@ -195,9 +227,10 @@ cifs_close(struct inode *inode, struct f cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; if (pSMBFile) { - if(pSMBFile->flist.next) - list_del(&pSMBFile->flist); + spin_lock(&files_lock); + list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); + spin_unlock(&files_lock); rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); if(pSMBFile->search_resume_name) kfree(pSMBFile->search_resume_name); @@ -206,6 +239,15 @@ cifs_close(struct inode *inode, struct f } else rc = -EBADF; + if(list_empty(&(CIFS_I(inode)->openFileList))) { + cFYI(1,("closing last open instance for inode %p",inode)); + /* if the file is not open we do not know if we can cache + info on this inode, much less write behind and read ahead */ + CIFS_I(inode)->clientCanCacheRead = FALSE; + CIFS_I(inode)->clientCanCacheAll = FALSE; + } + if((rc ==0) && CIFS_I(inode)->write_behind_rc) + rc = CIFS_I(inode)->write_behind_rc; FreeXid(xid); return rc; } @@ -338,8 +380,8 @@ cifs_write(struct file * file, const cha size_t write_size, loff_t * poffset) { int rc = 0; - int bytes_written = 0; - int total_written; + unsigned int bytes_written = 0; + unsigned int total_written; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid, long_op; @@ -407,6 +449,7 @@ cifs_partialpagewrite(struct page *page, struct cifsInodeInfo *cifsInode; struct cifsFileInfo *open_file = NULL; struct list_head *tmp; + struct list_head *tmp1; int xid; xid = GetXid(); @@ -442,14 +485,17 @@ cifs_partialpagewrite(struct page *page, cifsInode = CIFS_I(mapping->host); - list_for_each(tmp, &cifsInode->openFileList) { - open_file = list_entry(tmp,struct cifsFileInfo, flist); - /* We could check if file is open for writing first */ + read_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + /* We check if file is open for writing first */ if((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { + read_unlock(&GlobalSMBSeslock); bytes_written = cifs_write(open_file->pfile, write_data, - to-from, &offset); + to-from, &offset); + read_lock(&GlobalSMBSeslock); /* Does mm or vfs already set times? */ inode->i_atime = inode->i_mtime = CURRENT_TIME; if ((bytes_written > 0) && (offset)) { @@ -459,6 +505,7 @@ cifs_partialpagewrite(struct page *page, } } } + read_unlock(&GlobalSMBSeslock); if(open_file == NULL) { cFYI(1,("No writeable filehandles for inode")); rc = -EIO; @@ -542,8 +589,15 @@ cifs_fsync(struct file *file, struct den cFYI(1, ("Sync file - name: %s datasync: 0x%x ", dentry->d_name.name, datasync)); - +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) rc = filemap_fdatasync(inode->i_mapping); +#else + filemap_fdatasync(inode->i_mapping); +#endif + + + if(rc == 0) + CIFS_I(inode)->write_behind_rc = 0; FreeXid(xid); return rc; @@ -594,9 +648,15 @@ int cifs_flush(struct file *file) /* deal with writebehind errors */ /* unlock inode for writing */ /* filemapfdatawrite appears easier for the time being */ - +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) rc = filemap_fdatasync(inode->i_mapping); +#else + filemap_fdatasync(inode->i_mapping); +#endif + cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc)); + if(rc == 0) /* reset wb rc if we were able to write out dirty pages */ + CIFS_I(inode)->write_behind_rc = 0; return rc; } @@ -607,9 +667,9 @@ cifs_read(struct file * file, char *read loff_t * poffset) { int rc = -EACCES; - int bytes_read = 0; - int total_read; - int current_read_size; + unsigned int bytes_read = 0; + unsigned int total_read; + unsigned int current_read_size; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid; @@ -675,12 +735,16 @@ static void cifs_copy_cache_pages(struct while (bytes_read > 0) { if(list_empty(pages)) break; + + spin_lock(&mapping->page_lock); page = list_entry(pages->prev, struct page, list); list_del(&page->list); + spin_unlock(&mapping->page_lock); + if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { page_cache_release(page); - cFYI(1,("Add page cache failed")); + cFYI(1,("Add page cache failed")); continue; } @@ -712,13 +776,13 @@ cifs_readpages(struct file *file, struct struct list_head *page_list, unsigned num_pages) { int rc = -EACCES; - int xid,i; + int xid; loff_t offset; struct page * page; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int bytes_read = 0; - unsigned int read_size; + unsigned int read_size,i; char * smb_read_data = 0; struct smb_com_read_rsp * pSMBr; struct pagevec lru_pvec; @@ -735,12 +799,14 @@ cifs_readpages(struct file *file, struct pagevec_init(&lru_pvec, 0); for(i = 0;ipage_lock); if(list_empty(page_list)) { break; } page = list_entry(page_list->prev, struct page, list); offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + spin_unlock(&mapping->page_lock); + /* for reads over a certain size could initiate async read ahead */ cFYI(0,("Read %d pages into cache at offset %ld ", @@ -758,12 +824,15 @@ cifs_readpages(struct file *file, struct if ((rc < 0) || (smb_read_data == NULL)) { cFYI(1,("Read error in readpages: %d",rc)); /* clean up remaing pages off list */ + + spin_lock(&mapping->page_lock); while (!list_empty(page_list) && (i < num_pages)) { page = list_entry(page_list->prev, struct page, list); list_del(&page->list); } + spin_unlock(&mapping->page_lock); break; - } else if (bytes_read > 0){ + } else if (bytes_read > 0) { pSMBr = (struct smb_com_read_rsp *)smb_read_data; cifs_copy_cache_pages(mapping, page_list, bytes_read, smb_read_data + 4 /* RFC1000 hdr */ + @@ -774,14 +843,20 @@ cifs_readpages(struct file *file, struct break; } } else { - cFYI(1,("No bytes read")); + cFYI(1,("No bytes read cleaning remaining pages off readahead list")); + /* BB turn off caching and do new lookup on file size at server? */ + while (!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev, struct page, list); + list_del(&page->list); + } + break; } if(smb_read_data) { buf_release(smb_read_data); - smb_read_data = 0; - } - bytes_read = 0; + smb_read_data = 0; + } + bytes_read = 0; } pagevec_lru_add(&lru_pvec); @@ -843,6 +918,8 @@ fill_in_inode(struct inode *tmp_inode, FILE_DIRECTORY_INFO * pfindData, int *pobject_type) { struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + pfindData->ExtFileAttributes = le32_to_cpu(pfindData->ExtFileAttributes); pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); @@ -860,7 +937,13 @@ fill_in_inode(struct inode *tmp_inode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ - tmp_inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + tmp_inode->i_uid = cifs_sb->mnt_uid; + tmp_inode->i_gid = cifs_sb->mnt_gid; + /* set default mode. will override for dirs below */ + tmp_inode->i_mode = cifs_sb->mnt_file_mode; + cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", pfindData->ExtFileAttributes)); @@ -871,7 +954,7 @@ fill_in_inode(struct inode *tmp_inode, } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ - tmp_inode->i_mode = S_IRWXUGO; + tmp_inode->i_mode = cifs_sb->mnt_dir_mode; tmp_inode->i_mode |= S_IFDIR; } else { *pobject_type = DT_REG; @@ -884,7 +967,7 @@ fill_in_inode(struct inode *tmp_inode, /* can not fill in nlink here as in qpathinfo version and Unx search */ tmp_inode->i_size = pfindData->EndOfFile; tmp_inode->i_blocks = - do_div(pfindData->AllocationSize, tmp_inode->i_blksize); + (tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits; if (pfindData->AllocationSize < pfindData->EndOfFile) cFYI(1, ("Possible sparse file: allocation size less than end of file ")); cFYI(1, @@ -958,7 +1041,8 @@ unix_fill_in_inode(struct inode *tmp_ino pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); tmp_inode->i_size = pfindData->EndOfFile; tmp_inode->i_blocks = - do_div(pfindData->NumOfBytes, tmp_inode->i_blksize); + (tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits; + if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, (" File inode ")); tmp_inode->i_op = &cifs_file_inode_ops; @@ -986,6 +1070,7 @@ construct_dentry(struct qstr *qstring, s struct dentry *tmp_dentry; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; + struct cifsInodeInfo *pCifsI; cFYI(1, ("For %s ", qstring->name)); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -997,9 +1082,45 @@ construct_dentry(struct qstr *qstring, s cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode; /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */ + if(*ptmp_inode == NULL) { + *ptmp_inode = new_inode(file->f_dentry->d_sb); + d_instantiate(tmp_dentry, *ptmp_inode); + pCifsI = CIFS_I(*ptmp_inode); + INIT_LIST_HEAD(&pCifsI->openFileList); + /* can not enable caching for this inode + until a file instance is open and we + can check the oplock flag on the open + response */ + (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; + (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ + pCifsI->clientCanCacheRead = FALSE; + pCifsI->clientCanCacheAll = FALSE; + pCifsI->time = 0; + /* do not need to set cifs Attrs since + they are about to be overwritten + in fill_in_inode */ + atomic_set(&pCifsI->inUse, 0); + } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); *ptmp_inode = new_inode(file->f_dentry->d_sb); + if(ptmp_inode) { + pCifsI = CIFS_I(*ptmp_inode); + INIT_LIST_HEAD(&pCifsI->openFileList); + /* can not enable caching for this inode + until a file instance is open and we + can check the oplock flag on the open + response */ + (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; + (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ + pCifsI->clientCanCacheRead = FALSE; + pCifsI->clientCanCacheAll = FALSE; + pCifsI->time = 0; + /* do not need to set cifs Attrs since + they are about to be overwritten + in fill_in_inode */ + atomic_set(&pCifsI->inUse, 0); + } tmp_dentry->d_op = &cifs_dentry_ops; cFYI(0, (" instantiate dentry 0x%p with inode 0x%p ", tmp_dentry, *ptmp_inode)); @@ -1057,10 +1178,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) { int rc = 0; - int xid, i; + int xid; int Unicode = FALSE; int UnixSearch = FALSE; - unsigned int bufsize; + unsigned int bufsize, i; __u16 searchHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; @@ -1150,7 +1271,7 @@ cifs_readdir(struct file *file, void *di renew_parental_timestamps(file->f_dentry); lastFindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + - le32_to_cpu(findParms.LastNameOffset)); + findParms.LastNameOffset); if((char *)lastFindData > (char *)pfindData + bufsize) { cFYI(1,("last search entry past end of packet")); rc = -EIO; @@ -1205,7 +1326,7 @@ cifs_readdir(struct file *file, void *di pfindDataUnix->FileName, cifsFile->resume_name_length); } - for (i = 2; i < findParms.SearchCount + 2; i++) { + for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) { if (UnixSearch == FALSE) { pfindData->FileNameLength = le32_to_cpu(pfindData->FileNameLength); @@ -1310,7 +1431,7 @@ cifs_readdir(struct file *file, void *di /* BB save off resume key, key name and name length */ lastFindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData - + le32_to_cpu(findNextParms.LastNameOffset)); + + findNextParms.LastNameOffset); if((char *)lastFindData > (char *)pfindData + bufsize) { cFYI(1,("last search entry past end of packet")); rc = -EIO; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/inode.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/inode.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/inode.c 2003-08-17 21:27:53.000000000 +0200 @@ -36,12 +36,12 @@ struct inode * get_cifs_inode(struct sup cFYI(1,("got new inode %p",newinode)); if(newinode) { struct cifsInodeInfo * cifsInfo = CIFS_I(newinode); - if(oplockEnabled) { - cifsInfo->clientCanCacheRead = 1; - cifsInfo->clientCanCacheAll = 1; - } + cifsInfo->clientCanCacheRead = FALSE; + cifsInfo->clientCanCacheAll = FALSE; INIT_LIST_HEAD(&cifsInfo->openFileList); cifsInfo->cifsAttrs = 0x20; /* default */ + newinode->i_blksize = CIFS_MAX_MSGSIZE; + newinode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ atomic_set(&cifsInfo->inUse, 0); cifsInfo->time = 0; } @@ -62,6 +62,9 @@ cifs_get_inode_info_unix(struct inode ** struct cifs_sb_info *cifs_sb = CIFS_SB(sb); char *tmp_path; +/* BB add caching check so we do not go to server to overwrite inode info to cached file + where the local file sizes are correct and the server info is stale BB */ + xid = GetXid(); pTcon = cifs_sb->tcon; @@ -72,10 +75,6 @@ cifs_get_inode_info_unix(struct inode ** /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ if (rc) { if (rc == -EREMOTE) { -/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path, - &referrals, - &num_referrals, - cifs_sb->local_nls); */ tmp_path = kmalloc(strnlen (pTcon->treeName, @@ -146,9 +145,13 @@ cifs_get_inode_info_unix(struct inode ** findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); findData.EndOfFile = le64_to_cpu(findData.EndOfFile); inode->i_size = findData.EndOfFile; - inode->i_blksize = - (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00; - inode->i_blocks = do_div(findData.NumOfBytes, inode->i_blksize); +/* blksize needs to be multiple of two. So safer to default to blksize + and blkbits set in superblock so 2**blkbits and blksize will match */ +/* inode->i_blksize = + (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ + inode->i_blocks = + (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits; + if (findData.NumOfBytes < findData.EndOfFile) cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file ")); cFYI(1, @@ -178,32 +181,41 @@ cifs_get_inode_info_unix(struct inode ** } int -cifs_get_inode_info(struct inode **pinode, - const unsigned char *search_path, struct super_block *sb) +cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, + FILE_ALL_INFO * pfindData, struct super_block *sb) { int xid; int rc = 0; - FILE_ALL_INFO findData; struct cifsTconInfo *pTcon; struct inode *inode; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); char *tmp_path; + char *buf = NULL; xid = GetXid(); pTcon = cifs_sb->tcon; - cFYI(1, (" Getting info on %s ", search_path)); - /* we could have done a find first instead but this returns more info */ - rc = CIFSSMBQPathInfo(xid, pTcon, search_path, &findData, + cFYI(1,("Getting info on %s ", search_path)); + + if((pfindData == NULL) && (*pinode != NULL)) { + if(CIFS_I(*pinode)->clientCanCacheRead) { + cFYI(1,("No need to revalidate inode sizes on cached file ")); + FreeXid(xid); + return rc; + } + } + + /* if file info not passed in then get it from server */ + if(pfindData == NULL) { + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + pfindData = (FILE_ALL_INFO *)buf; + /* could do find first instead but this returns more info */ + rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, cifs_sb->local_nls); + } /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ if (rc) { if (rc == -EREMOTE) { - /* BB add call to new func rc = GetDFSReferral(); */ -/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path, - &referrals, - &num_referrals, - cifs_sb->local_nls); */ tmp_path = kmalloc(strnlen (pTcon->treeName, @@ -211,8 +223,10 @@ cifs_get_inode_info(struct inode **pinod strnlen(search_path, MAX_PATHCONF) + 1, GFP_KERNEL); if (tmp_path == NULL) { - FreeXid(xid); - return -ENOMEM; + if(buf) + kfree(buf); + FreeXid(xid); + return -ENOMEM; } strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); @@ -223,8 +237,10 @@ cifs_get_inode_info(struct inode **pinod kfree(tmp_path); /* BB fix up inode etc. */ } else if (rc) { - FreeXid(xid); - return rc; + if(buf) + kfree(buf); + FreeXid(xid); + return rc; } } else { struct cifsInodeInfo *cifsInfo; @@ -236,32 +252,38 @@ cifs_get_inode_info(struct inode **pinod inode = *pinode; cifsInfo = CIFS_I(inode); - findData.Attributes = le32_to_cpu(findData.Attributes); - cifsInfo->cifsAttrs = findData.Attributes; + pfindData->Attributes = le32_to_cpu(pfindData->Attributes); + cifsInfo->cifsAttrs = pfindData->Attributes; cFYI(1, (" Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; cFYI(1, (" New time %ld ", cifsInfo->time)); atomic_inc(&cifsInfo->inUse); /* inc on every refresh of inode */ - inode->i_blksize = - (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00; +/* blksize needs to be multiple of two. So safer to default to blksize + and blkbits set in superblock so 2**blkbits and blksize will match */ +/* inode->i_blksize = + (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ + /* Linux can not store file creation time unfortunately so we ignore it */ inode->i_atime = - cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); inode->i_mtime = - cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = - cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime)); - inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* 2767 perms indicate mandatory locking - will override for dirs later */ + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); cFYI(0, - (" Attributes came in as 0x%x ", findData.Attributes)); - if (findData.Attributes & ATTR_REPARSE) { - /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ + (" Attributes came in as 0x%x ", pfindData->Attributes)); + + /* set default mode. will override for dirs below */ + inode->i_mode = cifs_sb->mnt_file_mode; + + if (pfindData->Attributes & ATTR_REPARSE) { + /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ inode->i_mode |= S_IFLNK; - } else if (findData.Attributes & ATTR_DIRECTORY) { - /* override default perms since we do not do byte range locking on dirs */ - inode->i_mode = S_IRWXUGO; - inode->i_mode |= S_IFDIR; + } else if (pfindData->Attributes & ATTR_DIRECTORY) { + /* override default perms since we do not do byte range locking on dirs */ + inode->i_mode = cifs_sb->mnt_dir_mode; + inode->i_mode |= S_IFDIR; } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only mode e.g. 555 */ @@ -269,17 +291,21 @@ cifs_get_inode_info(struct inode **pinod inode->i_mode &= ~(S_IWUGO); /* BB add code here - validate if device or weird share or device type? */ } - inode->i_size = le64_to_cpu(findData.EndOfFile); - findData.AllocationSize = le64_to_cpu(findData.AllocationSize); + inode->i_size = le64_to_cpu(pfindData->EndOfFile); + pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); inode->i_blocks = - do_div(findData.AllocationSize, inode->i_blksize); + (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits; + cFYI(1, (" Size %ld and blocks %ld ", (unsigned long) inode->i_size, inode->i_blocks)); - inode->i_nlink = le32_to_cpu(findData.NumberOfLinks); - - /* BB fill in uid and gid here? with help from winbind? */ + inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + if (S_ISREG(inode->i_mode)) { cFYI(1, (" File inode ")); inode->i_op = &cifs_file_inode_ops; @@ -297,6 +323,8 @@ cifs_get_inode_info(struct inode **pinod kdev_t_to_nr(inode->i_rdev)); } } + if(buf) + kfree(buf); FreeXid(xid); return rc; } @@ -312,7 +340,7 @@ cifs_read_inode(struct inode *inode) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) cifs_get_inode_info_unix(&inode, "", inode->i_sb); else - cifs_get_inode_info(&inode, "", inode->i_sb); + cifs_get_inode_info(&inode, "", NULL, inode->i_sb); } int @@ -345,7 +373,7 @@ cifs_unlink(struct inode *inode, struct rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, - &netfid, &oplock, cifs_sb->local_nls); + &netfid, &oplock, NULL, cifs_sb->local_nls); if(rc==0) { CIFSSMBClose(xid, pTcon, netfid); /* BB In the future chain close with the NTCreateX to narrow window */ @@ -409,16 +437,18 @@ cifs_mkdir(struct inode *inode, struct d rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb); else - rc = cifs_get_inode_info(&newinode, full_path, + rc = cifs_get_inode_info(&newinode, full_path,NULL, inode->i_sb); direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); - direntry->d_inode->i_nlink = 2; + if(direntry->d_inode) + direntry->d_inode->i_nlink = 2; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, + (__u64)-1, + (__u64)-1, + 0 /* dev_t */, cifs_sb->local_nls); else { /* BB to be implemented via Windows secrty descriptors*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ @@ -552,7 +582,7 @@ cifs_revalidate(struct dentry *direntry) cifs_get_inode_info_unix(&direntry->d_inode, full_path, direntry->d_sb); else - cifs_get_inode_info(&direntry->d_inode, full_path, + cifs_get_inode_info(&direntry->d_inode, full_path, NULL, direntry->d_sb); /* BB if not oplocked, invalidate inode pages if mtime has changed */ @@ -657,9 +687,9 @@ cifs_setattr(struct dentry *direntry, st struct cifsFileInfo *open_file = NULL; FILE_BASIC_INFO time_buf; int set_time = FALSE; - __u64 mode = 0xFFFFFFFFFFFFFFFF; - __u64 uid = 0xFFFFFFFFFFFFFFFF; - __u64 gid = 0xFFFFFFFFFFFFFFFF; + __u64 mode = 0xFFFFFFFFFFFFFFFFULL; + __u64 uid = 0xFFFFFFFFFFFFFFFFULL; + __u64 gid = 0xFFFFFFFFFFFFFFFFULL; struct cifsInodeInfo *cifsInode; xid = GetXid(); @@ -722,7 +752,7 @@ cifs_setattr(struct dentry *direntry, st if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, - cifs_sb->local_nls); + 0 /* dev_t */, cifs_sb->local_nls); else if (attrs->ia_valid & ATTR_MODE) { if((mode & S_IWUGO) == 0) /* not writeable */ { if((cifsInode->cifsAttrs & ATTR_READONLY) == 0) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/link.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/link.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/link.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/link.c 2003-08-17 21:27:53.000000000 +0200 @@ -113,6 +113,9 @@ cifs_follow_link(struct dentry *direntry /* BB Should we be using page symlink ops here? */ if (rc == 0) { + +/* BB Add special case check for Samba DFS symlinks */ + target_path[PATH_MAX-1] = 0; rc = vfs_follow_link(nd, target_path); } @@ -157,7 +160,7 @@ cifs_symlink(struct inode *inode, struct rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb); else - rc = cifs_get_inode_info(&newinode, full_path, + rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb); if (rc != 0) { @@ -186,7 +189,10 @@ cifs_readlink(struct dentry *direntry, c struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; + char *tmp_path = NULL; char * tmpbuffer; + unsigned char * referrals = NULL; + int num_referrals = 0; int len; __u16 fid; @@ -206,6 +212,7 @@ cifs_readlink(struct dentry *direntry, c FreeXid(xid); return -ENOMEM; } + /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, @@ -214,7 +221,7 @@ cifs_readlink(struct dentry *direntry, c cifs_sb->local_nls); else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, - OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls); + OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); if(!rc) { rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, tmpbuffer, @@ -224,8 +231,36 @@ cifs_readlink(struct dentry *direntry, c if(CIFSSMBClose(xid, pTcon, fid)) { cFYI(1,("Error closing junction point (open for ioctl)")); } + if(rc == -EIO) { + /* Query if DFS Junction */ + tmp_path = + kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, + GFP_KERNEL); + if (tmp_path) { + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, full_path, MAX_PATHCONF); + rc = get_dfs_path(xid, pTcon->ses, tmp_path, + cifs_sb->local_nls, &num_referrals, &referrals); + cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); + if((num_referrals == 0) && (rc == 0)) + rc = -EACCES; + else { + cFYI(1,("num referral: %d",num_referrals)); + if(referrals) { + cFYI(1,("referral string: %s ",referrals)); + strncpy(tmpbuffer, referrals, len-1); + } + } + + kfree(tmp_path); + if(referrals) { + kfree(referrals); + } + } + /* BB add code like else decode referrals then memcpy to + tmpbuffer and free referrals string array BB */ + } } - } /* BB Anything else to do to handle recursive links? */ /* BB Should we be using page ops here? */ @@ -238,10 +273,12 @@ cifs_readlink(struct dentry *direntry, c rc)); } - if (tmpbuffer) + if (tmpbuffer) { kfree(tmpbuffer); - if (full_path) + } + if (full_path) { kfree(full_path); + } FreeXid(xid); return rc; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/misc.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/misc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/misc.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/misc.c 2003-08-17 21:27:53.000000000 +0200 @@ -190,6 +190,8 @@ header_assemble(struct smb_hdr *buffer, { int i; __u32 tmp; + struct list_head* temp_item; + struct cifsSesInfo * ses; char *temp = (char *) buffer; for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) { @@ -225,7 +227,52 @@ header_assemble(struct smb_hdr *buffer, if (treeCon->ses->capabilities & CAP_STATUS32) { buffer->Flags2 |= SMBFLG2_ERR_STATUS; } + buffer->Uid = treeCon->ses->Suid; /* always in LE format */ + if(multiuser_mount != 0) { + /* For the multiuser case, there are few obvious technically */ + /* possible mechanisms to match the local linux user (uid) */ + /* to a valid remote smb user (smb_uid): */ + /* 1) Query Winbind (or other local pam/nss daemon */ + /* for userid/password/logon_domain or credential */ + /* 2) Query Winbind for uid to sid to username mapping */ + /* and see if we have a matching password for existing*/ + /* session for that user perhas getting password by */ + /* adding a new pam_cifs module that stores passwords */ + /* so that the cifs vfs can get at that for all logged*/ + /* on users */ + /* 3) (Which is the mechanism we have chosen) */ + /* Search through sessions to the same server for a */ + /* a match on the uid that was passed in on mount */ + /* with the current processes uid (or euid?) and use */ + /* that smb uid. If no existing smb session for */ + /* that uid found, use the default smb session ie */ + /* the smb session for the volume mounted which is */ + /* the same as would be used if the multiuser mount */ + /* flag were disabled. */ + + /* BB Add support for establishing new tCon and SMB Session */ + /* with userid/password pairs found on the smb session */ + /* for other target tcp/ip addresses BB */ + if(current->uid != treeCon->ses->linux_uid) { + cFYI(1,("Multiuser mode and UID did not match tcon uid ")); + read_lock(&GlobalSMBSeslock); + list_for_each(temp_item, &GlobalSMBSessionList) { + ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); + if(ses->linux_uid == current->uid) { + if(ses->server == treeCon->ses->server) { + cFYI(1,("found matching uid substitute right smb_uid")); + buffer->Uid = ses->Suid; + break; + } else { + /* BB eventually call setup_session here */ + cFYI(1,("local UID found but smb sess with this server does not exist")); + } + } + } + read_unlock(&GlobalSMBSeslock); + } + } } if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) buffer->Flags2 |= SMBFLG2_DFS; @@ -274,12 +321,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, cFYI(0, ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, ntohl(smb->smb_buf_length))); - if ((length < 2 + sizeof (struct smb_hdr)) + if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || (4 + ntohl(smb->smb_buf_length) > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)) { - if (length < 2 + sizeof (struct smb_hdr)) { + if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); - if ((length >= sizeof (struct smb_hdr) - 1) + if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) && (smb->Status.CifsError != 0)) return 0; /* some error cases do not return wct and bcc */ @@ -298,7 +345,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, return 1; if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) - || (4 + ntohl(smb->smb_buf_length) != length)) { + || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { return 0; } else { cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); @@ -338,23 +385,18 @@ is_valid_oplock_break(struct smb_hdr *bu netfile = list_entry(tmp1,struct cifsFileInfo,tlist); if(pSMB->Fid == netfile->netfid) { struct cifsInodeInfo *pCifsInode; - /* BB Add following logic: - 2) look up inode from tcon->openFileList->file->f_dentry->d_inode - 3) flush dirty pages and cached byte range locks and mark inode - 4) depending on break type change to r/o caching or no caching - cifsinode->clientCanCacheAll = 0 - 5) inode->i_data.a_ops = &cifs_addr_ops_writethrough; - 6) send oplock break response to server */ + /* BB Add following logic to mark inode for write through + inode->i_data.a_ops = &cifs_addr_ops_writethrough; */ read_unlock(&GlobalSMBSeslock); cFYI(1,("Matching file id, processing oplock break")); pCifsInode = - CIFS_I(netfile->pfile->f_dentry->d_inode); + CIFS_I(netfile->pInode); pCifsInode->clientCanCacheAll = FALSE; if(pSMB->OplockLevel == 0) pCifsInode->clientCanCacheRead = FALSE; pCifsInode->oplockPending = TRUE; - AllocOplockQEntry(netfile->pfile, tcon); - cFYI(1,("about to wake up oplock thd")); + AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); + cFYI(1,("about to wake up oplock thd")); wake_up_process(oplockThread); return TRUE; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/netmisc.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/netmisc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/netmisc.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/netmisc.c 2003-08-17 21:27:53.000000000 +0200 @@ -46,7 +46,7 @@ struct smb_to_posix_error { const struct smb_to_posix_error mapping_table_ERRDOS[] = { {ERRbadfunc, -EINVAL}, {ERRbadfile, -ENOENT}, - {ERRbadpath, -ENOENT}, + {ERRbadpath, -ENOTDIR}, {ERRnofids, -EMFILE}, {ERRnoaccess, -EACCES}, {ERRbadfid, -EBADF}, @@ -63,26 +63,29 @@ const struct smb_to_posix_error mapping_ {ERRnofiles, -ENOENT}, {ERRbadshare, -ETXTBSY}, {ERRlock, -EACCES}, - {ERRfilexists, -EINVAL}, + {ERRunsup, -EINVAL}, + {ERRnosuchshare,-ENXIO}, + {ERRfilexists, -EEXIST}, {ERRinvparm, -EINVAL}, {ERRdiskfull, -ENOSPC}, - {ERRinvnum, -EINVAL}, + {ERRinvname, -ENOENT}, {ERRdirnotempty, -ENOTEMPTY}, {ERRnotlocked, -ENOLCK}, {ERRalreadyexists, -EEXIST}, {ERRmoredata, -EOVERFLOW}, {ErrQuota, -EDQUOT}, {ErrNotALink, -ENOLINK}, + {ERRnetlogonNotStarted,-ENOPROTOOPT}, {0, 0} }; const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRerror, -EIO}, - {ERRbadpw, -EACCES}, + {ERRbadpw, -EPERM}, {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, - {ERRinvnetname, -ENOENT}, + {ERRinvnetname, -ENODEV}, {ERRinvdevice, -ENXIO}, {ERRqfull, -ENOSPC}, {ERRqtoobig, -ENOSPC}, @@ -617,7 +620,7 @@ static const struct { ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, { ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { - ERRDOS, 2455, NT_STATUS_NETLOGON_NOT_STARTED}, { + ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { @@ -788,7 +791,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 * e int map_smb_to_linux_error(struct smb_hdr *smb) { - int i; + unsigned int i; int rc = -EIO; /* if transport error smb error may not be set */ __u8 smberrclass; __u16 smberrcode; @@ -856,10 +859,10 @@ map_smb_to_linux_error(struct smb_hdr *s * calculate the size of the SMB message based on the fixed header * portion, the number of word parameters and the data portion of the message */ -int +unsigned int smbCalcSize(struct smb_hdr *ptr) { - return (sizeof (struct smb_hdr) + (int) (2 * ptr->WordCount) + + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + BCC(ptr)); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/ntlmssp.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/ntlmssp.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/ntlmssp.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/ntlmssp.h 2003-08-17 21:27:53.000000000 +0200 @@ -27,26 +27,31 @@ #define NtLmChallenge 2 #define NtLmAuthenticate 3 #define UnknownMessage 8 + /* Negotiate Flags */ #define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode #define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM #define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm #define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability #define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality -#define NTLMSSP_NEGOTIATE_DGRAM 0x0040  +#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal #define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels -#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 +#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 +#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 +#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 +#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 +#define NTLMSSP_REQUEST_INIT_RESP 0x100000 +#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 +#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 #define NTLMSSP_NEGOTIATE_128 0x20000000 #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 -/* server only negotiate flags */ -#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 /* NEGOTIATE_DOMAIN 0x1000 ? */ -#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 /* NEGOTIATE_WORKSTATION 0x2000 ? */ +#define NTLMSSP_NEGOTIATE_56 0x80000000 /* Although typedefs are not commonly used for structure definitions */ /* in the Linux kernel, in this particular case they are useful */ @@ -62,7 +67,7 @@ typedef struct _SECURITY_BUFFER { typedef struct _NEGOTIATE_MESSAGE { __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; - __u32 MessageType; + __u32 MessageType; /* 1 */ __u32 NegotiateFlags; SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ @@ -72,7 +77,7 @@ typedef struct _NEGOTIATE_MESSAGE { typedef struct _CHALLENGE_MESSAGE { __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; - __u32 MessageType; + __u32 MessageType; /* 2 */ SECURITY_BUFFER TargetName; __u32 NegotiateFlags; __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; @@ -82,7 +87,7 @@ typedef struct _CHALLENGE_MESSAGE { typedef struct _AUTHENTICATE_MESSAGE { __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; - __u32 MessageType; + __u32 MessageType; /* 3 */ SECURITY_BUFFER LmChallengeResponse; SECURITY_BUFFER NtChallengeResponse; SECURITY_BUFFER DomainName; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/smbdes.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/smbdes.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/smbdes.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/smbdes.c 2003-08-17 21:27:53.000000000 +0200 @@ -399,7 +399,7 @@ SamOEMhash(unsigned char *data, unsigned s_box[ind] = s_box[j]; s_box[j] = tc; } - for (ind = 0; ind < (val ? 516 : 16); ind++) { + for (ind = 0; ind < val; ind++) { unsigned char tc; unsigned char t; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/smbencrypt.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/smbencrypt.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/smbencrypt.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/smbencrypt.c 2003-08-17 21:27:53.000000000 +0200 @@ -5,7 +5,8 @@ Copyright (C) Andrew Tridgell 1992-2000 Copyright (C) Luke Kenneth Casson Leighton 1996-2000 Modified by Jeremy Allison 1995. - Modified by Steve French (sfrench@us.ibm.com) 2002 + Copyright (C) Andrew Bartlett 2002-2003 + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 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 @@ -97,13 +98,15 @@ SMBencrypt(unsigned char *passwd, unsign E_P16(p14, p21); SMBOWFencrypt(p21, c8, p24); - + #ifdef DEBUG_PASSWORD DEBUG(100, ("SMBencrypt: lm#, challenge, response\n")); dump_data(100, (char *) p21, 16); dump_data(100, (char *) c8, 8); dump_data(100, (char *) p24, 24); #endif + memset(p14,0,15); + memset(p21,0,21); } /* Routines for Windows NT MD4 Hash functions. */ @@ -161,6 +164,7 @@ E_md4hash(const unsigned char *passwd, u len = _my_wcslen(wpwd) * sizeof (__u16); mdfour(p16, (unsigned char *) wpwd, len); + memset(wpwd,0,129 * 2); } /* Does both the NT and LM owfs of a user's password */ @@ -222,7 +226,7 @@ ntv2_owf_gen(const unsigned char owf[16] /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ - /* do not think it is supposed to be uppercased */ + /* BB user and domain may need to be uppercased */ user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); @@ -297,8 +301,52 @@ SMBNTencrypt(unsigned char *passwd, unsi #endif } -int -make_oem_passwd_hash(char data[516], const char *passwd, +/* Does the md5 encryption from the NT hash for NTLMv2. */ +void +SMBOWFencrypt_ntv2(const unsigned char kr[16], + const struct data_blob * srv_chal, + const struct data_blob * cli_chal, unsigned char resp_buf[16]) +{ + struct HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); + hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); + hmac_md5_final(resp_buf, &ctx); + +#ifdef DEBUG_PASSWORD + DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); + dump_data(100, srv_chal->data, srv_chal->length); + dump_data(100, cli_chal->data, cli_chal->length); + dump_data(100, resp_buf, 16); +#endif +} + +static struct data_blob LMv2_generate_response(const unsigned char ntlm_v2_hash[16], + const struct data_blob * server_chal) +{ + unsigned char lmv2_response[16]; + struct data_blob lmv2_client_data/* = data_blob(NULL, 8)*/; /* BB Fix BB */ + struct data_blob final_response /* = data_blob(NULL, 24)*/; /* BB Fix BB */ + + /* LMv2 */ + /* client-supplied random data */ + get_random_bytes(lmv2_client_data.data, lmv2_client_data.length); + /* Given that data, and the challenge from the server, generate a response */ + SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response); + memcpy(final_response.data, lmv2_response, sizeof(lmv2_response)); + + /* after the first 16 bytes is the random data we generated above, + so the server can verify us with it */ + memcpy(final_response.data+sizeof(lmv2_response), + lmv2_client_data.data, lmv2_client_data.length); + +/* data_blob_free(&lmv2_client_data); */ /* BB fix BB */ + + return final_response; +} + +int make_oem_passwd_hash(char data[516], const char *passwd, unsigned char old_pw_hash[16], int unicode) { int new_pw_len = strlen(passwd) * (unicode ? 2 : 1); @@ -333,32 +381,11 @@ make_oem_passwd_hash(char data[516], con DEBUG(100, ("make_oem_passwd_hash\n")); dump_data(100, data, 516); #endif - SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, TRUE); + SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, 516); return TRUE; } -/* Does the md5 encryption from the NT hash for NTLMv2. */ -void -SMBOWFencrypt_ntv2(const unsigned char kr[16], - const struct data_blob srv_chal, - const struct data_blob cli_chal, unsigned char resp_buf[16]) -{ - struct HMACMD5Context ctx; - - hmac_md5_init_limK_to_64(kr, 16, &ctx); - hmac_md5_update(srv_chal.data, srv_chal.length, &ctx); - hmac_md5_update(cli_chal.data, cli_chal.length, &ctx); - hmac_md5_final(resp_buf, &ctx); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); - dump_data(100, srv_chal.data, srv_chal.length); - dump_data(100, cli_chal.data, cli_chal.length); - dump_data(100, resp_buf, 16); -#endif -} - void SMBsesskeygen_ntv2(const unsigned char kr[16], const unsigned char *nt_resp, __u8 sess_key[16]) @@ -407,56 +434,39 @@ encode_pw_buffer(char buffer[516], char return TRUE; } -/*********************************************************** - SMB signing - setup the MAC key. -************************************************************/ - -void -cli_calculate_mac_key(__u8 * mac_key, int *pmac_key_len, - const char *ntpasswd, const unsigned char resp[24]) -{ - /* Get first 16 bytes. */ - E_md4hash(ntpasswd, mac_key); - memcpy(mac_key + 16, resp, 24); - *pmac_key_len = 40; - - /* Reset the sequence number in case we had a previous (aborted) attempt */ -/* cli->sign_info.send_seq_num = 0; */ -} - -/*********************************************************** - SMB signing - calculate a MAC to send. -************************************************************/ - -void -cli_caclulate_sign_mac(struct smb_hdr *outbuf, __u8 * mac_key, - int mac_key_len, __u32 * send_seq_num, - __u32 * reply_seq_num) -{ - unsigned char calc_md5_mac[16]; - struct MD5Context md5_ctx; - -/* if (!cli->sign_info.use_smb_signing) { - return; - } */ - - /* - * Firstly put the sequence number into the first 4 bytes. - * and zero out the next 4 bytes. - */ -/* - SIVAL(outbuf, smb_ss_field, *send_seq_num); - SIVAL(outbuf, smb_ss_field + 4, 0); */ +int SMBNTLMv2encrypt(const char *user, const char *domain, const char *password, + const struct data_blob *server_chal, + const struct data_blob *names_blob, + struct data_blob *lm_response, struct data_blob *nt_response, + struct data_blob *nt_session_key,struct nls_table * nls_codepage) +{ + unsigned char nt_hash[16]; + unsigned char ntlm_v2_hash[16]; + E_md4hash(password, nt_hash); + + /* We don't use the NT# directly. Instead we use it mashed up with + the username and domain. + This prevents username swapping during the auth exchange + */ + ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash,nls_codepage); + + if (nt_response) { +/* *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, + names_blob); */ /* BB fix BB */ + if (nt_session_key) { +/* *nt_session_key = data_blob(NULL, 16); */ /* BB fix BB */ + + /* The NTLMv2 calculations also provide a session key, for signing etc later */ + /* use only the first 16 bytes of nt_response for session key */ + SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data); + } + } + + /* LMv2 */ + + if (lm_response) { + *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal); + } - /* Calculate the 16 byte MAC and place first 8 bytes into the field. */ - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, mac_key, mac_key_len); - MD5Update(&md5_ctx, outbuf->Protocol, - be32_to_cpu(outbuf->smb_buf_length)); - MD5Final(calc_md5_mac, &md5_ctx); - - memcpy(outbuf->SecuritySignature, calc_md5_mac, 8); - (*send_seq_num)++; - *reply_seq_num = *send_seq_num; - (*send_seq_num)++; + return TRUE; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/smberr.h linux-2.4.20-wolk4.7-fullkernel/fs/cifs/smberr.h --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/smberr.h 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/smberr.h 2003-08-17 21:27:53.000000000 +0200 @@ -59,7 +59,7 @@ #define ERRfilexists 80 /* The file named in the request already exists. */ #define ERRinvparm 87 #define ERRdiskfull 112 -#define ERRinvnum 123 +#define ERRinvname 123 #define ERRdirnotempty 145 #define ERRnotlocked 158 #define ERRalreadyexists 183 @@ -109,4 +109,5 @@ class.*/ #define ERRbadclient 2240 #define ERRbadLogonTime 2241 #define ERRpasswordExpired 2242 +#define ERRnetlogonNotStarted 2455 #define ERRnosupport 0xFFFF diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/cifs/transport.c linux-2.4.20-wolk4.7-fullkernel/fs/cifs/transport.c --- linux-2.4.20-wolk4.6-fullkernel/fs/cifs/transport.c 2003-05-03 02:10:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/cifs/transport.c 2003-08-17 21:27:53.000000000 +0200 @@ -45,6 +45,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffe cERROR(1, ("Null session passed in to AllocMidQEntry ")); return NULL; } + if (ses->server == NULL) { + cERROR(1, ("Null TCP session in AllocMidQEntry")); + return NULL; + } + temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, SLAB_KERNEL); if (temp == NULL) @@ -65,7 +70,6 @@ AllocMidQEntry(struct smb_hdr *smb_buffe /* Should we wake up tcp thread first? BB */ timeout = interruptible_sleep_on_timeout(&ses->server->response_q,timeout); - cFYI(1,("timeout (after reconnection wait) %d",timeout)); } if (ses->server->tcpStatus == CifsGood) { @@ -97,10 +101,10 @@ DeleteMidQEntry(struct mid_q_entry *midE } struct oplock_q_entry * -AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon) +AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) { struct oplock_q_entry *temp; - if ((file == NULL) || (tcon == NULL)) { + if ((pinode == NULL) || (tcon == NULL)) { cERROR(1, ("Null parms passed to AllocOplockQEntry")); return NULL; } @@ -109,13 +113,14 @@ AllocOplockQEntry(struct file * file, st if (temp == NULL) return temp; else { - temp->file_to_flush = file; + temp->pinode = pinode; + temp->netfid = fid; temp->tcon = tcon; write_lock(&GlobalMid_Lock); list_add_tail(&temp->qhead, &GlobalOplock_Q); write_unlock(&GlobalMid_Lock); } - return temp; + return temp; } @@ -154,12 +159,8 @@ smb_send(struct socket *ssocket, struct /* smb header is converted in header_assemble. bcc and rest of SMB word area, and byte area if necessary, is converted to littleendian in - cifssmb.c and RFC1001 len is converted to bigendian in smb_send */ - if (smb_buf_length > 12) - smb_buffer->Flags2 = cpu_to_le16(smb_buffer->Flags2); - - /* if(smb_buffer->Flags2 & SMBFLG2_SECURITY_SIGNATURE) - sign_smb(smb_buffer); */ /* BB enable when signing tested more */ + cifssmb.c and RFC1001 len is converted to bigendian in smb_send + Flags2 is converted in SendReceive */ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); cFYI(1, ("Sending smb of length %d ", smb_buf_length)); @@ -186,7 +187,7 @@ SendReceive(const unsigned int xid, stru int *pbytes_returned, const int long_op) { int rc = 0; - int receive_len; + unsigned int receive_len; long timeout; struct mid_q_entry *midQ; @@ -200,14 +201,23 @@ SendReceive(const unsigned int xid, stru DeleteMidQEntry(midQ); return -EIO; } + + if (in_buf->smb_buf_length > 12) + in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); + + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + midQ->midState = MID_REQUEST_SUBMITTED; rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, (struct sockaddr *) &(ses->server->sockAddr)); + if (long_op == -1) + goto cifs_no_response_exit; if (long_op > 1) /* writes past end of file can take looooong time */ timeout = 300 * HZ; else if (long_op == 1) - timeout = 60 * HZ; + timeout = 45 * HZ; /* should be greater than + servers oplock break timeout (about 43 seconds) */ else timeout = 15 * HZ; /* wait for 15 seconds or until woken up due to response arriving or @@ -224,6 +234,7 @@ SendReceive(const unsigned int xid, stru receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); else { + cFYI(1,("No response buffer")); DeleteMidQEntry(midQ); return -EIO; } @@ -245,11 +256,18 @@ SendReceive(const unsigned int xid, stru memcpy(out_buf, midQ->resp_buf, receive_len + 4 /* include 4 byte RFC1001 header */ ); - /* convert the length back to a form that we can use */ dump_smb(out_buf, 92); + /* convert the length into a more usable form */ out_buf->smb_buf_length = be32_to_cpu(out_buf->smb_buf_length); + if((out_buf->smb_buf_length > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ + if(rc) + cFYI(1,("Unexpected signature received from server")); + } + if (out_buf->smb_buf_length > 12) out_buf->Flags2 = le16_to_cpu(out_buf->Flags2); if (out_buf->smb_buf_length > 28) @@ -269,10 +287,12 @@ SendReceive(const unsigned int xid, stru 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC(out_buf)); - } else + } else { rc = -EIO; + cFYI(1,("Bad MID state? ")); + } } - +cifs_no_response_exit: DeleteMidQEntry(midQ); /* BB what if process is killed? - BB add background daemon to clean up Mid entries from killed processes & test killing process with active mid */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/dquot.c linux-2.4.20-wolk4.7-fullkernel/fs/dquot.c --- linux-2.4.20-wolk4.6-fullkernel/fs/dquot.c 2003-08-04 23:06:39.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/dquot.c 2003-08-17 21:31:32.000000000 +0200 @@ -179,7 +179,7 @@ static inline void put_dquot_dup_ref(str static inline int const hashfn(struct super_block *sb, unsigned int id, int type) { - return((HASHDEV(sb->s_dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; + return((((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; } static inline void insert_dquot_hash(struct dquot *dquot) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/exec.c linux-2.4.20-wolk4.7-fullkernel/fs/exec.c --- linux-2.4.20-wolk4.6-fullkernel/fs/exec.c 2003-08-04 23:06:39.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/exec.c 2003-08-17 21:31:36.000000000 +0200 @@ -682,8 +682,6 @@ int flush_old_exec(struct linux_binprm * retval = unshare_files(); if(retval) goto flush_failed; - steal_locks(files, current->files); - put_files_struct(files); /* * Release all of the old mmap stuff @@ -692,6 +690,8 @@ int flush_old_exec(struct linux_binprm * if (retval) goto mmap_failed; /* This is the point of no return */ + steal_locks(files); + put_files_struct(files); release_old_signals(oldsig); current->sas_ss_sp = current->sas_ss_size = 0; @@ -753,6 +753,8 @@ int flush_old_exec(struct linux_binprm * return 0; mmap_failed: + put_files_struct(current->files); + current->files = files; flush_failed: spin_lock_irq(¤t->sigmask_lock); if (current->sig != oldsig) { @@ -1235,6 +1237,43 @@ void set_binfmt(struct linux_binfmt *new __MOD_DEC_USE_COUNT(old->module); } +#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) +void pax_report_fault(struct pt_regs *regs, void *pc, void *sp) +{ + struct task_struct *tsk = current; + struct mm_struct *mm = current->mm; + char* buffer = (char*)__get_free_page(GFP_ATOMIC); + char* path=NULL; + + if (buffer) { + struct vm_area_struct* vma; + + down_read(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { + break; + } + vma = vma->vm_next; + } + if (vma) + path = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt, buffer, PAGE_SIZE); + up_read(&mm->mmap_sem); + } + if (tsk->curr_ip) + printk(KERN_ERR "PAX: From %u.%u.%u.%u: terminating task: %s(%s):%d, uid/euid: %u/%u, " + "PC: %p, SP: %p\n", NIPQUAD(tsk->curr_ip), path, tsk->comm, tsk->pid, + tsk->uid, tsk->euid, pc, sp); + else + printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, " + "PC: %p, SP: %p\n", path, tsk->comm, tsk->pid, + tsk->uid, tsk->euid, pc, sp); + if (buffer) free_page((unsigned long)buffer); + pax_report_insns(pc); + do_coredump(SIGKILL, regs); +} +#endif + #define MAX_CORE_NAME (160) int do_coredump(long signr, struct pt_regs * regs) { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/ext3/inode.c linux-2.4.20-wolk4.7-fullkernel/fs/ext3/inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/ext3/inode.c 2003-05-03 02:36:47.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/ext3/inode.c 2003-08-17 21:31:43.000000000 +0200 @@ -2299,8 +2299,6 @@ void ext3_read_inode(struct inode * inod INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan); INIT_LIST_HEAD(&inode->u.ext3_i.i_dirty); - brelse (iloc.bh); - if (inode->i_ino == EXT3_ACL_IDX_INO || inode->i_ino == EXT3_ACL_DATA_INO) /* Nothing to do */ ; @@ -2321,6 +2319,7 @@ void ext3_read_inode(struct inode * inod } else init_special_inode(inode, inode->i_mode, le32_to_cpu(iloc.raw_inode->i_block[0])); + brelse(iloc.bh); ext3_set_inode_flags(inode); return; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/inode.c linux-2.4.20-wolk4.7-fullkernel/fs/inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/inode.c 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/inode.c 2003-08-17 21:31:13.000000000 +0200 @@ -117,7 +117,6 @@ static struct inode *alloc_inode(struct inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; - mapping->a_ops = &empty_aops; mapping->host = inode; mapping->gfp_mask = GFP_HIGHUSER; @@ -142,9 +141,8 @@ static void destroy_inode(struct inode * * once, because the fields are idempotent across use * of the inode, so let the slab aware of that. */ -void inode_init_once(struct inode *inode) +void _inode_init_once(struct inode *inode) { - memset(inode, 0, sizeof(*inode)); init_waitqueue_head(&inode->i_wait); INIT_LIST_HEAD(&inode->i_hash); INIT_LIST_HEAD(&inode->i_data.clean_pages); @@ -161,6 +159,12 @@ void inode_init_once(struct inode *inode i_size_ordered_init(inode); } +void inode_init_once(struct inode *inode) +{ + memset(inode, 0, sizeof(*inode)); + _inode_init_once(inode); +} + static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) { struct inode * inode = (struct inode *) foo; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/ioctl.c linux-2.4.20-wolk4.7-fullkernel/fs/ioctl.c --- linux-2.4.20-wolk4.6-fullkernel/fs/ioctl.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/ioctl.c 2003-08-17 21:31:04.000000000 +0200 @@ -112,7 +112,6 @@ asmlinkage long sys_ioctl(unsigned int f fioasync_out: up(&inode->i_sem); break; - } case FIOQSIZE: if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || @@ -124,6 +123,8 @@ asmlinkage long sys_ioctl(unsigned int f else error = -ENOTTY; break; + } + default: error = -ENOTTY; if (S_ISREG(filp->f_dentry->d_inode->i_mode)) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/jbd/transaction.c linux-2.4.20-wolk4.7-fullkernel/fs/jbd/transaction.c --- linux-2.4.20-wolk4.6-fullkernel/fs/jbd/transaction.c 2003-05-03 02:35:53.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/jbd/transaction.c 2003-08-17 21:31:44.000000000 +0200 @@ -578,12 +578,18 @@ static int do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) { struct buffer_head *bh; - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; + transaction_t *transaction; + journal_t *journal; int error; char *frozen_buffer = NULL; int need_copy = 0; int locked; + + if (is_handle_aborted(handle)) + return -EROFS; + + transaction = handle->h_transaction; + journal = transaction->t_journal; jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); @@ -1467,6 +1473,7 @@ int journal_stop(handle_t *handle) if (handle->h_sync) { do { old_handle_count = transaction->t_handle_count; + set_current_state(TASK_RUNNING); yield(); } while (old_handle_count != transaction->t_handle_count); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/locks.c linux-2.4.20-wolk4.7-fullkernel/fs/locks.c --- linux-2.4.20-wolk4.6-fullkernel/fs/locks.c 2003-08-04 23:06:39.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/locks.c 2003-08-17 21:31:36.000000000 +0200 @@ -1933,11 +1933,11 @@ done: return length; } -void steal_locks(fl_owner_t from, fl_owner_t to) +void steal_locks(fl_owner_t from) { struct list_head *tmp; - if (from == to) + if (from == current->files) return; lock_kernel(); @@ -1945,7 +1945,7 @@ void steal_locks(fl_owner_t from, fl_own struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); if (fl->fl_owner == from) - fl->fl_owner = to; + fl->fl_owner = current->files; } unlock_kernel(); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/namei.c linux-2.4.20-wolk4.7-fullkernel/fs/namei.c --- linux-2.4.20-wolk4.6-fullkernel/fs/namei.c 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/namei.c 2003-08-17 21:31:24.000000000 +0200 @@ -2274,7 +2274,7 @@ int vfs_unlink(struct inode *dir, struct rsbac_attribute_value)) { printk(KERN_WARNING - "vfs_unlink() [do_unlink() [sys_unlink()]]: rsbac_adf_set_attr() returned error"); + "vfs_unlink() [do_unlink() [sys_unlink()]]: rsbac_adf_set_attr() returned error\n"); } } #endif @@ -2865,12 +2865,12 @@ static inline int do_rename(const char * rsbac_target_id.file.device = old_dentry->d_inode->i_dev; rsbac_target_id.file.inode = old_dentry->d_inode->i_ino; rsbac_target_id.file.dentry_p = old_dentry; - rsbac_attribute_value.dummy = 0; + rsbac_attribute_value.new_dir_dentry_p = new_dir; if (!rsbac_adf_request(R_RENAME, current->pid, rsbac_target, rsbac_target_id, - A_none, + A_new_dir_dentry_p, rsbac_attribute_value)) { error = -EPERM; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nls/Config.in linux-2.4.20-wolk4.7-fullkernel/fs/nls/Config.in --- linux-2.4.20-wolk4.6-fullkernel/fs/nls/Config.in 2003-05-09 01:38:27.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nls/Config.in 2003-08-17 21:31:01.000000000 +0200 @@ -11,7 +11,7 @@ fi # msdos and Joliet want NLS if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \ - -o "$CONFIG_CIFS" != "n" \ + -o "$CONFIG_CIFS" != "n" \ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \ -o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \ -o "$CONFIG_BEFS_FS" != "n" -o "$CONFIG_HFSPLUS_FS" != "n" ]; then diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/Makefile linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/Makefile --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/Makefile 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,21 @@ +# +# Makefile for the Linux nwfs filesystem 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 (not a .c file). +# + +O_TARGET := nwfs.o + +obj-y := nwvfs.o alloc.o disk.o nwpart.o volume.o globals.o lru.o \ + hash.o async.o fat.o bit.o block.o cluster.o dir.o \ + mmap.o inode.o super.o file.o ioctl.o nwdir.o nwfile.o nwfix.o \ + trustee.o nwext.o suballoc.o create.o date.o \ + nwcreate.o symlink.o nwvp.o nwvphal.o + +obj-m := $(O_TARGET) + +EXTRA_CFLAGS += -DOVERRIDE=1 -DLINUX_DRIVER=1 -DNATIVE_MODULE=1 + +include $(TOPDIR)/Rules.make diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/alloc.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/alloc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/alloc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/alloc.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,391 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : ALLOC.C +* DESCRIP : NWFS Operating System Abstraction Layer +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +// we track our memory to check for leaks at unload. + +#define ALLOC_LIMIT -1 + +typedef struct _MEM_HEADER +{ + struct _MEM_HEADER *next; + struct _MEM_HEADER *prior; + ULONG Size; + TRACKING *Type; + ULONG Pool; + void *context; +} MEM_HEADER; + +MEM_HEADER *MemoryListHead = 0; +MEM_HEADER *MemoryListTail = 0; + +ULONG AddToMemoryList(MEM_HEADER *mem); +ULONG RemoveFromMemoryList(MEM_HEADER *mem); + +extern TRACKING *tracked_memory[]; +extern ULONG tracked_memory_count; + +void displayMemoryInfo(void) +{ + register ULONG i, count; + + NWFSPrint("NWFS Memory Usage\n"); + NWFSPrint("total_memory_in_use : %d bytes\n", (int)(MemoryInUse + + PagedMemoryInUse)); + NWFSPrint("atomic_memory_in_use : %d bytes\n", (int)MemoryInUse); + NWFSPrint("paged_memory_in_use : %d bytes\n", (int)PagedMemoryInUse); + NWFSPrint("atomic_memory_allocated : %d bytes\n", (int)MemoryAllocated); + NWFSPrint("atomic_memory_freed : %d bytes\n", (int)MemoryFreed); + NWFSPrint("paged_memory_allocated : %d bytes\n", (int)PagedMemoryAllocated); + NWFSPrint("paged_memory_freed : %d bytes\n", (int)PagedMemoryFreed); + + for (count=i=0; i < tracked_memory_count; i++) + { + if ((tracked_memory[i]) && + (tracked_memory[i]->count || tracked_memory[i]->units)) + { + NWFSPrint("%s count-%-10d units-%-10d ", + tracked_memory[i]->label, (int)tracked_memory[i]->count, + (int)tracked_memory[i]->units); + if (count++ & 1) + NWFSPrint("\n"); + } + } + NWFSPrint("\n"); + +} + + +#define toupper(c) (((c) >= 'a' && (c) <= 'z') ? (c) + ('A'-'a') : (c)) +#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c)) + +ULONG AllocateSemaphore(void *sema, ULONG value) +{ + sema_init(sema, value); + return 0; +} + +long WaitOnSemaphore(void *sema) +{ +#if (DEBUG_DEADLOCKS) + register ULONG ccode; + + ccode = down_interruptible(sema); + if (ccode == -EINTR) + return ccode; + return 0; +#else + down(sema); + return 0; +#endif +} + +long SignalSemaphore(void *sema) +{ + up(sema); + return 0; +} + +void *NWFSAlloc(ULONG size, TRACKING *Tag) +{ + register MEM_HEADER *mem; + register BYTE *p; + + mem = kmalloc((size + sizeof(MEM_HEADER)), GFP_KERNEL); + if (!mem) + return 0; + + p = (BYTE *)((ULONG)mem + sizeof(MEM_HEADER)); + mem->Size = size; + mem->Type = Tag; + mem->next = 0; + mem->prior = 0; + mem->Pool = 1; + mem->context = 0; + + MemoryAllocated += size; + MemoryInUse += size; + + Tag->count += size; + Tag->units++; + + AddToMemoryList(mem); + + return (void *) p; + +} + +void *NWFSIOAlloc(ULONG size, TRACKING *Tag) +{ + register MEM_HEADER *mem; + register BYTE *p; + + mem = kmalloc((size + sizeof(MEM_HEADER)), GFP_KERNEL); + if (!mem) + return 0; + + p = (BYTE *)((ULONG)mem + sizeof(MEM_HEADER)); + mem->Size = size; + mem->Type = Tag; + mem->next = 0; + mem->prior = 0; + mem->Pool = 3; + mem->context = 0; + + MemoryAllocated += size; + MemoryInUse += size; + + Tag->count += size; + Tag->units++; + + AddToMemoryList(mem); + + return (void *) p; + +} + +void *NWFSCacheAlloc(ULONG size, TRACKING *Tag) +{ + register ULONG nSize; + register MEM_HEADER *mem; + register BYTE *p; + + nSize = (((size + sizeof(MEM_HEADER)) + 4095) / 4096) * 4096; + mem = vmalloc(nSize); + if (!mem) + return 0; + + p = (BYTE *)((ULONG)mem + sizeof(MEM_HEADER)); + mem->Size = size; + mem->Type = Tag; + mem->next = 0; + mem->prior = 0; + mem->Pool = 2; + mem->context = 0; + + PagedMemoryAllocated += size; + PagedMemoryInUse += size; + + Tag->count += size; + Tag->units++; + + AddToMemoryList(mem); + + return (void *) p; +} + +void NWFSFree(void *p) +{ + register MEM_HEADER *mem, *mem1; + + mem1 = p; + mem = &mem1[-1]; + + mem->Type->count -= mem->Size; + mem->Type->units--; + + switch (mem->Pool) + { + case 1: + MemoryFreed += mem->Size; + if (MemoryInUse) + MemoryInUse -= mem->Size; + RemoveFromMemoryList(mem); + kfree((void *)mem); + break; + + case 2: + PagedMemoryFreed += mem->Size; + if (PagedMemoryInUse) + PagedMemoryInUse -= mem->Size; + RemoveFromMemoryList(mem); + vfree((void *)mem); + break; + + case 3: + MemoryFreed += mem->Size; + if (MemoryInUse) + MemoryInUse -= mem->Size; + RemoveFromMemoryList(mem); + kfree((void *)mem); + break; + + default: + NWFSPrint("nwfs: NWFSFree reports free on invalid memory\n"); + break; + } +} + +int NWFSCompare(void *dest, void *src, ULONG size) +{ + return (memcmp(dest, src, size)); +} + +void NWFSSet(void *dest, ULONG value, ULONG size) +{ + memset(dest, value, size); +} + +void NWFSCopy(void *dest, void *src, ULONG size) +{ + memmove(dest, src, size); +} + +ULONG NWFSCopyFromUserSpace(void *dest, void *src, ULONG size) +{ + return (copy_from_user(dest, src, size)); +} + +ULONG NWFSCopyToUserSpace(void *dest, void *src, ULONG size) +{ + return (copy_to_user(dest, src, size)); +} + +ULONG NWFSSetUserSpace(void *dest, ULONG value, ULONG size) +{ + if (size > 65536) + return NwMemoryFault; + + if (ZeroBuffer) + return (copy_to_user(dest, ZeroBuffer, size)); + return NwMemoryFault; +} + +BYTE NWFSUpperCase(BYTE c) +{ + return (toupper(c)); +} + +BYTE NWFSLowerCase(BYTE c) +{ + return (tolower(c)); +} + +void NWFSClean(void *p) +{ + kfree((void *)p); +} + +void displayMemoryList(void) +{ + BYTE *p; + MEM_HEADER *mem, *temp; + extern BYTE *dumpRecord(BYTE *, ULONG); + extern BYTE *dumpRecordBytes(BYTE *, ULONG); + + mem = MemoryListHead; + while (mem) + { + p = (BYTE *) &mem->Type; +#if (DUMP_LEAKED_MEMORY) + NWFSPrint("addr-%08X type-[%s] size-%d\n", + (unsigned)((ULONG)mem + sizeof(MEM_HEADER)), + (char *)mem->Type->label ? (char *)mem->Type->label : "NONE", + (int)mem->Size); + + NWFSPrint("address-0x%08X (DWORD dump)\n", + (unsigned)((ULONG)mem + sizeof(MEM_HEADER))); + dumpRecord((BYTE *)((ULONG)mem + sizeof(MEM_HEADER)), 64); + NWFSPrint("address-0x%08X (BYTE dump)\n", + (unsigned)((ULONG)mem + sizeof(MEM_HEADER))); + dumpRecordBytes((BYTE *)((ULONG)mem + sizeof(MEM_HEADER)), 64); +#endif + + temp = mem; + mem = mem->next; + NWFSClean(temp); // free the tracked memory + } + return; +} + +ULONG AddToMemoryList(MEM_HEADER *mem) +{ + if (!MemoryListHead) + { + MemoryListHead = mem; + MemoryListTail = mem; + mem->next = mem->prior = 0; + } + else + { + MemoryListTail->next = mem; + mem->next = 0; + mem->prior = MemoryListTail; + MemoryListTail = mem; + } + return 0; +} + +ULONG RemoveFromMemoryList(MEM_HEADER *mem) +{ + if (MemoryListHead == mem) + { + MemoryListHead = mem->next; + if (MemoryListHead) + MemoryListHead->prior = NULL; + else + MemoryListTail = NULL; + } + else + { + mem->prior->next = mem->next; + if (mem != MemoryListTail) + mem->next->prior = mem->prior; + else + MemoryListTail = mem->prior; + } + return 0; +} + + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/async.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/async.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/async.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/async.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,1065 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : ASYNC.C +* DESCRIP : NWFS Asynch IO Library +* DATE : July 13, 2000 (my birthday) +* +* +***************************************************************************/ + +#include "globals.h" + +// We use eight (8) processes for the async io manager. Each disk bin +// is computed as disk % 8 and matched into one of eight bin groups. +// On SMP versions of linux, this should allow us to keep as many +// drive spindles active as possible at one time without eating too +// many server processes to do this, provided the linux kernel +// load balances these processes across processors. + +ASYNCH_IO *disk_io_head[8] = { 0, 0, 0, 0, 0, 0, 0 }; +ASYNCH_IO *disk_io_tail[8] = { 0, 0, 0, 0, 0, 0, 0 }; +ASYNCH_IO_HEAD asynch_io_head[MAX_DISKS]; + +ULONG aio_submitted = 0; +ULONG aio_completed = 0; +ULONG aio_error = 0; +ULONG disk_aio_submitted = 0; +ULONG disk_aio_completed = 0; +ULONG sync_active[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +ULONG async_active[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +ULONG cb_active = 0; +ULONG aio_sequence = 0; + +#if (PROFILE_AIO) +ULONG hash_hits = 0; +ULONG hash_misses = 0; +ULONG hash_fill = 0; +ULONG hash_total = 0; +double probe_avg = 0; +ULONG probe_max = 0; + +ULONG total_read_req = 0; +ULONG total_write_req = 0; +ULONG total_fill_req = 0; +ULONG total_complete = 0; +ULONG req_sec = 0; +ULONG seconds = 0; +#endif + +#if (LINUX_SLEEP) + +NWFSInitMutex(disk_io_sem0); +NWFSInitMutex(disk_io_sem1); +NWFSInitMutex(disk_io_sem2); +NWFSInitMutex(disk_io_sem3); +NWFSInitMutex(disk_io_sem4); +NWFSInitMutex(disk_io_sem5); +NWFSInitMutex(disk_io_sem6); +NWFSInitMutex(disk_io_sem7); + +#if (LINUX_SPIN) +spinlock_t aio_spinlock = SPIN_LOCK_UNLOCKED; +long aio_flags = 0; +#else +NWFSInitMutex(asynch_head_lock); +#endif + +struct semaphore *io_sem_table[8]={ + &disk_io_sem0, &disk_io_sem1, &disk_io_sem2, &disk_io_sem3, + &disk_io_sem4, &disk_io_sem5, &disk_io_sem6, &disk_io_sem7 +}; + +#endif + +extern void RunAsynchIOQueue(ULONG disk); + +#if (PROFILE_AIO) +void profile_complete(void) +{ + total_complete++; +} +#endif + +void asynch_lock(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&aio_spinlock, aio_flags); +#else + if (WaitOnSemaphore(&asynch_head_lock) == -EINTR) + NWFSPrint("asynch lock was interrupted\n"); +#endif +#endif +} + +void asynch_unlock(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&aio_spinlock, aio_flags); +#else + SignalSemaphore(&asynch_head_lock); +#endif +#endif +} + +ULONG hash_disk_io(ASYNCH_IO *io) +{ + register int i = (io->disk % MAX_DISKS); + register int j = ((io->sector_offset >> 8) & 0xF); + ASYNCH_IO *old, *p; + + if (!asynch_io_head[i].hash_head[j]) + { + io->hnext = io->hprior = NULL; + asynch_io_head[i].hash_head[j] = io; + asynch_io_head[i].hash_tail[j] = io; + return 0; + } + + p = asynch_io_head[i].hash_head[j]; + old = NULL; + while (p) + { + if (p->disk != io->disk) + { + NWFSPrint("nwfs: io request has bad disk id (%d/%d)\n", + (int)p->disk, (int)io->disk); + return -1; + } + + if (p->sector_offset < io->sector_offset) + { + old = p; + p = p->hnext; + } + else + { + if (p->hprior) + { + p->hprior->hnext = io; + io->hnext = p; + io->hprior = p->hprior; + p->hprior = io; + return 0; + } + io->hnext = p; + io->hprior = NULL; + p->hprior = io; + asynch_io_head[i].hash_head[j] = io; + return 0; + } + } + old->hnext = io; + io->hnext = NULL; + io->hprior = old; + asynch_io_head[i].hash_tail[j] = io; + return 0; +} + +ULONG unhash_disk_io(ASYNCH_IO *io) +{ + register int i = (io->disk % MAX_DISKS); + register int j = ((io->sector_offset >> 8) & 0xF); + + if (asynch_io_head[i].hash_head[j] == io) + { + asynch_io_head[i].hash_head[j] = (void *) io->hnext; + if (asynch_io_head[i].hash_head[j]) + asynch_io_head[i].hash_head[j]->hprior = NULL; + else + asynch_io_head[i].hash_tail[j] = NULL; + } + else + { + io->hprior->hnext = io->hnext; + if (io != asynch_io_head[i].hash_tail[j]) + io->hnext->hprior = io->hprior; + else + asynch_io_head[i].hash_tail[j] = io->hprior; + } + io->hnext = io->hprior = 0; + + return 0; +} + +void process_sync_io(ULONG disk) +{ + register int i = (disk % 8); + register int r, j; + ASYNCH_IO *list, *io; + + sync_active[i]++; + + while (disk_io_head[i]) + { + asynch_lock(); + list = disk_io_head[i]; + disk_io_head[i] = disk_io_tail[i] = 0; + for (r=0; r < MAX_DISKS; r++) + { + if ((r % 8) == i) + { + for (j=0; j < 16; j++) + { + asynch_io_head[r].hash_head[j] = 0; + asynch_io_head[r].hash_tail[j] = 0; + } + } + } + asynch_unlock(); + + while (list) + { + io = list; + list = list->next; + io->next = io->prior = 0; + + if (io->signature != ASIO_SUBMIT_IO) + { + NWFSPrint("sync - bad io (0x%08X) request cmd-%X s-%X\n", + (unsigned)io, (unsigned)io->command, + (unsigned)io->signature); + io->ccode = ASIO_BAD_SIGNATURE; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + aio_error++; + aio_completed++; + continue; + } + + switch (io->command) + { + case ASYNCH_TEST: + disk_aio_submitted++; + io->ccode = 0; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_READ: + disk_aio_submitted++; + io->return_code = pReadDiskSectors(io->disk, + io->sector_offset, + io->buffer, + io->sector_count, + io->sector_count); + io->ccode = 0; + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + } + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_WRITE: + disk_aio_submitted++; + io->return_code = pWriteDiskSectors(io->disk, + io->sector_offset, + io->buffer, + io->sector_count, + io->sector_count); + io->ccode = 0; + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + } + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_FILL: + disk_aio_submitted++; + io->return_code = pZeroFillDiskSectors(io->disk, + io->sector_offset, + io->sector_count, + io->sector_count); + io->ccode = 0; + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + } + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + default: + io->ccode = ASIO_BAD_COMMAND; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + aio_error++; + aio_completed++; + break; + } + } + } + + sync_active[i]--; + return; +} + +#if (!LINUX_20 && LINUX_AIO && !LINUX_UTIL && !LINUX_BUFFER_CACHE) + +void process_asynch_io(ULONG disk) +{ + register int i = (disk % 8); + register int r, j; + ASYNCH_IO *list, *io; + + // continue to cycle through this list until we have completely + // emptied the list. + + async_active[i]++; + + while (disk_io_head[i]) + { + // take the entire list, zero the head and tail and process the list + // from this context. this will simulate an alternating A and B list + // and avoid elevator starvation. We also need to clear all the + // asynch hash list info for this run so folks don't attempt to + // link new aio requests to this active aio chain. + + asynch_lock(); + list = disk_io_head[i]; + disk_io_head[i] = disk_io_tail[i] = 0; + for (r=0; r < MAX_DISKS; r++) + { + if ((r % 8) == i) + { + for (j=0; j < 16; j++) + { + asynch_io_head[r].hash_head[j] = 0; + asynch_io_head[r].hash_tail[j] = 0; + } + } + } + asynch_unlock(); + + while (list) + { + io = list; + list = list->next; + io->next = io->prior = 0; + + if (io->signature != ASIO_SUBMIT_IO) + { + NWFSPrint("\naio process - bad io (0x%08X) cmd-%X sig-%X cb-%X d/s-%d/%X\n", + (unsigned)io, + (unsigned)io->command, + (unsigned)io->signature, + (unsigned)io->call_back_routine, + (int)io->disk, + (unsigned)io->sector_offset); + +// io->ccode = ASIO_BAD_SIGNATURE; +// if (io->call_back_routine) +// (io->call_back_routine)(io); +// io->signature = ASIO_COMPLETED; +// aio_error++; +// aio_completed++; +// continue; + } + + switch (io->command) + { + case ASYNCH_TEST: + disk_aio_submitted++; + io->ccode = 0; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_READ: +#if (PROFILE_AIO) + total_read_req++; +#endif + disk_aio_submitted++; + io->return_code = aReadDiskSectors(io->disk, + io->sector_offset, + io->buffer, + io->sector_count, + io->sector_count, + io); + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + } + io->signature = ASIO_AIO_POST; + break; + + case ASYNCH_WRITE: +#if (PROFILE_AIO) + total_write_req++; +#endif + disk_aio_submitted++; + io->return_code = aWriteDiskSectors(io->disk, + io->sector_offset, + io->buffer, + io->sector_count, + io->sector_count, + io); + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + } + io->signature = ASIO_AIO_POST; + break; + + case ASYNCH_FILL: +#if (PROFILE_AIO) + total_fill_req++; +#endif + disk_aio_submitted++; + io->return_code = aZeroFillDiskSectors(io->disk, + io->sector_offset, + io->sector_count, + io->sector_count, + io); + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + } + io->signature = ASIO_AIO_POST; + break; + + default: + io->ccode = ASIO_BAD_COMMAND; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + aio_error++; + aio_completed++; + break; + } + } +#if (!POST_IMMEDIATE) +#if (LINUX_22) + lock_kernel(); +#endif + run_task_queue(&tq_disk); +#if (LINUX_22) + unlock_kernel(); +#endif +#endif + } + + async_active[i]--; + return; +} + +#else + +void process_asynch_io(ULONG disk) +{ + register int i = (disk % 8); + register int r, j; + ASYNCH_IO *list, *io; + + // continue to cycle through this list until we have completely + // emptied the list. + + async_active[i]++; + + while (disk_io_head[i]) + { + // take the entire list, zero the head and tail and process the list + // from this context. this will simulate an alternating A and B list + // and avoid elevator starvation. We also need to clear all the + // asynch hash list info for this run so folks don't attempt to + // link new aio requests to this active aio chain. + + asynch_lock(); + list = disk_io_head[i]; + disk_io_head[i] = disk_io_tail[i] = 0; + for (r=0; r < MAX_DISKS; r++) + { + if ((r % 8) == i) + { + for (j=0; j < 16; j++) + { + asynch_io_head[r].hash_head[j] = 0; + asynch_io_head[r].hash_tail[j] = 0; + } + } + } + +#if (PROFILE_AIO) + if (hash_hits || hash_misses) + { + if (hash_total) + probe_avg = (double)((double)probe_avg / (double)hash_total); + else + probe_avg = 0; + + // we seem to average 96% hit efficiency for locating an insertion + // point in the aio list with an average of 1 probe per insert. The + // other 4% involve cases where a single element is on the list, + // and we only probe 1 time to find our insert point. + +#if (VERBOSE) + NWFSPrint("rd_aio-%d wr_aio-%d f_aio-%d compl-%d req/sec-%d\n", + (int)total_read_req, (int)total_write_req, + (int)total_fill_req, (int)total_complete, + (int)(seconds ? (total_complete / seconds) : total_complete)); + + NWFSPrint("hits-%d misses-%d fill-%d total-%d probe_avg-%d probe_max-%d\n", + (int)hash_hits, (int)hash_misses, (int)hash_fill, + (int)hash_total, (int)probe_avg, (int)probe_max); +#endif + + } + total_read_req = total_write_req = total_fill_req = total_complete = 0; + req_sec = seconds = 0; + hash_hits = hash_misses = hash_fill = hash_total = probe_avg = probe_max = 0; +#endif + asynch_unlock(); + + while (list) + { + io = list; + list = list->next; + io->next = io->prior = 0; + + if (io->signature != ASIO_SUBMIT_IO) + { + NWFSPrint("\nnwfs aio - bad io (0x%08X) cmd-%X s-%X cb-%X \nd/s-%d/%X\n", + (unsigned)io, + (unsigned)io->command, + (unsigned)io->signature, + (unsigned)io->call_back_routine, + (int)io->disk, + (unsigned)io->sector_offset); + +// io->ccode = ASIO_BAD_SIGNATURE; +// if (io->call_back_routine) +// (io->call_back_routine)(io); +// io->signature = ASIO_COMPLETED; +// aio_error++; +// aio_completed++; +// continue; + } + + switch (io->command) + { + case ASYNCH_TEST: + disk_aio_submitted++; + io->ccode = 0; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_READ: +#if (PROFILE_AIO) + total_read_req++; +#endif + disk_aio_submitted++; + io->return_code = pReadDiskSectors(io->disk, + io->sector_offset, + io->buffer, + io->sector_count, + io->sector_count); + io->ccode = 0; + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + } + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_WRITE: +#if (PROFILE_AIO) + total_write_req++; +#endif + disk_aio_submitted++; + io->return_code = pWriteDiskSectors(io->disk, + io->sector_offset, + io->buffer, + io->sector_count, + io->sector_count); + io->ccode = 0; + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + } + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + case ASYNCH_FILL: +#if (PROFILE_AIO) + total_fill_req++; +#endif + disk_aio_submitted++; + io->return_code = pZeroFillDiskSectors(io->disk, + io->sector_offset, + io->sector_count, + io->sector_count); + io->ccode = 0; + if (!io->return_code) + { + io->ccode = ASIO_IO_ERROR; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + } + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + disk_aio_completed++; + aio_completed++; + break; + + default: + io->ccode = ASIO_BAD_COMMAND; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + aio_error++; + aio_completed++; + break; + } + } + } + + async_active[i]--; + return; +} + +#endif + +ULONG asynch_io_pending(ULONG disk) +{ + return ((disk_io_head[(disk % 8)]) ? 1 : 0); +} + +ASYNCH_IO *remove_io(ULONG disk, ASYNCH_IO *io) +{ + register int i = (disk % 8); + + if (disk_io_head[i] == io) + { + disk_io_head[i] = (void *) io->next; + if (disk_io_head[i]) + disk_io_head[i]->prior = NULL; + else + disk_io_tail[i] = NULL; + } + else + { + io->prior->next = io->next; + if (io != disk_io_tail[i]) + io->next->prior = io->prior; + else + disk_io_tail[i] = io->prior; + } + io->next = io->prior = 0; + + return io; + +} + +ULONG index_io(ULONG disk, ASYNCH_IO *io) +{ + register int i = (disk % 8); + register int r = (io->disk % MAX_DISKS); + register int j = ((io->sector_offset >> 8) & 0xF); +#if (PROFILE_AIO) + register int count; +#endif + ASYNCH_IO *old, *p; + +#if (PROFILE_AIO) + count = 1; +#endif + if (!disk_io_tail[i]) + { + io->next = io->prior = NULL; + disk_io_head[i] = io; + disk_io_tail[i] = io; +#if (PROFILE_AIO) + hash_fill++; + hash_total++; + + if (count > probe_max) + probe_max = count; + probe_avg += count; +#endif + return 0; + } + + if (asynch_io_head[r].hash_head[j]) + { +#if (PROFILE_AIO) + hash_hits++; +#endif + p = asynch_io_head[r].hash_head[j]; + } + else + { +#if (PROFILE_AIO) + hash_misses++; +#endif + p = disk_io_head[i]; + } +#if (PROFILE_AIO) + hash_total++; +#endif + + old = NULL; + while (p) + { + if ((p->disk < io->disk) || + (p->sector_offset < io->sector_offset)) + { + old = p; + p = p->next; +#if (PROFILE_AIO) + count++; +#endif + } + else + { + if (p->prior) + { + p->prior->next = io; + io->next = p; + io->prior = p->prior; + p->prior = io; + +#if (PROFILE_AIO) + if (count > probe_max) + probe_max = count; + probe_avg += count; +#endif + return 0; + } + io->next = p; + io->prior = NULL; + p->prior = io; + disk_io_head[i] = io; + +#if (PROFILE_AIO) + if (count > probe_max) + probe_max = count; + probe_avg += count; +#endif + return 0; + } + } + old->next = io; + io->next = NULL; + io->prior = old; + disk_io_tail[i] = io; + +#if (PROFILE_AIO) + if (count > probe_max) + probe_max = count; + probe_avg += count; +#endif + return 0; +} + +void insert_io(ULONG disk, ASYNCH_IO *io) +{ + asynch_lock(); + if (io->signature == ASIO_SUBMIT_IO) + { + NWFSPrint("nwfs: asynch io request already active\n"); + asynch_unlock(); + return; + } + io->signature = ASIO_SUBMIT_IO; + + index_io(disk, io); + hash_disk_io(io); + + aio_submitted++; + + if (io->signature != ASIO_SUBMIT_IO) + NWFSPrint("nwfs: insert_io request not active (%X)\n", + (unsigned)io->signature); + + asynch_unlock(); + return; + +} + +// +// +// + +ASYNCH_IO *io_callback_head = 0; +ASYNCH_IO *io_callback_tail = 0; + +#if (LINUX_SLEEP) +NWFSInitSemaphore(callback_semaphore); +#endif + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) +spinlock_t cb_spinlock = SPIN_LOCK_UNLOCKED; +long cb_flags = 0; +#else +NWFSInitMutex(cb_sem); +#endif +#endif + +void cb_lock(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&cb_spinlock, cb_flags); +#else + if (WaitOnSemaphore(&cb_sem) == -EINTR) + NWFSPrint("cb lock was interrupted\n"); +#endif +#endif +} + +void cb_unlock(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&cb_spinlock, cb_flags); +#else + SignalSemaphore(&cb_sem); +#endif +#endif +} + +ASYNCH_IO *get_callback(void) +{ + register ASYNCH_IO *io; + + cb_lock(); + io = io_callback_head; + if (io) + { + io_callback_head = io->next; + if (io_callback_head) + io_callback_head->prior = NULL; + else + io_callback_tail = NULL; + + io->next = io->prior = 0; + cb_unlock(); + return io; + } + cb_unlock(); + return 0; +} + +void insert_callback(ASYNCH_IO *io) +{ +#if (LINUX_SPIN) + if (io->flags & ASIO_INTR_CALLBACK) + { + register ULONG ccode = 0; + + if (io->call_back_routine) + ccode = (io->call_back_routine)(io); + + if (!ccode) + { + disk_aio_completed++; + io->signature = ASIO_CALLBACK_POST; + io->signature = ASIO_COMPLETED; + aio_completed++; + return; + } + } +#endif + + NWFSPrint("sleep callback\n"); + + cb_lock(); + + if (io->signature != ASIO_AIO_POST) + { + NWFSPrint("\nins callback - bad io (0x%08X) cmd-%X sig-%X cb-%X \nd/s-%d/%X\n", + (unsigned)io, (unsigned)io->command, (unsigned)io->signature, + (unsigned)io->call_back_routine, (int)io->disk, + (unsigned)io->sector_offset); + } + + disk_aio_completed++; + + if (!io_callback_head) + { + io_callback_head = io; + io_callback_tail = io; + io->next = io->prior = 0; + } + else + { + io_callback_tail->next = io; + io->next = 0; + io->prior = io_callback_tail; + io_callback_tail = io; + } + + io->signature = ASIO_CALLBACK_POST; + +#if (LINUX_SLEEP) + SignalSemaphore(&callback_semaphore); +#endif + + cb_unlock(); + return; +} + +void process_callback(void) +{ + register ASYNCH_IO *io; + + cb_active++; + io = get_callback(); + while (io) + { + if (io->signature != ASIO_CALLBACK_POST) + { + NWFSPrint("\nproc callback - bad io (0x%08X) cmd-%X sig-%X cb-%X \nd/s-%d/%X\n", + (unsigned)io, (unsigned)io->command, (unsigned)io->signature, + (unsigned)io->call_back_routine, (int)io->disk, + (unsigned)io->sector_offset); + + io->ccode = ASIO_BAD_SIGNATURE; + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + aio_error++; + aio_completed++; + io = get_callback(); + continue; + } + + if (io->call_back_routine) + (io->call_back_routine)(io); + io->signature = ASIO_COMPLETED; + aio_completed++; + + io = get_callback(); + } + cb_active--; + return; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/bit.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/bit.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/bit.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/bit.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,1190 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : BIT.C +* DESCRIP : NWFS Bit Block Routines for Managing Free Lists +* DATE : November 16, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +void NWLockBB(BIT_BLOCK_HEAD *bb) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&bb->BB_spinlock, bb->BB_flags); +#else + if (WaitOnSemaphore(&bb->BBSemaphore) == -EINTR) + NWFSPrint("lock bit block was interupted\n"); +#endif +#endif +} + +void NWUnlockBB(BIT_BLOCK_HEAD *bb) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&bb->BB_spinlock, bb->BB_flags); +#else + SignalSemaphore(&bb->BBSemaphore); +#endif +#endif +} + +// +// general bit block allocation, chaining, and search routines +// + +BIT_BLOCK *AllocateBitBlock(ULONG BlockSize) +{ + register BIT_BLOCK *blk; + + blk = NWFSAlloc(sizeof(BIT_BLOCK), BITBLOCK_TAG); + if (!blk) + return 0; + + NWFSSet(blk, 0, sizeof(BIT_BLOCK)); + + blk->BlockBuffer = NWFSCacheAlloc(BlockSize, BITBUFFER_TAG); + if (!blk->BlockBuffer) + { + NWFSFree(blk); + return 0; + } + NWFSSet(blk->BlockBuffer, 0, BlockSize); + return blk; +} + +void FreeBitBlock(BIT_BLOCK *blk) +{ + if (blk->BlockBuffer) + NWFSFree(blk->BlockBuffer); + NWFSFree(blk); + return; +} + +ULONG GetBitBlockLimit(BIT_BLOCK_HEAD *bb) +{ + return (bb->Limit); +} + +ULONG GetBitBlockBlockSize(BIT_BLOCK_HEAD *bb) +{ + return (bb->BlockSize); +} + +ULONG CreateBitBlockList(BIT_BLOCK_HEAD *bb, ULONG Limit, ULONG BlockSize, + BYTE *name) +{ + register BIT_BLOCK *blk; + register int Blocks, BlockNo, i; + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_init(&bb->BB_spinlock); + bb->BB_flags = 0; +#else + AllocateSemaphore(&bb->BBSemaphore, 1); +#endif +#endif + + NWLockBB(bb); + bb->Head = bb->Tail = 0; + bb->Count = 0; + bb->BlockSize = BlockSize; + bb->Limit = Limit; + + if (name) + { + for (i=0; (i < 15) && (name[i]); i++) + bb->Name[i] = name[i]; + bb->Name[i] = '\0'; + } + else + bb->Name[0] = '\0'; + + if (!bb->BlockSize) + { + NWUnlockBB(bb); + return -1; + } + + // always have one block by default + + Blocks = ((((Limit + (8 - 1)) / 8) + + (bb->BlockSize - 1)) / bb->BlockSize); + for (BlockNo=0; BlockNo < Blocks; BlockNo++) + { + blk = AllocateBitBlock(BlockSize); + if (!blk) + { + NWUnlockBB(bb); + NWFSPrint("nwfs: could not allocate bit block\n"); + return -1; + } + + blk->BlockIndex = bb->Count; + if (!InsertBitBlock(bb, blk)) + { + NWUnlockBB(bb); + NWFSPrint("nwfs: could not create bit block list"); + return -1; + } + bb->Count++; + } + NWUnlockBB(bb); + return 0; +} + +ULONG FreeBitBlockList(BIT_BLOCK_HEAD *bb) +{ + register BIT_BLOCK *blk; + + NWLockBB(bb); + while (bb->Head) + { + blk = RemoveBitBlock(bb, bb->Head); + if (blk) + { + NWFSFree(blk->BlockBuffer); + NWFSFree(blk); + } + } + + NWUnlockBB(bb); + return 0; +} + +ULONG AdjustBitBlockList(BIT_BLOCK_HEAD *bb, ULONG NewLimit) +{ + register BIT_BLOCK *blk, *list, *prev = 0; + register ULONG TotalBlocks, NewBlocks, i; + + NWLockBB(bb); + + // always have one block by default + + TotalBlocks = ((((NewLimit + (8 - 1)) / 8) + + (bb->BlockSize - 1)) / bb->BlockSize); + + // we need to expand the bit block list; + + if (TotalBlocks > bb->Count) + { + // get the delta between current blocks and total requested + // blocks. + + NewBlocks = TotalBlocks - bb->Count; + for (i=0; i < NewBlocks; i++) + { + blk = AllocateBitBlock(bb->BlockSize); + if (!blk) + { + NWFSPrint("nwfs: could not allocate bit block\n"); + NWUnlockBB(bb); + return -1; + } + blk->BlockIndex = bb->Count; + if (!InsertBitBlock(bb, blk)) + { + NWFSPrint("nwfs: could not extend bit block list\n"); + NWUnlockBB(bb); + return -1; + } + bb->Count++; + } + + bb->Limit = NewLimit; + NWUnlockBB(bb); + return 0; + } + + // we need to shrink the bit block list + if (TotalBlocks < bb->Count) + { + list = bb->Head; + for (i=0; i < TotalBlocks; i++) + { + prev = list; + list = list->next; + } + bb->Count = i; + if (prev) + prev->next = 0; + + // purge the remainder of the list + while (list) + { + prev = list; + list = list->next; + FreeBitBlock(prev); + } + bb->Limit = NewLimit; + + NWUnlockBB(bb); + return 0; + } + + // if current blocks and computed blocks are equal, then we + // return success (fall through case) but update Limit + + bb->Limit = NewLimit; + + NWUnlockBB(bb); + return 0; +} + +BIT_BLOCK *InsertBitBlockByValue(BIT_BLOCK_HEAD *bb, BIT_BLOCK *i, BIT_BLOCK *top) +{ + BIT_BLOCK *old, *p; + + if (!bb->Tail) + { + i->next = i->prior = NULL; + bb->Tail = i; + return i; + } + p = top; + old = NULL; + while (p) + { + if (p->BlockIndex < i->BlockIndex) + { + old = p; + p = p->next; + } + else + { + if (p->prior) + { + p->prior->next = i; + i->next = p; + i->prior = p->prior; + p->prior = i; + return top; + } + i->next = p; + i->prior = NULL; + p->prior = i; + return i; + } + } + old->next = i; + i->next = NULL; + i->prior = old; + bb->Tail = i; + return bb->Head; +} + +BIT_BLOCK *InsertBitBlock(BIT_BLOCK_HEAD *bb, BIT_BLOCK *blk) +{ + register BIT_BLOCK *searchblk; + + searchblk = bb->Head; + while (searchblk) + { + if (searchblk == blk) + return 0; + searchblk = searchblk->next; + } + bb->Head = InsertBitBlockByValue(bb, blk, bb->Head); + return blk; +} + +BIT_BLOCK *RemoveBitBlock(BIT_BLOCK_HEAD *bb, BIT_BLOCK *blk) +{ + register BIT_BLOCK *searchblk; + + searchblk = bb->Head; + while (searchblk) + { + if (searchblk == blk) + { + if (bb->Head == blk) + { + bb->Head = (void *) blk->next; + if (bb->Head) + bb->Head->prior = NULL; + else + bb->Tail = NULL; + } + else + { + blk->prior->next = blk->next; + if (blk != bb->Tail) + blk->next->prior = blk->prior; + else + bb->Tail = blk->prior; + } + blk->next = blk->prior = 0; + return blk; + } + searchblk = searchblk->next; + } + return 0; +} + + +// +// +// + +ULONG InitBitBlockList(BIT_BLOCK_HEAD *bb, ULONG value) +{ + register BIT_BLOCK *blk; + + NWLockBB(bb); + blk = bb->Head; + while (blk) + { + NWFSSet(blk->BlockBuffer, (value ? 1 : 0), bb->BlockSize); + blk = blk->next; + } + NWUnlockBB(bb); + return 0; +} + +// +// + +ULONG GetBitBlockValue(BIT_BLOCK_HEAD *bb, ULONG Index) +{ + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset, retCode; + + NWLockBB(bb); + if (Index > (bb->Limit - 1)) + { + NWUnlockBB(bb); + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk) + { + if (blk->BlockIndex == Block) + { + retCode = (ULONG)(((blk->BlockBuffer[Offset >> 3]) >> (Offset & 7)) & 1); + NWUnlockBB(bb); + return retCode; + } + blk = blk->next; + } + NWUnlockBB(bb); + return -1; +} + +ULONG SetBitBlockValue(BIT_BLOCK_HEAD *bb, ULONG Index, ULONG Value) +{ + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset; + + NWLockBB(bb); + if (Index > (bb->Limit - 1)) + { + NWUnlockBB(bb); + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk) + { + if (blk->BlockIndex == Block) + { + (Value & 1) ? (blk->BlockBuffer[Offset >> 3] |= (1 << (Offset & 7))) + : (blk->BlockBuffer[Offset >> 3] &= ~(1 << (Offset & 7))); + NWUnlockBB(bb); + return 0; + } + blk = blk->next; + } + NWUnlockBB(bb); + return -1; +} + +ULONG SetBitBlockValueWithRange(BIT_BLOCK_HEAD *bb, ULONG Index, ULONG Value, + ULONG Range) +{ + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset; + register int count = Range, i; + + NWLockBB(bb); + if (Index > (bb->Limit - 1)) + { + NWUnlockBB(bb); + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk && (count > 0)) + { + if (blk->BlockIndex == Block) + { + while (blk) + { + i = 0; + if (blk->BlockIndex == Block) + i = Offset; + + while ((i < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + i) < bb->Limit)) + { + (Value & 1) + ? (blk->BlockBuffer[i >> 3] |= (1 << (i & 7))) + : (blk->BlockBuffer[i >> 3] &= ~(1 << (i & 7))); + + count--; + if (!count) + { + NWUnlockBB(bb); + return 0; + } + i++; + } + blk = blk->next; + } + NWUnlockBB(bb); + return -1; + } + blk = blk->next; + } + NWUnlockBB(bb); + return -1; +} + +ULONG GetBitBlockValueNoLock(BIT_BLOCK_HEAD *bb, ULONG Index) +{ + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset, retCode; + + if (Index > (bb->Limit - 1)) + { + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk) + { + if (blk->BlockIndex == Block) + { + retCode = (ULONG)(((blk->BlockBuffer[Offset >> 3]) >> (Offset & 7)) & 1); + return retCode; + } + blk = blk->next; + } + return -1; +} + +ULONG SetBitBlockValueNoLock(BIT_BLOCK_HEAD *bb, ULONG Index, ULONG Value) +{ + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset; + + if (Index > (bb->Limit - 1)) + { + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk) + { + if (blk->BlockIndex == Block) + { + (Value & 1) ? (blk->BlockBuffer[Offset >> 3] |= (1 << (Offset & 7))) + : (blk->BlockBuffer[Offset >> 3] &= ~(1 << (Offset & 7))); + return 0; + } + blk = blk->next; + } + return -1; +} + +// +// +// + +ULONG ScanBitBlockValueWithIndex(BIT_BLOCK_HEAD *bb, ULONG Value, + ULONG Index, ULONG Range) +{ + register ULONG i; + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset; + + NWLockBB(bb); + +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count = 0; + bb->skip_search_count = 0; +#endif + + if (Index > (bb->Limit - 1)) + { + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanBitBlockValueWithIndex - index(%d) > limit(%d)\n", + (int)Index, (int)bb->Limit); +#endif + +#if (PROFILE_BIT_SEARCH) + NWFSPrint("swi:count-%d-%d value-%d index/lim-%d/%d (index > limit) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + bb->Name); +#endif + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk) + { + if (blk->BlockIndex == Block) + { + while (blk) + { + i = 0; + if (blk->BlockIndex == Block) + i = Offset; + + if (Value & 1) + { + while ((i < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + i) < bb->Limit)) + { + // if this index is on a dword boundry, then evaluate + // this value as a dword to speed table searching + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&blk->BlockBuffer[i >> 3] == 0) + { + i += (sizeof(ULONG) * 8); +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count += (sizeof(ULONG) * 8); + bb->skip_search_count++; +#endif + continue; + } + } + + if (((blk->BlockBuffer[i >> 3]) >> (i & 7)) & 1) + { + register int j, k; + + for (k = 0, j = i; + (k < Range) && ((j < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + j) < + bb->Limit)); + j++, k++) + { + if (!(((blk->BlockBuffer[j >> 3]) >> (j & 7)) & 1)) + break; + } + + if (k == Range) + { + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanBitBlockValueWithIndex - %d\n", + (int)((blk->BlockIndex * EntriesPerBlock) + i)); +#endif + +#if (PROFILE_BIT_SEARCH) + if (bb->bit_search_count > BIT_SEARCH_THRESHOLD) + NWFSPrint("swi:count-%d-%d value-%d index/lim-%d/%d (%X) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + (unsigned)((blk->BlockIndex * + EntriesPerBlock) + i), + bb->Name); +#endif + return ((blk->BlockIndex * EntriesPerBlock) + i); + } + else + i = j; + } + i++; +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count++; +#endif + + } + } + else + { + while ((i < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + i) < bb->Limit)) + { + // if this index is on a dword boundry, then evaluate + // this value as a dword to speed table searching + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&blk->BlockBuffer[i >> 3] == (ULONG)-1) + { + i += (sizeof(ULONG) * 8); +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count += (sizeof(ULONG) * 8); + bb->skip_search_count++; +#endif + continue; + } + } + + if (!(((blk->BlockBuffer[i >> 3]) >> (i & 7)) & 1)) + { + register int j, k; + + for (k = 0, j = i; + (k < Range) && ((j < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + j) < + bb->Limit)); + j++, k++) + { + if (((blk->BlockBuffer[j >> 3]) >> (j & 7)) & 1) + break; + } + + if (k == Range) + { + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanBitBlockValueWithIndex - %d\n", + (int)((blk->BlockIndex * EntriesPerBlock) + i)); +#endif + +#if (PROFILE_BIT_SEARCH) + if (bb->bit_search_count > BIT_SEARCH_THRESHOLD) + NWFSPrint("swi:count-%d-%d value-%d index/lim-%d/%d (%X) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + (unsigned)((blk->BlockIndex * + EntriesPerBlock) + i), + bb->Name); +#endif + return ((blk->BlockIndex * EntriesPerBlock) + i); + } + else + i = j; + } + i++; +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count++; +#endif + } + } + blk = blk->next; + } + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanBitBlockValueWithIndex(2) - -1\n"); +#endif + +#if (PROFILE_BIT_SEARCH) + NWFSPrint("swi:count-%d-%d value-%d index/lim-%d/%d (-1) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + bb->Name); +#endif + return -1; + } + blk = blk->next; + } + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanBitBlockValueWithIndex(1) - -1\n"); +#endif + +#if (PROFILE_BIT_SEARCH) + NWFSPrint("swi:count-%d-%d value-%d index/lim-%d/%d (-1) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + bb->Name); +#endif + return -1; + +} + +ULONG ScanAndSetBitBlockValueWithIndex(BIT_BLOCK_HEAD *bb, ULONG Value, + ULONG Index, ULONG Range) +{ + register ULONG i; + register BIT_BLOCK *blk; + register ULONG EntriesPerBlock; + register ULONG Block, Offset; + + NWLockBB(bb); + +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count = 0; + bb->skip_search_count = 0; +#endif + + if (Index > (bb->Limit - 1)) + { + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanAndSetBitBlockValueWithIndex - index(%d) > limit(%d)\n", + (int)Index, (int)bb->Limit); +#endif + +#if (PROFILE_BIT_SEARCH) + NWFSPrint("sswi:count-%d-%d value-%d index/lim-%d/%d (index > limit) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + bb->Name); +#endif + return -1; + } + + EntriesPerBlock = (bb->BlockSize * 8); + Block = Index / EntriesPerBlock; + Offset = Index % EntriesPerBlock; + + blk = bb->Head; + while (blk) + { + if (blk->BlockIndex == Block) + { + while (blk) + { + i = 0; + if (blk->BlockIndex == Block) + i = Offset; + + if (Value & 1) + { + while ((i < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + i) < bb->Limit)) + { + // if this index is on a dword boundry, then evaluate + // this value as a dword to speed table searching + + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&blk->BlockBuffer[i >> 3] == 0) + { + i += (sizeof(ULONG) * 8); +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count += (sizeof(ULONG) * 8); + bb->skip_search_count++; +#endif + continue; + } + } + + if (((blk->BlockBuffer[i >> 3]) >> (i & 7)) & 1) + { + register int j, k; + + for (k = 0, j = i; + (k < Range) && ((j < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + j) < + bb->Limit)); + j++, k++) + { + if (!(((blk->BlockBuffer[j >> 3]) >> (j & 7)) & 1)) + break; + } + + if (k == Range) + { + for (k = 0, j = i; + (k < Range) && ((j < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + j) < + bb->Limit)); + j++, k++) + { + blk->BlockBuffer[j >> 3] &= ~(1 << (j & 7)); + } + + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanAndSetBitBlockValueWithIndex - %d\n", + (int)((blk->BlockIndex * EntriesPerBlock) + i)); +#endif + +#if (PROFILE_BIT_SEARCH) + if (bb->bit_search_count > BIT_SEARCH_THRESHOLD) + NWFSPrint("sswi:count-%d-%d value-%d index/lim-%d/%d (%X) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + (unsigned)((blk->BlockIndex * + EntriesPerBlock) + i), + bb->Name); +#endif + return ((blk->BlockIndex * EntriesPerBlock) + i); + } + else + i = j; + } + i++; +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count++; +#endif + } + } + else + { + while ((i < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + i) < bb->Limit)) + { + // if this index is on a dword boundry, then evaluate + // this value as a dword to speed table searching + + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&blk->BlockBuffer[i >> 3] == (ULONG)-1) + { + i += (sizeof(ULONG) * 8); +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count += (sizeof(ULONG) * 8); + bb->skip_search_count++; +#endif + continue; + } + } + + if (!(((blk->BlockBuffer[i >> 3]) >> (i & 7)) & 1)) + { + register int j, k; + + for (k = 0, j = i; + (k < Range) && ((j < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + j) < + bb->Limit)); + j++, k++) + { + if (((blk->BlockBuffer[j >> 3]) >> (j & 7)) & 1) + break; + } + + if (k == Range) + { + for (k = 0, j = i; + (k < Range) && ((j < EntriesPerBlock) && + (((blk->BlockIndex * EntriesPerBlock) + j) < + bb->Limit)); + j++, k++) + { + blk->BlockBuffer[j >> 3] |= (1 << (j & 7)); + } + + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanAndSetBitBlockValueWithIndex - %d\n", + (int)((blk->BlockIndex * EntriesPerBlock) + i)); +#endif + +#if (PROFILE_BIT_SEARCH) + if (bb->bit_search_count > BIT_SEARCH_THRESHOLD) + NWFSPrint("sswi:count-%d-%d value-%d index/lim-%d/%d (%X) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + (unsigned)((blk->BlockIndex * + EntriesPerBlock) + i), + bb->Name); +#endif + return ((blk->BlockIndex * EntriesPerBlock) + i); + } + else + i = j; + } + i++; +#if (PROFILE_BIT_SEARCH) + bb->bit_search_count++; +#endif + } + } + blk = blk->next; + } + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanAndSetBitBlockValueWithIndex(2) - -1\n"); +#endif + +#if (PROFILE_BIT_SEARCH) + NWFSPrint("sswi:count-%d-%d value-%d index/lim-%d/%d (-1) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + bb->Name); +#endif + return -1; + } + blk = blk->next; + } + NWUnlockBB(bb); +#if (VERBOSE) + NWFSPrint("ScanAndSetBitBlockValueWithIndex(1) - -1\n"); +#endif + +#if (PROFILE_BIT_SEARCH) + NWFSPrint("sswi:count-%d-%d value-%d index/lim-%d/%d (-1) %s\n", + (int)bb->bit_search_count, + (int)bb->skip_search_count, + (int)Value, (int)Index, (int)bb->Limit, + bb->Name); +#endif + return -1; + +} + +ULONG BitScanValueWithIndex(BYTE *p, ULONG size, ULONG Value, + ULONG Index, ULONG Range) +{ + register ULONG i; + register ULONG EntriesPerBlock; + + if (Index > (size - 1)) + return -1; + + EntriesPerBlock = (size * 8); + i = Index % EntriesPerBlock; + if (Value & 1) + { + while ((i < EntriesPerBlock) && ((EntriesPerBlock + i) < size)) + { + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&p[i >> 3] == 0) + { + i += (sizeof(ULONG) * 8); + continue; + } + } + + if (((p[i >> 3]) >> (i & 7)) & 1) + { + register int j, k; + + for (k = 0, j = i; (k < Range) && ((j < EntriesPerBlock) && + ((EntriesPerBlock + j) < size)); j++, k++) + { + if (!(((p[j >> 3]) >> (j & 7)) & 1)) + break; + } + if (k == Range) + return i; + else + i = j; + } + i++; + } + } + else + { + while ((i < EntriesPerBlock) && ((EntriesPerBlock + i) < size)) + { + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&p[i >> 3] == (ULONG)-1) + { + i += (sizeof(ULONG) * 8); + continue; + } + } + + if (!(((p[i >> 3]) >> (i & 7)) & 1)) + { + register int j, k; + + for (k = 0, j = i; (k < Range) && ((j < EntriesPerBlock) && + ((EntriesPerBlock + j) < size)); j++, k++) + { + if (((p[j >> 3]) >> (j & 7)) & 1) + break; + } + if (k == Range) + return i; + else + i = j; + } + i++; + } + } + return -1; + +} + +ULONG BitScanAndSetValueWithIndex(BYTE *p, ULONG size, ULONG Value, + ULONG Index, ULONG Range) +{ + register ULONG i; + register ULONG EntriesPerBlock; + + if (Index > (size - 1)) + return -1; + + EntriesPerBlock = (size * 8); + i = Index % EntriesPerBlock; + if (Value & 1) + { + while ((i < EntriesPerBlock) && ((EntriesPerBlock + i) < size)) + { + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&p[i >> 3] == 0) + { + i += (sizeof(ULONG) * 8); + continue; + } + } + + if (((p[i >> 3]) >> (i & 7)) & 1) + { + register int j, k; + + for (k = 0, j = i; (k < Range) && ((j < EntriesPerBlock) && + ((EntriesPerBlock + j) < size)); j++, k++) + { + if (!(((p[j >> 3]) >> (j & 7)) & 1)) + break; + } + + if (k == Range) + { + for (k = 0, j = i; (k < Range) && ((j < EntriesPerBlock) && + ((EntriesPerBlock + j) < size)); j++, k++) + { + p[j >> 3] &= ~(1 << (j & 7)); + } + return i; + } + else + i = j; + } + i++; + } + } + else + { + while ((i < EntriesPerBlock) && ((EntriesPerBlock + i) < size)) + { + if (!(i % (sizeof(ULONG) * 8)) && + ((i + (sizeof(ULONG) * 8)) < EntriesPerBlock)) + { + if (*(ULONG *)&p[i >> 3] == (ULONG)-1) + { + i += (sizeof(ULONG) * 8); + continue; + } + } + + if (!(((p[i >> 3]) >> (i & 7)) & 1)) + { + register int j, k; + + for (k = 0, j = i; (k < Range) && ((j < EntriesPerBlock) && + ((EntriesPerBlock + j) < size)); j++, k++) + { + if (((p[j >> 3]) >> (j & 7)) & 1) + break; + } + + if (k == Range) + { + for (k = 0, j = i; (k < Range) && ((j < EntriesPerBlock) && + ((EntriesPerBlock + j) < size)); j++, k++) + { + p[j >> 3] |= (1 << (j & 7)); + } + return i; + } + else + i = j; + } + i++; + } + } + return -1; + +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/block.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/block.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/block.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/block.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,1440 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHORS : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : BLOCK.C +* DESCRIP : NWFS Block Device Interface Module +* DATE : December 2, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +BYTE *ZeroBuffer = 0; + +#if (FILE_DISK_EMULATION) + +void SyncDevice(ULONG disk) +{ + return; +} + +uint32 pReadDiskSectors( + uint32 disk_id, + uint32 sector_offset, + uint8 *buffer, + uint32 sector_count, + uint32 extra) +{ +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + if (extra) {}; + if (SystemDisk[disk_id] != 0) + { + fseek((FILE *) SystemDisk[disk_id]->PhysicalDiskHandle, sector_offset * 512, 0); + return (fread(buffer, 512, sector_count, (FILE *) SystemDisk[disk_id]->PhysicalDiskHandle)); + } + return(0); +} + +uint32 pWriteDiskSectors( + uint32 disk_id, + uint32 sector_offset, + uint8 *buffer, + uint32 sector_count, + uint32 extra) +{ +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + if (extra) {}; + if (SystemDisk[disk_id] != 0) + { + fseek((FILE *) SystemDisk[disk_id]->PhysicalDiskHandle, sector_offset * 512, 0); + return (fwrite(buffer, 512, sector_count, (FILE *) SystemDisk[disk_id]->PhysicalDiskHandle)); + + } + return(0); +} + + +ULONG pZeroFillDiskSectors( + uint32 disk_id, + uint32 sector_offset, + uint32 sector_count, + uint32 extra) +{ +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + if (extra) {}; + if (SystemDisk[disk_id] != 0) + { + fseek((FILE *) SystemDisk[disk_id]->PhysicalDiskHandle, sector_offset * 512, 0); + return (fwrite(ZeroBuffer, 512, sector_count, (FILE *) SystemDisk[disk_id]->PhysicalDiskHandle)); + + } + return(0); +} + +ULONG ReadDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ + return (pReadDiskSectors(disk, LBA, Sector, sectors, readAhead)); +} + +ULONG WriteDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ + return (pWriteDiskSectors(disk, LBA, Sector, sectors, readAhead)); +} + +ULONG ZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, + ULONG sectors, ULONG readAhead) +{ + return (pZeroFillDiskSectors(disk, StartingLBA, sectors, readAhead)); +} + +#else // FILE_DISK_EMULATION + + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +extern ULONG insert_io(ULONG disk, ASYNCH_IO *io); +extern void RunAsynchIOQueue(ULONG disk); +extern void profile_complete(void); +void insert_callback(ASYNCH_IO *io); + +#if (LINUX_24) +DECLARE_WAIT_QUEUE_HEAD(wait_for_bh); +#elif (LINUX_20 | LINUX_22) +struct wait_queue *wait_for_bh = NULL; +#endif + +#if (LINUX_22 | LINUX_24) +kmem_cache_t *bh_p = 0; +#endif + +// +// low level disk sector interface routines +// + +#define AIO_SIGNATURE (ULONG)"AIOD" + +struct buffer_head *bh_head = 0; +struct buffer_head *bh_tail = 0; +ULONG bh_count = 0; +ULONG bh_waiters = 0; + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) +spinlock_t bh_spinlock = SPIN_LOCK_UNLOCKED; +long bh_flags = 0; +#else +NWFSInitMutex(bh_semaphore); +#endif +#endif + +void lock_bh_free(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&bh_spinlock, bh_flags); +#else + if (WaitOnSemaphore(&bh_semaphore) == -EINTR) + NWFSPrint("lock bh was interrupted\n"); +#endif +#endif +} + +void unlock_bh_free(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&bh_spinlock, bh_flags); +#else + SignalSemaphore(&bh_semaphore); +#endif +#endif +} + + +void nwfs_put_bh(struct buffer_head *bh) +{ + lock_bh_free(); + if (!bh_head) + { + bh_head = bh_tail = bh; + bh->b_next_free = bh->b_prev_free = 0; + } + else + { + bh_tail->b_next_free = bh; + bh->b_next_free = 0; + bh->b_prev_free = bh_tail; + bh_tail = bh; + } + unlock_bh_free(); + + // wake up any waiters + wake_up(&wait_for_bh); + + return; +} + +struct buffer_head *int_get_bh(void) +{ + struct buffer_head *bh; + + lock_bh_free(); + if (bh_head) + { + bh = bh_head; + bh_head = bh->b_next_free; + if (bh_head) + bh_head->b_prev_free = NULL; + else + bh_tail = NULL; + + bh->b_next_free = bh->b_prev_free = 0; + unlock_bh_free(); + return bh; + } + else + if (bh_count < MAX_BUFFER_HEADS) + { + unlock_bh_free(); + +#if (LINUX_20) + bh = (struct buffer_head *)kmalloc(sizeof(struct buffer_head), + GFP_ATOMIC); + + BH_TRACKING.count += sizeof(struct buffer_head); + BH_TRACKING.units++; + MemoryInUse += sizeof(struct buffer_head); + +#elif (LINUX_22 | LINUX_24) + bh = (struct buffer_head *)kmem_cache_alloc(bh_p, SLAB_KERNEL); + + BH_TRACKING.count += sizeof(struct buffer_head); + BH_TRACKING.units++; + MemoryInUse += sizeof(struct buffer_head); + +#else + bh = (struct buffer_head *)NWFSIOAlloc(sizeof(struct buffer_head), BH_TAG); +#endif + if (!bh) + return 0; + + bh_count++; + + NWFSSet(bh, 0, sizeof(struct buffer_head)); + +#if (LINUX_24) + init_waitqueue_head(&bh->b_wait); +#endif + return bh; + } + unlock_bh_free(); + return 0; +} + +void free_bh_list(void) +{ + struct buffer_head *bh; + + lock_bh_free(); + while (bh_head) + { + bh = bh_head; + bh_head = bh->b_next_free; + +#if (LINUX_20) + kfree(bh); + + BH_TRACKING.count -= sizeof(struct buffer_head); + BH_TRACKING.units--; + MemoryInUse -= sizeof(struct buffer_head); + +#elif (LINUX_22 | LINUX_24) + if (bh_p) + { + kmem_cache_free(bh_p, bh); + + BH_TRACKING.count -= sizeof(struct buffer_head); + BH_TRACKING.units--; + MemoryInUse -= sizeof(struct buffer_head); + } +#else + NWFSFree(bh); +#endif + } + bh_head = bh_tail = 0; + +#if (LINUX_22 | LINUX_24) + if (bh_p) + { + kmem_cache_shrink(bh_p); +#if (LINUX_24) + kmem_cache_destroy(bh_p); +#endif + } + bh_p = 0; +#endif + + bh_count = 0; + unlock_bh_free(); + return; +} + +struct buffer_head *__get_bh_wait(void) +{ + struct buffer_head *bh; +#if (LINUX_20 | LINUX_22) + struct wait_queue wait = { current, NULL }; +#elif (LINUX_24) + DECLARE_WAITQUEUE(wait, current); +#endif + +#if (LINUX_20 | LINUX_22) + add_wait_queue(&wait_for_bh, &wait); +#elif (LINUX_24) + add_wait_queue_exclusive(&wait_for_bh, &wait); +#endif + + for (;;) + { + current->state = TASK_UNINTERRUPTIBLE; + bh = int_get_bh(); + if (bh) + break; +#if (!POST_IMMEDIATE) + +#if (LINUX_22) + lock_kernel(); +#endif + run_task_queue(&tq_disk); +#if (LINUX_22) + unlock_kernel(); +#endif + +#endif + bh_waiters++; + schedule(); + bh_waiters--; + } + remove_wait_queue(&wait_for_bh, &wait); + current->state = TASK_RUNNING; + return bh; +} + +struct buffer_head *nwfs_get_bh(void) +{ + struct buffer_head *bh; + +#if (LINUX_22 | LINUX_24) + if (!bh_p) + { + bh_p = kmem_cache_create("nwfs_buffer_head", sizeof(struct buffer_head), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!bh_p) + { + NWFSPrint("Cannot create buffer head SLAB cache\n"); + unlock_bh_free(); + return 0; + } + } +#endif + + bh = int_get_bh(); + if (bh) + return bh; + return __get_bh_wait(); +} + +#if (LINUX_BUFFER_CACHE) + +// +// The 2.2.X buffer cache is not SMP thread safe, +// so lock the kernel when we enter it to prevent memory corruption +// from occurring on SMP systems. +// + +ULONG pReadDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ + register ULONG i, bytesRead = 0; + register ULONG bps, lba; + register NWDISK *NWDisk; + register ULONG read_error = 0; + register ULONG rsize, blocks, blocksize, spb; + struct buffer_head *bh[sectors]; + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + +#if (VERBOSE) + NWFSPrint("read disk-%d lba-%d for %d sectors\n", + (int)disk, (int)StartingLBA, (int)sectors); +#endif + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read-bc)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + +#if (LINUX_22) + lock_kernel(); +#endif + + for (i=0; i < blocks; i++) + { + if (!(bh[i] = getblk((ULONG)NWDisk->PhysicalDiskHandle, + lba + i, blocksize))) + { + for (i=0; i < blocks; i++) + if (bh[i]) + brelse(bh[i]); +#if (LINUX_22) + unlock_kernel(); +#endif + return 0; + } + } + +#if (DUMP_BUFFER_HEADS) + if (1) + { + for (i=0; i < blocks; i++) + { + NWFSPrint("getblk buffer head (read) %d-0x%08X\n", (int)i, + (unsigned)bh[i]); + dumpRecordBytes(bh[i], sizeof(struct buffer_head)); + dumpRecord(bh[i], sizeof(struct buffer_head)); + } +#if (LINUX_22) + unlock_kernel(); +#endif + return 0; + } +#endif + + ll_rw_block(READ, blocks, bh); + for(i=0; i < blocks; i++) + { + wait_on_buffer(bh[i]); + if (buffer_uptodate(bh[i])) + { + NWFSCopy(&Sector[i * blocksize], bh[i]->b_data, blocksize); + bytesRead += blocksize; + } + else + { + NWFSPrint("read error %d of %d bytes read %d blksize-%d\n", + (int)i, (int)blocks, (int)bytesRead, + (int)blocksize); + read_error = 1; + } + brelse(bh[i]); + } +#if (LINUX_22) + unlock_kernel(); +#endif + +#if (PROFILE_AIO) + profile_complete(); +#endif + + return (read_error ? 0 : bytesRead); + +} + +ULONG pWriteDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ + register ULONG i, bytesWritten = 0; + register ULONG bps, lba; + struct buffer_head *bh[sectors]; + register ULONG write_error = 0; + register ULONG rsize, blocks, blocksize, spb; + register NWDISK *NWDisk; + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + +#if (VERBOSE) + NWFSPrint("write disk-%d lba-%d for %d sectors\n", + (int)disk, (int)StartingLBA, (int)sectors); +#endif + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (write-bc)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + +#if (LINUX_22) + lock_kernel(); +#endif + for (i=0; i < blocks; i++) + { + if (!(bh[i] = getblk((ULONG)NWDisk->PhysicalDiskHandle, + lba + i, blocksize))) + { + for (i=0; i < blocks; i++) + if (bh[i]) + brelse(bh[i]); +#if (LINUX_22) + unlock_kernel(); +#endif + return 0; + } + NWFSCopy(bh[i]->b_data, &Sector[i * blocksize], blocksize); + mark_buffer_uptodate(bh[i], 1); + +#if (LINUX_24) + mark_buffer_dirty(bh[i]); +#else + mark_buffer_dirty(bh[i], 0); +#endif + bytesWritten += blocksize; + } + +#if (DUMP_BUFFER_HEADS) + if (1) + { + for (i=0; i < blocks; i++) + { + NWFSPrint("getblk buffer head (write) %d-0x%08X\n", (int)i, + (unsigned)bh[i]); + dumpRecordBytes(bh[i], sizeof(struct buffer_head)); + dumpRecord(bh[i], sizeof(struct buffer_head)); + } +#if (LINUX_22) + unlock_kernel(); +#endif + return 0; + } +#endif + + ll_rw_block(WRITE, blocks, bh); + for (i=0; i < blocks; i++) + { + wait_on_buffer(bh[i]); + if (!buffer_uptodate(bh[i])) + write_error = 1; + brelse(bh[i]); + } +#if (LINUX_22) + unlock_kernel(); +#endif + +#if (PROFILE_AIO) + profile_complete(); +#endif + + return (write_error ? 0 : bytesWritten); + +} + +ULONG pZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, ULONG sectors, + ULONG readAhead) +{ + register ULONG i, bytesWritten = 0; + register ULONG bps, lba; + struct buffer_head *bh[sectors]; + register ULONG write_error = 0; + register ULONG rsize, blocks, blocksize, spb; + register NWDISK *NWDisk; + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + +#if (VERBOSE) + NWFSPrint("zero disk-%d lba-%d for %d sectors\n", + (int)disk, (int)StartingLBA, (int)sectors); +#endif + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (fill-bc)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + +#if (LINUX_22) + lock_kernel(); +#endif + for (i=0; i < blocks; i++) + { + if (!(bh[i] = getblk((ULONG)NWDisk->PhysicalDiskHandle, + lba + i, blocksize))) + { + for (i=0; i < blocks; i++) + if (bh[i]) + brelse(bh[i]); +#if (LINUX_22) + unlock_kernel(); +#endif + return 0; + } + NWFSSet(bh[i]->b_data, 0, blocksize); + mark_buffer_uptodate(bh[i], 1); +#if (LINUX_24) + mark_buffer_dirty(bh[i]); +#else + mark_buffer_dirty(bh[i], 0); +#endif + bytesWritten += blocksize; + } + +#if (DUMP_BUFFER_HEADS) + if (1) + { + for (i=0; i < blocks; i++) + { + NWFSPrint("getblk buffer head (fill) %d-0x%08X\n", (int)i, + (unsigned)bh[i]); + dumpRecordBytes(bh[i], sizeof(struct buffer_head)); + dumpRecord(bh[i], sizeof(struct buffer_head)); + } +#if (LINUX_22) + unlock_kernel(); +#endif + return 0; + } +#endif + + ll_rw_block(WRITE, blocks, bh); + for (i=0; i < blocks; i++) + { + wait_on_buffer(bh[i]); + if (!buffer_uptodate(bh[i])) + write_error = 1; + brelse(bh[i]); + } +#if (LINUX_22) + unlock_kernel(); +#endif + +#if (PROFILE_AIO) + profile_complete(); +#endif + + return (write_error ? 0 : bytesWritten); +} + +#else + +// +// this case assumes we will use the NWFS buffer cache and not allow +// cache sharing with the linux buffer cache. +// + +// +// Linux 2.4 +// + +#if (LINUX_24) + +void end_io(struct buffer_head *bh, int uptodate) +{ + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + return; +} + +ULONG pReadDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ + register ULONG i, j, bytesRead = 0; + register ULONG bps, lba; + register NWDISK *NWDisk; + register ULONG read_error = 0; + register ULONG rsize, blocks, blocksize, spb; + struct buffer_head *bh[sectors]; + register struct page *page = virt_to_page(Sector); + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + + for (i=0; i < blocks; i++) + { + bh[i] = nwfs_get_bh(); + if (!bh[i]) + { + for (j=0; j < i; j++) + if (bh[j]) + nwfs_put_bh(bh[j]); + return 0; + } + } + + for (i=0; i < blocks; i++) + { + bh[i]->b_this_page = bh[(i + 1) % blocks]; // create circular list + bh[i]->b_state = 0; + bh[i]->b_next_free = (struct buffer_head *)NULL; + bh[i]->b_size = blocksize; + bh[i]->b_data = (char *)&Sector[i * blocksize]; + bh[i]->b_list = BUF_CLEAN; + bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle; + bh[i]->b_blocknr = lba + i; + bh[i]->b_count.counter = 1; + bh[i]->b_flushtime = 0; + bh[i]->b_end_io = end_io; + bh[i]->b_private = NULL; + bh[i]->b_page = page; + set_bit(BH_Mapped, &bh[i]->b_state); + set_bit(BH_Lock, &bh[i]->b_state); + clear_bit(BH_Uptodate, &bh[i]->b_state); + } + +#if (DUMP_BUFFER_HEADS) + if (1) + { + for (i=0; i < blocks; i++) + { + NWFSPrint("nwfs buffer head (read) %d-0x%08X\n", (int)i, + (unsigned)bh[i]); + dumpRecordBytes(bh[i], sizeof(struct buffer_head)); + dumpRecord(bh[i], sizeof(struct buffer_head)); + } + return 0; + } +#endif + + for (i=0; i < blocks; i++) + submit_bh(READ, bh[i]); + + for (i=0; i < blocks; i++) + { + wait_on_buffer(bh[i]); + if (buffer_uptodate(bh[i])) + bytesRead += blocksize; + else + read_error = 1; + nwfs_put_bh(bh[i]); + } + +#if (PROFILE_AIO) + profile_complete(); +#endif + + return (read_error ? 0 : bytesRead); + +} + +ULONG pWriteDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ + register ULONG i, j, bytesWritten = 0; + register ULONG bps, lba; + register ULONG write_error = 0; + register ULONG rsize, blocks, blocksize, spb; + register NWDISK *NWDisk; + struct buffer_head *bh[sectors]; + register struct page *page = virt_to_page(Sector); + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + + for (i=0; i < blocks; i++) + { + bh[i] = nwfs_get_bh(); + if (!bh[i]) + { + for (j=0; j < i; j++) + if (bh[j]) + nwfs_put_bh(bh[j]); + return 0; + } + } + + for (i=0; i < blocks; i++) + { + bh[i]->b_this_page = bh[(i + 1) % blocks]; // create circular list + bh[i]->b_state = 0; + bh[i]->b_next_free = (struct buffer_head *) NULL; + bh[i]->b_size = blocksize; + bh[i]->b_data = (char *)&Sector[i * blocksize]; + bh[i]->b_list = BUF_CLEAN; + bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle; + bh[i]->b_blocknr = lba + i; + bh[i]->b_count.counter = 1; + bh[i]->b_flushtime = 0; + bh[i]->b_end_io = end_io; + bh[i]->b_private = NULL; + bh[i]->b_page = page; + set_bit(BH_Req, &bh[i]->b_state); + set_bit(BH_Mapped, &bh[i]->b_state); + set_bit(BH_Uptodate, &bh[i]->b_state); + set_bit(BH_Dirty, &bh[i]->b_state); + set_bit(BH_Lock, &bh[i]->b_state); + } + +#if (DUMP_BUFFER_HEADS) + if (1) + { + for (i=0; i < blocks; i++) + { + NWFSPrint("nwfs buffer head (write) %d-0x%08X\n", (int)i, + (unsigned)bh[i]); + dumpRecordBytes(bh[i], sizeof(struct buffer_head)); + dumpRecord(bh[i], sizeof(struct buffer_head)); + } + return 0; + } +#endif + + for (i=0; i < blocks; i++) + submit_bh(WRITE, bh[i]); + + for (i=0; i < blocks; i++) + { + wait_on_buffer(bh[i]); + if (buffer_uptodate(bh[i])) + bytesWritten += blocksize; + else + write_error = 1; + nwfs_put_bh(bh[i]); + } + +#if (PROFILE_AIO) + profile_complete(); +#endif + + return (write_error ? 0 : bytesWritten); + +} + +ULONG pZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, ULONG sectors, + ULONG readAhead) +{ + register ULONG i, j, bytesWritten = 0; + register ULONG bps, lba; + register ULONG write_error = 0; + register ULONG rsize, blocks, blocksize, spb; + register NWDISK *NWDisk; + struct buffer_head *bh[sectors]; + register struct page *page = virt_to_page(ZeroBuffer); + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + + for (i=0; i < blocks; i++) + { + bh[i] = nwfs_get_bh(); + if (!bh[i]) + { + for (j=0; j < i; j++) + if (bh[j]) + nwfs_put_bh(bh[j]); + return 0; + } + } + + for (i=0; i < blocks; i++) + { + bh[i]->b_this_page = bh[(i + 1) % blocks]; // create circular list + bh[i]->b_state = 0; + bh[i]->b_next_free = (struct buffer_head *) NULL; + bh[i]->b_size = blocksize; + bh[i]->b_data = (char *) ZeroBuffer; + bh[i]->b_list = BUF_CLEAN; + bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle; + bh[i]->b_blocknr = lba + i; + bh[i]->b_count.counter = 1; + bh[i]->b_flushtime = 0; + bh[i]->b_end_io = end_io; + bh[i]->b_private = NULL; + bh[i]->b_page = page; + set_bit(BH_Req, &bh[i]->b_state); + set_bit(BH_Mapped, &bh[i]->b_state); + set_bit(BH_Uptodate, &bh[i]->b_state); + set_bit(BH_Dirty, &bh[i]->b_state); + set_bit(BH_Lock, &bh[i]->b_state); + } + +#if (DUMP_BUFFER_HEADS) + if (1) + { + for (i=0; i < blocks; i++) + { + NWFSPrint("nwfs buffer head (fill) %d-0x%08X\n", (int)i, + (unsigned)bh[i]); + dumpRecordBytes(bh[i], sizeof(struct buffer_head)); + dumpRecord(bh[i], sizeof(struct buffer_head)); + } + return 0; + } +#endif + + for (i=0; i < blocks; i++) + submit_bh(WRITE, bh[i]); + + for (i=0; i < blocks; i++) + { + wait_on_buffer(bh[i]); + if (buffer_uptodate(bh[i])) + bytesWritten += blocksize; + else + write_error = 1; + nwfs_put_bh(bh[i]); + } + +#if (PROFILE_AIO) + profile_complete(); +#endif + + return (write_error ? 0 : bytesWritten); +} + +// +// +// + +void end_asynch_io(struct buffer_head *bh, int uptodate) +{ + register int i; + ASYNCH_IO *io = (ASYNCH_IO *)bh->b_private; + bh->b_private = 0; + + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + + if (!io) + { + NWFSPrint("nwfs: aio callback has NULL handle\n"); + return; + } + + if (!test_bit(BH_Uptodate, &bh->b_state)) + io->ccode = ASIO_IO_ERROR; + + atomic_inc((atomic_t *)&io->complete); + if (io->complete == io->count) + { + for (i=0; i < io->count; i++) + { + nwfs_put_bh(io->bh[i]); + io->bh[i] = 0; + } + + insert_callback(io); + +#if (PROFILE_AIO) + profile_complete(); +#endif + } + return; +} + +ULONG aReadDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector, + ULONG sectors, ULONG readAhead, ASYNCH_IO *io) +{ + register ULONG i, j, bytesRead = 0; + register ULONG bps, lba; + register NWDISK *NWDisk; + register struct page *page = virt_to_page(Sector); + register ULONG rsize, blocks, blocksize, spb; + + if (!page) + { + NWFSPrint("nwfs: page context was NULL in aReadDiskSectors\n"); + return 0; + } + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + + for (i=0; i < blocks; i++) + { + io->bh[i] = nwfs_get_bh(); + if (!io->bh[i]) + { + for (j=0; j < i; j++) + if (io->bh[j]) + nwfs_put_bh(io->bh[j]); + return 0; + } + } + + io->ccode = 0; + io->count = blocks; + io->complete = 0; + for (i=0; i < blocks; i++) + { + io->bh[i]->b_this_page = io->bh[(i + 1) % blocks]; + io->bh[i]->b_state = 0; + io->bh[i]->b_next_free = (struct buffer_head *)NULL; + io->bh[i]->b_size = blocksize; + io->bh[i]->b_data = (char *)&Sector[i * blocksize]; + io->bh[i]->b_list = BUF_CLEAN; + io->bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle; + io->bh[i]->b_blocknr = lba + i; + io->bh[i]->b_count.counter = 1; + io->bh[i]->b_flushtime = 0; + io->bh[i]->b_end_io = end_asynch_io; + io->bh[i]->b_private = io; + io->bh[i]->b_page = page; + set_bit(BH_Mapped, &io->bh[i]->b_state); + set_bit(BH_Lock, &io->bh[i]->b_state); + clear_bit(BH_Uptodate, &io->bh[i]->b_state); + } + + for (i=0; i < blocks; i++) + submit_bh(READ, io->bh[i]); + +#if (POST_IMMEDIATE) + run_task_queue(&tq_disk); +#endif + + bytesRead = (sectors * bps); + return (bytesRead); + +} + +ULONG aWriteDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector, + ULONG sectors, ULONG readAhead, ASYNCH_IO *io) +{ + register ULONG i, j, bytesWritten = 0; + register ULONG bps, lba; + register NWDISK *NWDisk; + register struct page *page = virt_to_page(Sector); + register ULONG rsize, blocks, blocksize, spb; + + if (!page) + { + NWFSPrint("nwfs: page context was NULL in aWriteDiskSectors\n"); + return 0; + } + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + + for (i=0; i < blocks; i++) + { + io->bh[i] = nwfs_get_bh(); + if (!io->bh[i]) + { + for (j=0; j < i; j++) + if (io->bh[j]) + nwfs_put_bh(io->bh[j]); + return 0; + } + } + + io->ccode = 0; + io->count = blocks; + io->complete = 0; + for (i=0; i < blocks; i++) + { + io->bh[i]->b_this_page = io->bh[(i + 1) % blocks]; + io->bh[i]->b_state = 0; + io->bh[i]->b_next_free = (struct buffer_head *) NULL; + io->bh[i]->b_size = blocksize; + io->bh[i]->b_data = (char *)&Sector[i * blocksize]; + io->bh[i]->b_list = BUF_CLEAN; + io->bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle; + io->bh[i]->b_blocknr = lba + i; + io->bh[i]->b_count.counter = 1; + io->bh[i]->b_flushtime = 0; + io->bh[i]->b_end_io = end_asynch_io; + io->bh[i]->b_private = io; + io->bh[i]->b_page = page; + set_bit(BH_New, &io->bh[i]->b_state); + set_bit(BH_Mapped, &io->bh[i]->b_state); + set_bit(BH_Uptodate, &io->bh[i]->b_state); + set_bit(BH_Dirty, &io->bh[i]->b_state); + set_bit(BH_Lock, &io->bh[i]->b_state); + } + + for (i=0; i < blocks; i++) + submit_bh(WRITE, io->bh[i]); + +#if (POST_IMMEDIATE) + run_task_queue(&tq_disk); +#endif + + bytesWritten = (sectors * bps); + return (bytesWritten); + +} + +ULONG aZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, ULONG sectors, + ULONG readAhead, ASYNCH_IO *io) +{ + register ULONG i, j, bytesWritten = 0; + register ULONG bps, lba; + register NWDISK *NWDisk; + register struct page *page = virt_to_page(ZeroBuffer); + register ULONG rsize, blocks, blocksize, spb; + + if (!page) + { + NWFSPrint("nwfs: page context was NULL in aZeroFillDiskSectors\n"); + return 0; + } + + NWDisk = SystemDisk[disk]; + bps = NWDisk->BytesPerSector; + blocksize = NWDisk->DeviceBlockSize; + + rsize = sectors * bps; + blocks = rsize / blocksize; + if (!blocks) + return 0; + spb = blocksize / bps; + + lba = StartingLBA / spb; + if (StartingLBA % spb) + { + NWFSPrint("request not %d block aligned (%d) sectors-%d lba-%d (read)\n", + (int)blocksize, (int)(StartingLBA % spb), (int)sectors, + (int)StartingLBA); + return 0; + } + + for (i=0; i < blocks; i++) + { + io->bh[i] = nwfs_get_bh(); + if (!io->bh[i]) + { + for (j=0; j < i; j++) + if (io->bh[j]) + nwfs_put_bh(io->bh[j]); + return 0; + } + } + + io->ccode = 0; + io->count = blocks; + io->complete = 0; + for (i=0; i < blocks; i++) + { + io->bh[i]->b_this_page = io->bh[(i + 1) % blocks]; + io->bh[i]->b_state = 0; + io->bh[i]->b_next_free = (struct buffer_head *) NULL; + io->bh[i]->b_size = blocksize; + io->bh[i]->b_data = (char *) ZeroBuffer; + io->bh[i]->b_list = BUF_CLEAN; + io->bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle; + io->bh[i]->b_blocknr = lba + i; + io->bh[i]->b_count.counter = 1; + io->bh[i]->b_flushtime = 0; + io->bh[i]->b_end_io = end_asynch_io; + io->bh[i]->b_private = io; + io->bh[i]->b_page = page; + set_bit(BH_New, &io->bh[i]->b_state); + set_bit(BH_Mapped, &io->bh[i]->b_state); + set_bit(BH_Uptodate, &io->bh[i]->b_state); + set_bit(BH_Dirty, &io->bh[i]->b_state); + set_bit(BH_Lock, &io->bh[i]->b_state); + } + + for (i=0; i < blocks; i++) + submit_bh(WRITE, io->bh[i]); + +#if (POST_IMMEDIATE) + run_task_queue(&tq_disk); +#endif + + bytesWritten = (sectors * bps); + return (bytesWritten); +} + +#endif + +#endif + +void SyncDevice(ULONG disk) +{ + sync_dev((int)disk); + return; +} + +#if (DO_ASYNCH_IO) +ULONG release_aio(ASYNCH_IO *io) +{ +#if (LINUX_SLEEP) + SignalSemaphore((struct semaphore *)io->call_back_parameter); +#endif + return 0; +} +#endif + +ULONG ReadDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ +#if (DO_ASYNCH_IO) + ASYNCH_IO io; +#if (LINUX_SLEEP) + NWFSInitSemaphore(raw_semaphore); +#endif + + NWFSSet(&io, 0, sizeof(ASYNCH_IO)); + + io.command = ASYNCH_READ; + io.disk = disk; + io.flags = ASIO_INTR_CALLBACK; + io.sector_offset = LBA; + io.sector_count = sectors; + io.buffer = Sector; + io.call_back_routine = release_aio; +#if (LINUX_SLEEP) + io.call_back_parameter = (ULONG) &raw_semaphore; +#endif + + insert_io(disk, &io); + + RunAsynchIOQueue(disk); + +#if (LINUX_SLEEP) + WaitOnSemaphore(&raw_semaphore); +#endif + + return (ULONG)(io.return_code); +#else + return (pReadDiskSectors(disk, LBA, Sector, sectors, readAhead)); +#endif +} + +ULONG WriteDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG sectors, ULONG readAhead) +{ +#if (DO_ASYNCH_IO) + ASYNCH_IO io; +#if (LINUX_SLEEP) + NWFSInitSemaphore(raw_semaphore); +#endif + + NWFSSet(&io, 0, sizeof(ASYNCH_IO)); + + io.command = ASYNCH_WRITE; + io.disk = disk; + io.flags = ASIO_INTR_CALLBACK; + io.sector_offset = LBA; + io.sector_count = sectors; + io.buffer = Sector; + io.call_back_routine = release_aio; +#if (LINUX_SLEEP) + io.call_back_parameter = (ULONG) &raw_semaphore; +#endif + + insert_io(disk, &io); + + RunAsynchIOQueue(disk); + +#if (LINUX_SLEEP) + WaitOnSemaphore(&raw_semaphore); +#endif + + return (ULONG)(io.return_code); +#else + return (pWriteDiskSectors(disk, LBA, Sector, sectors, readAhead)); +#endif +} + +ULONG ZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, + ULONG sectors, ULONG readAhead) +{ +#if (DO_ASYNCH_IO) + ASYNCH_IO io; +#if (LINUX_SLEEP) + NWFSInitSemaphore(raw_semaphore); +#endif + + NWFSSet(&io, 0, sizeof(ASYNCH_IO)); + + io.command = ASYNCH_FILL; + io.disk = disk; + io.flags = ASIO_INTR_CALLBACK; + io.sector_offset = StartingLBA; + io.sector_count = sectors; + io.buffer = NULL; + io.call_back_routine = release_aio; +#if (LINUX_SLEEP) + io.call_back_parameter = (ULONG) &raw_semaphore; +#endif + + insert_io(disk, &io); + + RunAsynchIOQueue(disk); + +#if (LINUX_SLEEP) + WaitOnSemaphore(&raw_semaphore); +#endif + + return (ULONG)(io.return_code); +#else + return (pZeroFillDiskSectors(disk, StartingLBA, sectors, readAhead)); +#endif +} + +#endif +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/cluster.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/cluster.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/cluster.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/cluster.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,2100 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : CLUSTER.C +* DESCRIP : NWFS Volume Cluster Routines +* DATE : December 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +ULONG TruncateClusterChain(VOLUME *volume, ULONG *Chain, ULONG Index, + ULONG PrevChain, ULONG size, ULONG SAFlag, + ULONG Attributes) +{ + register ULONG cluster, fcluster, prev_cluster, cbytes, NewCluster; + register ULONG index, FileIndex, FileOffset, prev_index; + MIRROR_LRU *lru = 0; + ULONG retCode = 0; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + register VOLUME_WORKSPACE *WorkSpace; + register ULONG SuballocSize; + + if (!Chain) + return NwInvalidParameter; + + if (!(*Chain)) + { + NWFSPrint("nwfs: fat chain was NULL (truncate)\n"); + return NwFileCorrupt; + } + + if (*Chain == (ULONG) -1) + return 0; + + index = 0; + prev_cluster = (ULONG) -1; + prev_index = (ULONG) -1; + cluster = *Chain; + + if (PrevChain) + prev_cluster = PrevChain; + + if (Index) + index = Index; + + FileIndex = size / volume->ClusterSize; + FileOffset = size % volume->ClusterSize; + +#if (VERBOSE) + NWFSPrint("nwfs_truncate: size-%d chain-%08X index-%X offset-%X\n", + (int) size, + (unsigned int)*Chain, + (unsigned int)FileIndex, + (unsigned int)FileOffset); +#endif + + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + // check if suballocation is legal for this file. + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || (Attributes & TRANSACTION)) + return NwNotPermitted; + + // if we are at our target index + if (index == FileIndex) + { + SuballocSize = GetSuballocSize(volume, cluster); + + // this case assumes we will free the current suballoc + // fragment. + + if (!FileOffset) + { + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, (ULONG) -1)) + return NwVolumeCorrupt; + } + else + *Chain = (ULONG) -1; + + FreeSuballocRecord(volume, cluster); + return 0; + } + + if ((FileOffset + (SUBALLOC_BLOCK_SIZE - 1)) < SuballocSize) + { + // for this case, we are going to free the current suballoc + // element, and replace it with a suballoc element of a + // smaller size. + + WorkSpace = AllocateWorkspace(volume); + if (WorkSpace) + { + NewCluster = AllocateSuballocRecord(volume, FileOffset, + &retCode); + if (NewCluster) + { + // here we read the previous data from the suballoc element + cbytes = ReadSuballocRecord(volume, 0, cluster, + &WorkSpace->Buffer[0], + FileOffset, + KERNEL_ADDRESS_SPACE, + &retCode); + if (cbytes != FileOffset) + { + FreeSuballocRecord(volume, NewCluster); + FreeWorkspace(volume, WorkSpace); + goto SkipFirstSuballocReplace; + } + + // write the previous data to the new suballoc element + cbytes = WriteSuballocRecord(volume, 0, NewCluster, + &WorkSpace->Buffer[0], + FileOffset, + KERNEL_ADDRESS_SPACE, + &retCode); + if (cbytes != FileOffset) + { + FreeSuballocRecord(volume, NewCluster); + FreeWorkspace(volume, WorkSpace); + goto SkipFirstSuballocReplace; + } + FreeWorkspace(volume, WorkSpace); + + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, NewCluster)) + { + FreeSuballocRecord(volume, NewCluster); + return NwVolumeCorrupt; + } + } + else + *Chain = NewCluster; + + FreeSuballocRecord(volume, cluster); + return 0; + } + FreeWorkspace(volume, WorkSpace); + } + } + } + +SkipFirstSuballocReplace:; + return 0; + } + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + prev_index = index; + index = FAT->FATIndex; + } + + while (FAT && FAT->FATCluster) + { + // if we are past our target index in the fat chain, then + // truncate the remaining elements in the chain. + + if (index > FileIndex) + { + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, (ULONG) -1)) + return NwVolumeCorrupt; + } + else + *Chain = (ULONG) -1; + + goto FreeChain; + } + + // check if we have found the cluster that matches our target + // index. + + if (index == FileIndex) + { + // if size is on a cluster boundry, then free the current + // cluster and all entries following it unless the file has + // holes. + + if (!FileOffset) + { + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, (ULONG) -1)) + return NwVolumeCorrupt; + } + else + *Chain = (ULONG) -1; + + goto FreeChain; + } + + // This case assumes that we have detected a file element + // that is the first element in the fat chain and that + // is not at the expected index of zero. This means that + // the first portion of the file is sparse and has a hole in + // it. It is invalid to suballocate the first non-zero + // indexed block within a fat chain because the index value + // cannot be stored by a suballocation element. As such, + // this is the one of two cases where we do not suballocate a + // partial cluster. Since the file is sparse, we are already + // getting significantly more efficient storage than the + // count of clusters reflected in the index count. + + // If index is non-zero and we are at the head of the fat + // chain, then do not suballocate this cluster. + + if (index && (prev_cluster == (ULONG) -1)) + { +#if (VERBOSE) + NWFSPrint("detected sparse element %08X-[%08X] (head)\n", + (unsigned int) index, + (unsigned int) cluster); +#endif + goto DontSuballocate; + } + + // if we are not the first cluster in the chain, but if we are + // the next cluster immediately following an allocation hole + // in the file, then do not suballocate this cluster. we + // keep track of the previous index value, and if the index + // numbers in the fat table are not sequential, then we know + // that this cluster immediately follows a hole in the + // file. + + if ((prev_cluster != (ULONG) -1) && ((prev_index + 1) != index)) + { +#if (VERBOSE) + NWFSPrint("detected sparse element %08X-[%08X] (chain)\n", + (unsigned int) index, + (unsigned int) cluster); +#endif + goto DontSuballocate; + } + + // check if suballocation is legal for this file. + + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || + (Attributes & TRANSACTION)) + goto DontSuballocate; + + // If this cluster has a sequential index count, and is not + // a sparse cluster at the chain head, and its current + // allocation size is not within volume->ClusterSize - 511, + // and the file is not flagged transactional, and suballocation + // has not been disabled at the file level, then convert + // this cluster into a suballocation element, copy the + // data from the partially filled cluster, and free + // everything in the chain, including this cluster. + + if ((FileOffset + (SUBALLOC_BLOCK_SIZE - 1)) < volume->ClusterSize) + { + // for this case, we are going to free the current cluster + // and replace it with a suballoc element of a + // smaller size. + + WorkSpace = AllocateWorkspace(volume); + if (WorkSpace) + { + NewCluster = AllocateSuballocRecord(volume, FileOffset, &retCode); + if (NewCluster) + { + // here we read the previous data from the cluster + cbytes = ReadClusterWithOffset(volume, + cluster, + 0, + &WorkSpace->Buffer[0], + FileOffset, + KERNEL_ADDRESS_SPACE, + &retCode, + DATA_PRIORITY); + if (cbytes != FileOffset) + { + FreeSuballocRecord(volume, NewCluster); + FreeWorkspace(volume, WorkSpace); + goto DontSuballocate; + } + + // write the previous data to the new suballoc element + cbytes = WriteSuballocRecord(volume, + 0, + NewCluster, + &WorkSpace->Buffer[0], + FileOffset, + KERNEL_ADDRESS_SPACE, + &retCode); + if (cbytes != FileOffset) + { + FreeSuballocRecord(volume, NewCluster); + FreeWorkspace(volume, WorkSpace); + goto DontSuballocate; + } + FreeWorkspace(volume, WorkSpace); + + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, NewCluster)) + { + FreeSuballocRecord(volume, NewCluster); + return NwVolumeCorrupt; + } + } + else + *Chain = NewCluster; + + goto FreeChain; + } + FreeWorkspace(volume, WorkSpace); + } + } + +DontSuballocate:; + // set this cluster as end of file + if (SetClusterValue(volume, cluster, (ULONG) -1)) + return NwVolumeCorrupt; + + // bump to next cluster + cluster = FAT->FATCluster; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + prev_index = index; + index = FAT->FATIndex; + } + goto FreeChain; + } + + // save previous cluster + prev_cluster = cluster; + + // bump to next cluster + cluster = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + // check if suballocation is legal for this file. + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || (Attributes & TRANSACTION)) + return NwNotPermitted; + + // if we are at our target index + if ((index + 1) == FileIndex) + { + SuballocSize = GetSuballocSize(volume, cluster); + + // this case assumes we will free the current suballoc + // fragment. + + if (!FileOffset) + { + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, (ULONG) -1)) + return NwVolumeCorrupt; + } + else + *Chain = (ULONG) -1; + + FreeSuballocRecord(volume, cluster); + return 0; + } + + if ((FileOffset + (SUBALLOC_BLOCK_SIZE - 1)) < SuballocSize) + { + // for this case, we are going to free the current suballoc + // element, and replace it with a suballoc element of a + // smaller size. + + WorkSpace = AllocateWorkspace(volume); + if (WorkSpace) + { + NewCluster = AllocateSuballocRecord(volume, FileOffset, + &retCode); + if (NewCluster) + { + // here we read the previous data from the suballoc element + cbytes = ReadSuballocRecord(volume, 0, cluster, + &WorkSpace->Buffer[0], + FileOffset, + KERNEL_ADDRESS_SPACE, + &retCode); + if (cbytes != FileOffset) + { + FreeSuballocRecord(volume, NewCluster); + FreeWorkspace(volume, WorkSpace); + goto SkipSuballocReplace; + } + + // write the previous data to the new suballoc element + cbytes = WriteSuballocRecord(volume, 0, NewCluster, + &WorkSpace->Buffer[0], + FileOffset, + KERNEL_ADDRESS_SPACE, + &retCode); + if (cbytes != FileOffset) + { + FreeSuballocRecord(volume, NewCluster); + FreeWorkspace(volume, WorkSpace); + goto SkipSuballocReplace; + } + FreeWorkspace(volume, WorkSpace); + + // if there was a previous cluster, then set as EOF + if (prev_cluster != (ULONG) -1) + { + if (SetClusterValue(volume, prev_cluster, NewCluster)) + { + FreeSuballocRecord(volume, NewCluster); + return NwVolumeCorrupt; + } + } + else + *Chain = NewCluster; + + FreeSuballocRecord(volume, cluster); + return 0; + } + FreeWorkspace(volume, WorkSpace); + } + } + } + +SkipSuballocReplace:; + return 0; + } + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + prev_index = index; + index = FAT->FATIndex; + } + } + return 0; + + +FreeChain:; + while (FAT && FAT->FATCluster) + { + // save current cluster + fcluster = cluster; + + // bump to next cluster + cluster = FAT->FATCluster; + + // clear this cluster in the FAT table + retCode = NWUpdateFat(volume, FAT, lru, 0, 0, fcluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return NwVolumeCorrupt; + } + + // set current cluster free in bit block list + SetFreeClusterValue(volume, fcluster, 0); + + volume->VolumeFreeClusters++; + if (volume->VolumeAllocatedClusters) + volume->VolumeAllocatedClusters--; + + // check if the next cluster is a suballoc element or EOF + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || (Attributes & TRANSACTION)) + return NwNotPermitted; + + // set suballoc element free in list + FreeSuballocRecord(volume, cluster); + + return 0; + } + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + index = FAT->FATIndex; + } + return 0; + +} + +// +// Cluster Allocation bitmap routines +// + +ULONG InitializeClusterFreeList(VOLUME *volume) +{ + return (CreateBitBlockList(&volume->FreeBlockList, + volume->VolumeClusters, + BIT_BLOCK_SIZE, + "cluster free")); +} + +ULONG ExtendClusterFreeList(VOLUME *volume, ULONG Amount) +{ +#if (VERBOSE) + NWFSPrint("extend_cluster_free_list\n"); +#endif + return (AdjustBitBlockList(&volume->FreeBlockList, Amount)); +} + +ULONG FreeClusterFreeList(VOLUME *volume) +{ +#if (VERBOSE) + NWFSPrint("free_cluster_free_list\n"); +#endif + return (FreeBitBlockList(&volume->FreeBlockList)); +} + +ULONG GetFreeClusterValue(VOLUME *volume, ULONG Cluster) +{ +#if (VERBOSE) + NWFSPrint("get_free_cluster_value\n"); +#endif + return (GetBitBlockValue(&volume->FreeBlockList, Cluster)); +} + +ULONG SetFreeClusterValue(VOLUME *volume, ULONG Cluster, ULONG flag) +{ + register int i; + +#if (VERBOSE) + NWFSPrint("set_free_cluster_value\n"); +#endif + for (i=0; i < volume->MountedNumberOfSegments; i++) + { + if (Cluster < (volume->SegmentClusterStart[i] + + volume->SegmentClusterSize[i])) + { + if (Cluster >= volume->SegmentClusterStart[i]) + { + if (Cluster < volume->LastAllocatedIndex[i]) + volume->LastAllocatedIndex[i] = Cluster; + break; + } + } + } + return (SetBitBlockValue(&volume->FreeBlockList, Cluster, flag)); +} + +ULONG FindFreeCluster(VOLUME *volume, ULONG Cluster) +{ +#if (VERBOSE) + NWFSPrint("find_free_cluster\n"); +#endif + return (ScanAndSetBitBlockValueWithIndex(&volume->FreeBlockList, 0, Cluster, + 1)); +} + +// +// +// + +ULONG InitializeClusterAssignedList(VOLUME *volume) +{ + return (CreateBitBlockList(&volume->AssignedBlockList, + volume->VolumeClusters, + BIT_BLOCK_SIZE, + "cluster assign")); +} + +ULONG ExtendClusterAssignedList(VOLUME *volume, ULONG Amount) +{ + return (AdjustBitBlockList(&volume->AssignedBlockList, Amount)); +} + +ULONG FreeClusterAssignedList(VOLUME *volume) +{ + return (FreeBitBlockList(&volume->AssignedBlockList)); +} + +ULONG GetAssignedClusterValue(VOLUME *volume, ULONG Cluster) +{ + return (GetBitBlockValue(&volume->AssignedBlockList, Cluster)); +} + +ULONG SetAssignedClusterValue(VOLUME *volume, ULONG Cluster, ULONG flag) +{ + return (SetBitBlockValue(&volume->AssignedBlockList, Cluster, flag)); +} + +ULONG FindAssignedCluster(VOLUME *volume, ULONG Cluster) +{ + return (ScanBitBlockValueWithIndex(&volume->AssignedBlockList, 0, Cluster, + 1)); +} + +// +// This routine compares the free list built from the fat against +// a free list built from reported allocations in the directory, +// suballoc file chains, and DOS/MAC namespace data chains to +// determine if any orphaned or broken fat chains are wasting +// space on the device. +// + +ULONG AdjustAllocatedClusters(VOLUME *volume) +{ + register ULONG total = 0; + register ULONG i, val1, val2, ccode, retries; +#if (CACHE_FAT_TABLES) + extern ULONG FlushFAT(VOLUME *volume); +#endif + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Verifying Volume Allocation ***\n"); +#endif + + // if the count of empty subdirectories on this volume is greater + // than the current free directory blocks, then preallocate + // free space in the directory file until the count of empty + // directories is greater than or equal to the number of + // free directory blocks in the directory file. Netware treats + // this as a fatal error if any empty subdirectories exist for + // which there is no corresponding free directory block. We + // don't treat this as a fatal error, and will attempt to + // pre-allocate free records until a reasonable limit + // is reached. What is odd about this case is that Netware 4.2 + // will actually break this rule, and create empty subdirectories + // without populating them properly, then vrepair the volume + // when it mounts. + +#if (VERBOSE) + NWFSPrint("nwfs: free dir block count-%d free dir count-%d\n", + (int)volume->FreeDirectoryBlockCount, + (int)volume->FreeDirectoryCount); +#endif + + if (volume->FreeDirectoryBlockCount < volume->FreeDirectoryCount) + { + retries = 0; + while (volume->FreeDirectoryBlockCount < volume->FreeDirectoryCount) + { + ccode = PreAllocateEmptyDirectorySpace(volume); + if (ccode) + break; + + if (retries++ > 10) // if we get stuck in a loop here, then exit + { + NWFSPrint("nwfs: exceeded pre-allocated record limit (verify) [%u-%u]\n", + (unsigned int)volume->FreeDirectoryCount, + (unsigned int)volume->FreeDirectoryBlockCount); + break; + } + } + } + + for (i=0; i < volume->MountedVolumeClusters; i++) + { + val1 = GetFreeClusterValue(volume, i); + val2 = GetAssignedClusterValue(volume, i); + + if (val1 != val2) + { + // if the record is unallocated in the free list but we found + // an allocation for this cluster in either the directory, + // extdirectory, suballoc, or macintosh chain, then mark this + // cluster as free in the cluster free list. + + if (!val1 && val2) + { + // this means the volume is corrupted. + NWFSPrint("nwfs: directory reports allocation not in fat table\n"); + return 0; + } + + // set this cluster as free and record that we have freed an + // unassigned cluster. + SetFreeClusterValue(volume, i, 0); + + // clear the cluster fields in the fat table + FreeClusterNoFlush(volume, i); + + // track total clusters freed + total++; + } + } + +#if (CACHE_FAT_TABLES) + // flush out dirty fat buffers + FlushFAT(volume); +#endif + + return total; +} + +ULONG NWUpdateFat(VOLUME *volume, FAT_ENTRY *FAT, MIRROR_LRU *lru, + ULONG index, ULONG value, ULONG cluster) +{ + register ULONG retCode; + + if (!FAT || !lru) + return -1; + + FAT->FATIndex = index; + FAT->FATCluster = value; + + retCode = WriteFATEntry(volume, lru, FAT, cluster); + if (retCode) + NWFSPrint("WriteFATEntry cluster-%X error\n", (unsigned)cluster); + +#if (CACHE_FAT_TABLES) + FlushFATBuffer(volume, lru, cluster); +#endif + + return retCode; +} + +ULONG NWUpdateFatNoFlush(VOLUME *volume, FAT_ENTRY *FAT, MIRROR_LRU *lru, + ULONG index, ULONG value, ULONG cluster) +{ + register ULONG retCode; + + if (!FAT || !lru) + return -1; + + FAT->FATIndex = index; + FAT->FATCluster = value; + + retCode = WriteFATEntry(volume, lru, FAT, cluster); + if (retCode) + NWFSPrint("WriteFATEntry cluster-%X error\n", (unsigned)cluster); + + if (lru) + lru->BlockState = L_DIRTY; + + return 0; +} + +ULONG GetChainSize(VOLUME *volume, long ClusterChain) +{ + register ULONG cluster; + ULONG total = 0; + register ULONG index = 0; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + + if ((!ClusterChain) || (ClusterChain == (ULONG) -1)) + return total; + + cluster = ClusterChain; + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return total; + + if (cluster & 0x80000000) + total += GetSuballocSize(volume, cluster); + + return total; + } + + FAT = GetFatEntry(volume, cluster, &FAT_S); + if (FAT) + index = FAT->FATIndex; + + while (FAT && FAT->FATCluster) + { + // If we detect a non-ascending index sequence, then we assume + // that the fat chain is corrupt. + if (total > ((index + 1) * volume->ClusterSize)) + return total; + + // set total to indexed offset in fat chain plus the current + // cluster allocation. + total = ((index + 1) * volume->ClusterSize); + + // bump to next cluster + cluster = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return total; + + if (cluster & 0x80000000) + total += GetSuballocSize(volume, cluster); + + return total; + } + + FAT = GetFatEntry(volume, cluster, &FAT_S); + if (FAT) + index = FAT->FATIndex; + } + return total; + +} + +ULONG GetChainSizeValidate(VOLUME *volume, + long ClusterChain, + ULONG SAFlag, + ULONG *total) +{ + register ULONG cluster, index = 0; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + + if (!total) + return NwInvalidParameter; + *total = 0; + + if (!ClusterChain) + return NwChainBad; + + if (ClusterChain == (ULONG) -1) + return 0; + + cluster = ClusterChain; + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + if (cluster & 0x80000000) + { + if (!SAFlag) + return NwInvalidParameter; + + (*total) += GetSuballocSize(volume, cluster); + } + return 0; + } + + FAT = GetFatEntry(volume, cluster, &FAT_S); + if (FAT) + index = FAT->FATIndex; + + if (!FAT->FATCluster) + return NwChainBad; + + while (FAT && FAT->FATCluster) + { + // If we detect a non-ascending index sequence, then we assume + // that the fat chain is corrupt. + if ((*total) > ((index + 1) * volume->ClusterSize)) + return NwChainBad; + + // set total to indexed offset in fat chain plus the current + // cluster allocation. + (*total) = ((index + 1) * volume->ClusterSize); + + // bump to next cluster + cluster = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + if (cluster & 0x80000000) + { + if (!SAFlag) + return NwInvalidParameter; + + (*total) += GetSuballocSize(volume, cluster); + } + return 0; + } + + FAT = GetFatEntry(volume, cluster, &FAT_S); + if (FAT) + index = FAT->FATIndex; + + if (!FAT->FATCluster) + return NwChainBad; + } + return 0; + +} + +// this function builds a detailed allocation map of all clusters +// and suballoc elements that exist within the specified fat +// chain. + +ULONG BuildChainAssignment(VOLUME *volume, ULONG Chain, ULONG SAFlag) +{ + register ULONG cluster, retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + + if ((!Chain) || (Chain == (ULONG) -1)) + return 0; + + cluster = Chain; + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + if (cluster & 0x80000000) + { + if (!SAFlag) + return NwInvalidParameter; + + retCode = SetSuballocListValue(volume, cluster, 1); + if (retCode) + NWFSPrint("nwfs: multiple files point to suballoc record\n"); + + return retCode; + } + + return 0; + } + + FAT = GetFatEntry(volume, cluster, &FAT_S); + while (FAT && FAT->FATCluster) + { + retCode = GetAssignedClusterValue(volume, cluster); + if (retCode) + { + NWFSPrint("nwfs: detected invalid assigned cluster-%X\n", + (unsigned int)cluster); + return -1; + } + + retCode = SetAssignedClusterValue(volume, cluster, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set cluster-%X\n", + (unsigned int)cluster); + } + + // bump to next cluster + cluster = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return 0; + + if (cluster & 0x80000000) + { + if (!SAFlag) + return NwInvalidParameter; + + retCode = SetSuballocListValue(volume, cluster, 1); + if (retCode) + NWFSPrint("nwfs: multiple files point to suballoc record\n"); + + return retCode; + } + return 0; + } + FAT = GetFatEntry(volume, cluster, &FAT_S); + } + return 0; + +} + +ULONG VerifyChainAssignment(VOLUME *volume, ULONG Chain, ULONG SAFlag) +{ + register ULONG cluster, retCode = 0; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + + if ((!Chain) || (Chain == (ULONG) -1)) + return 0; + + cluster = Chain; + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return retCode; + + if (cluster & 0x80000000) + { + if (!SAFlag) + return NwInvalidParameter; + + if (!GetSuballocListValue(volume, cluster)) + { + NWFSPrint("nwfs: suballoc [%08X] record verifies as free\n", + (unsigned int)cluster); + retCode++; + } + } + return retCode; + } + + FAT = GetFatEntry(volume, cluster, &FAT_S); + while (FAT && FAT->FATCluster) + { + retCode = GetAssignedClusterValue(volume, cluster); + if (!retCode) + { + NWFSPrint("nwfs: cluster [%08X] verifies as free\n", + (unsigned int)cluster); + retCode++; + } + + // bump to next cluster + cluster = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF + if (cluster & 0x80000000) + { + if (cluster == (ULONG) -1) + return retCode; + + if (cluster & 0x80000000) + { + if (!SAFlag) + return NwInvalidParameter; + + if (!GetSuballocListValue(volume, cluster)) + { + NWFSPrint("nwfs: suballoc [%08X] record verifies as free\n", + (unsigned int)cluster); + retCode++; + } + } + return retCode; + } + FAT = GetFatEntry(volume, cluster, &FAT_S); + } + return retCode; + +} + +ULONG FreeCluster(VOLUME *volume, long cluster) +{ + register ULONG retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + + if ((cluster < 0) || (cluster == -1)) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + retCode = NWUpdateFat(volume, FAT, lru, 0, 0, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + + // set current cluster free in bit block list + + SetFreeClusterValue(volume, cluster, 0); + volume->VolumeFreeClusters++; + if (volume->VolumeAllocatedClusters) + volume->VolumeAllocatedClusters--; + + return 0; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (FreeCluster)\n"); + return -1; + +} + +ULONG FreeClusterNoFlush(VOLUME *volume, long cluster) +{ + register ULONG retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + + if ((cluster < 0) || (cluster == -1)) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + retCode = NWUpdateFatNoFlush(volume, FAT, lru, 0, 0, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + + // set current cluster free in bit block list + + SetFreeClusterValue(volume, cluster, 0); + volume->VolumeFreeClusters++; + if (volume->VolumeAllocatedClusters) + volume->VolumeAllocatedClusters--; + + return 0; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (FreeClusterNoFlush)\n"); + return -1; + +} + +ULONG SetClusterValue(VOLUME *volume, long cluster, ULONG Value) +{ + register ULONG retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + + // don't allow people to free clusters with this call + if ((cluster < 0) || (cluster == -1) || (!Value)) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + retCode = NWUpdateFat(volume, FAT, lru, FAT->FATIndex, Value, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + return 0; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (SetClusterValue)\n"); + return -1; + +} + +ULONG SetClusterIndex(VOLUME *volume, long cluster, ULONG Index) +{ + register ULONG retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + + if ((cluster < 0) || (cluster == -1)) + return 0; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + retCode = NWUpdateFat(volume, FAT, lru, Index, FAT->FATCluster, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + return 0; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (SetClusterIndex)\n"); + return -1; + +} + +ULONG SetClusterValueAndIndex(VOLUME *volume, long cluster, + ULONG Value, ULONG Index) +{ + register ULONG retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + + // don't allow people to free clusters with this call + if ((cluster < 0) || (cluster == -1) || (!Value)) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + retCode = NWUpdateFat(volume, FAT, lru, Index, Value, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + return 0; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (SetClusterValueAndIndex)\n"); + return -1; +} + +// +// Below is the method Netware uses to perform striping for multi- +// segmented volumes. the method employed by Netware is more +// efficient than raid or the block striping typical of NT and Unix, +// and is incredibly simple. +// +// Netware keeps track of which segment was last allocated from, it +// then round robins between the segments during cluster allocation, +// and evenly distributes files across individual segments. this +// architecture lends itself well to additive storage. It is +// extremely simple to splice additional segments to the end +// of a Netware volume to increase its size over time. +// +// one disadvantage to this method, however, is that if you lose +// a segment in a netware volume, it renders the entire volume +// unusable until the volume has been repaired. mirroring +// is advised for multi-segmented volumes. +// + +ULONG AllocateCluster(VOLUME *volume) +{ + register ULONG cluster, retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + +#if (VERBOSE) + NWFSPrint("allocate cluster\n"); +#endif + + // start looking for a free cluster on the current segment's last + // allocated index + cluster = FindFreeCluster(volume, + volume->LastAllocatedIndex[volume->AllocSegment]); + + // start looking for a free cluster on the current segment + if (cluster == (ULONG) -1) + { + cluster = FindFreeCluster(volume, + volume->SegmentClusterStart[volume->AllocSegment]); + + // start looking at the beginning of the volume + if (cluster == (ULONG) -1) + { + cluster = FindFreeCluster(volume, volume->SegmentClusterStart[0]); + if (cluster == (ULONG) -1) + return -1; + } + } + + if (cluster != (ULONG) -1) + volume->LastAllocatedIndex[volume->AllocSegment] = cluster; + + // bump to the segment pointer to the next segment. range check + // and reset to zero if we wrap. + + volume->AllocSegment++; + if (volume->AllocSegment >= volume->MountedNumberOfSegments) + volume->AllocSegment = 0; + + if (cluster == (ULONG) -1) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + if (volume->VolumeFreeClusters) + volume->VolumeFreeClusters--; + volume->VolumeAllocatedClusters++; + + retCode = NWUpdateFat(volume, FAT, lru, 0, (ULONG) -1, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + return cluster; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (AllocateCluster)\n"); + return -1; +} + +ULONG AllocateClusterSetIndex(VOLUME *volume, ULONG Index) +{ + register ULONG cluster, retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + +#if (VERBOSE) + NWFSPrint("allocate cluster set index\n"); +#endif + + // start looking for a free cluster on the current segment's last + // allocated index + cluster = FindFreeCluster(volume, + volume->LastAllocatedIndex[volume->AllocSegment]); + + // start looking for a free cluster on the current segment + if (cluster == (ULONG) -1) + { + cluster = FindFreeCluster(volume, + volume->SegmentClusterStart[volume->AllocSegment]); + + // start looking at the beginning of the volume + if (cluster == (ULONG) -1) + { + cluster = FindFreeCluster(volume, volume->SegmentClusterStart[0]); + if (cluster == (ULONG) -1) + return -1; + } + } + + if (cluster != (ULONG) -1) + volume->LastAllocatedIndex[volume->AllocSegment] = cluster; + + // bump to the segment pointer to the next segment. range check + // and reset to zero if we wrap. + + volume->AllocSegment++; + if (volume->AllocSegment >= volume->MountedNumberOfSegments) + volume->AllocSegment = 0; + + if (cluster == (ULONG) -1) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + if (volume->VolumeFreeClusters) + volume->VolumeFreeClusters--; + volume->VolumeAllocatedClusters++; + + retCode = NWUpdateFat(volume, FAT, lru, Index, (ULONG) -1, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + return cluster; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (AllocateClusterSetIndex)\n"); + return -1; +} + +ULONG AllocateClusterSetIndexSetChain(VOLUME *volume, ULONG Index, ULONG Next) +{ + register ULONG cluster, retCode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + MIRROR_LRU *lru = 0; + +#if (VERBOSE) + NWFSPrint("allocate cluster set chain/index\n"); +#endif + + // start looking for a free cluster on the current segment's last + // allocated index + cluster = FindFreeCluster(volume, + volume->LastAllocatedIndex[volume->AllocSegment]); + + // start looking for a free cluster on the current segment + if (cluster == (ULONG) -1) + { + cluster = FindFreeCluster(volume, + volume->SegmentClusterStart[volume->AllocSegment]); + + // start looking at the beginning of the volume + if (cluster == (ULONG) -1) + { + cluster = FindFreeCluster(volume, volume->SegmentClusterStart[0]); + if (cluster == (ULONG) -1) + return -1; + } + } + + if (cluster != (ULONG) -1) + volume->LastAllocatedIndex[volume->AllocSegment] = cluster; + + // bump to the segment pointer to the next segment. range check + // and reset to zero if we wrap. + + volume->AllocSegment++; + if (volume->AllocSegment >= volume->MountedNumberOfSegments) + volume->AllocSegment = 0; + + if (cluster == (ULONG) -1) + return -1; + + FAT = GetFatEntryAndLRU(volume, cluster, &lru, &FAT_S); + if (FAT) + { + if (volume->VolumeFreeClusters) + volume->VolumeFreeClusters--; + volume->VolumeAllocatedClusters++; + + retCode = NWUpdateFat(volume, FAT, lru, Index, Next, cluster); + if (retCode) + { + NWFSPrint("*** error updating FAT [%X/%X] ***\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster2); + return -1; + } + return cluster; + } + else + NWFSPrint("nwfs: cluster FAT Range Error (AllocateClusterSetIndexSetChain)\n"); + return -1; +} + +ULONG ReadAbsoluteVolumeCluster(VOLUME *volume, ULONG Cluster, BYTE *Buffer) +{ + register ULONG i, ccode; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in ReadVolumeCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + + for (i=0; i < volume->BlocksPerCluster; i++) + { + ccode = nwvp_vpartition_block_read(volume->nwvp_handle, + (Cluster * volume->BlocksPerCluster) + i, + 1, Buffer); + if (ccode) + return NwDiskIoError; + + Buffer += volume->BlockSize; + } + return 0; + +} + +ULONG WriteAbsoluteVolumeCluster(VOLUME *volume, ULONG Cluster, BYTE *Buffer) +{ + register ULONG i, ccode; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in WriteVolumeCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + + for (i=0; i < volume->BlocksPerCluster; i++) + { + ccode = nwvp_vpartition_block_write(volume->nwvp_handle, + (Cluster * volume->BlocksPerCluster) + i, + 1, Buffer); + if (ccode) + return NwDiskIoError; + + Buffer += volume->BlockSize; + } + return 0; +} + +ULONG ReadPhysicalVolumeCluster(VOLUME *volume, ULONG Cluster, + BYTE *Buffer, ULONG size, ULONG priority) +{ + register ULONG i, vsize; + register long bytesLeft; + register LRU *lru; + register LRU_HANDLE *lru_handle = &DataLRU; + ULONG mirror = (ULONG)-1; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in ReadVolumeCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + + if (size > volume->ClusterSize) + { + NWFSPrint("cluster size bad in ReadVolumeCluster\n"); + return NwInvalidParameter; + } + + if (priority == RAW_PRIORITY) + return (ReadAbsoluteVolumeCluster(volume, Cluster, Buffer)); + + switch (priority) + { + case FAT_PRIORITY: + lru_handle = &FATLRU; + break; + + case DIRECTORY_PRIORITY: + lru_handle = &JournalLRU; + break; + + default: + break; + } + + for (bytesLeft = size, i=0; i < volume->BlocksPerCluster; i++) + { + vsize = (bytesLeft > (long)volume->BlockSize) + ? volume->BlockSize : bytesLeft; + + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + i, + 1, priority, + ((i == 0) ? (volume->BlocksPerCluster - i) : 1), + &mirror); + + if (!lru) + return NwDiskIoError; + + if (lru->bad_bits) + { + ReleaseLRU(lru_handle, lru); + return NwDiskIoError; + } + + NWFSCopy(Buffer, lru->buffer, vsize); + ReleaseLRU(lru_handle, lru); + + Buffer += vsize; + bytesLeft -= vsize; + } + return 0; + +} + +ULONG WritePhysicalVolumeCluster(VOLUME *volume, ULONG Cluster, + BYTE *Buffer, ULONG size, ULONG priority) +{ + register ULONG i, vsize; + register long bytesLeft; + register LRU *lru; + register LRU_HANDLE *lru_handle = &DataLRU; + ULONG mirror = (ULONG)-1; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in WriteVolumeCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + + if (size > volume->ClusterSize) + { + NWFSPrint("cluster size bad in WriteVolumeCluster\n"); + return NwInvalidParameter; + } + + if (priority == RAW_PRIORITY) + return (WriteAbsoluteVolumeCluster(volume, Cluster, Buffer)); + + switch (priority) + { + case FAT_PRIORITY: + lru_handle = &FATLRU; + break; + + case DIRECTORY_PRIORITY: + lru_handle = &JournalLRU; + break; + + default: + break; + } + + for (bytesLeft = size, i=0; i < volume->BlocksPerCluster; i++) + { + vsize = (bytesLeft > (long)volume->BlockSize) + ? volume->BlockSize : bytesLeft; + + if (vsize == volume->BlockSize) + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + i, + 0, priority, 1, &mirror); + else + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + i, + 1, priority, 1, &mirror); + + if (!lru) + return NwDiskIoError; + + lru->bad_bits = 0; + NWFSCopy(lru->buffer, Buffer, vsize); + ReleaseDirtyLRU(lru_handle, lru); + + Buffer += vsize; + bytesLeft -= vsize; + } + return 0; +} + +ULONG ZeroPhysicalVolumeCluster(VOLUME *volume, ULONG Cluster, ULONG priority) +{ + register ULONG i, vsize; + register long bytesLeft; + register LRU *lru; + register LRU_HANDLE *lru_handle = &DataLRU; + ULONG mirror = (ULONG)-1; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in ZeroVolumeCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + + if (priority == RAW_PRIORITY) + return (WriteAbsoluteVolumeCluster(volume, Cluster, ZeroBuffer)); + + switch (priority) + { + case FAT_PRIORITY: + lru_handle = &FATLRU; + break; + + case DIRECTORY_PRIORITY: + lru_handle = &JournalLRU; + break; + + default: + break; + } + + for (bytesLeft = volume->ClusterSize, i=0; + i < volume->BlocksPerCluster; + i++) + { + vsize = (bytesLeft > (long)volume->BlockSize) + ? volume->BlockSize : bytesLeft; + + if (vsize == volume->BlockSize) + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + i, + 0, priority, 1, &mirror); + else + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + i, + 1, priority, 1, &mirror); + if (!lru) + return NwDiskIoError; + + lru->bad_bits = 0; + NWFSSet(lru->buffer, 0, vsize); + ReleaseDirtyLRU(lru_handle, lru); + + bytesLeft -= vsize; + } + return 0; +} + +ULONG SyncCluster(VOLUME *volume, ULONG Cluster) +{ + register ULONG retCode = 0; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in SyncCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + + retCode = SyncLRUBlocks(volume, + (Cluster * volume->BlocksPerCluster), + volume->BlocksPerCluster); + return retCode; +} + +ULONG ReadAheadVolumeCluster(VOLUME *volume, ULONG Cluster) +{ + register ULONG retCode = 0; + register LRU_HANDLE *lru_handle = &DataLRU; +#if (READ_AHEAD_ON) + ULONG mirror = (ULONG)-1; +#endif + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in ReadAheadVolumeCluster\n"); + NWFSPrint(" %x >= %x \n", (int) Cluster, + (int) volume->MountedVolumeClusters); + return NwInvalidParameter; + } + +#if (READ_AHEAD_ON) + retCode = PerformBlockReadAhead(lru_handle, volume, + (Cluster * volume->BlocksPerCluster), + volume->BlocksPerCluster, 1, &mirror); +#endif + return retCode; +} + +// +// these functions read and write clusters with an offset and size +// and handle wrap cases with individual logical disk blocks that +// can span sectors +// + +ULONG ReadClusterWithOffset(VOLUME *volume, ULONG Cluster, + ULONG offset, BYTE *buf, ULONG size, + ULONG as, ULONG *retCode, ULONG priority) +{ + register long bytesLeft, voffset, vsize, vindex; + register ULONG StartIndex, StartOffset, i; + register ULONG bytesRead = 0; + register LRU *lru; + register LRU_HANDLE *lru_handle = &DataLRU; + register BYTE *workbuffer = 0; + ULONG mirror = (ULONG)-1; + + if (retCode) + *retCode = 0; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in ReadVolumeCluster [%X]\n", + (unsigned int) Cluster); + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + if ((offset + size) > volume->ClusterSize) + { + NWFSPrint("read size bad in ReadClusterWithOffset\n"); + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + if (priority == RAW_PRIORITY) + { + register ULONG ccode; + + workbuffer = NWFSAlloc(IO_BLOCK_SIZE, BLOCK_TAG); + if (!workbuffer) + return NwInsufficientResources; + + StartIndex = offset / volume->BlockSize; + StartOffset = offset % volume->BlockSize; + + for (bytesLeft = size, vindex = StartIndex; + (vindex < (long)volume->BlocksPerCluster) && (bytesLeft > 0); + vindex++) + { + voffset = 0; + if (vindex == (long)StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->BlockSize - voffset)) + ? (volume->BlockSize - voffset) : bytesLeft; + + ccode = nwvp_vpartition_block_read(volume->nwvp_handle, + (Cluster * volume->BlocksPerCluster) + vindex, + 1, workbuffer); + if (ccode) + { + if (retCode) + *retCode = NwDiskIoError; + break; + } + + if (as) + NWFSCopy(buf, &workbuffer[voffset], vsize); + else + { + if (NWFSCopyToUserSpace(buf, &workbuffer[voffset], vsize)) + { + if (retCode) + *retCode = NwMemoryFault; + if (workbuffer) + NWFSFree(workbuffer); + return bytesRead; + } + } + buf += vsize; + bytesRead += vsize; + bytesLeft -= vsize; + } + } + else + { + switch (priority) + { + case FAT_PRIORITY: + lru_handle = &FATLRU; + break; + + case DIRECTORY_PRIORITY: + lru_handle = &JournalLRU; + break; + + default: + break; + } + + StartIndex = offset / volume->BlockSize; + StartOffset = offset % volume->BlockSize; + + for (bytesLeft = size, vindex = StartIndex; + (vindex < (long)volume->BlocksPerCluster) && (bytesLeft > 0); + vindex++) + { + voffset = 0; + if (vindex == (long)StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->BlockSize - voffset)) + ? (volume->BlockSize - voffset) : bytesLeft; + + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + vindex, + 1, priority, + ((vindex == (long)StartIndex) + ? (volume->BlocksPerCluster - vindex) : 1), + &mirror); + if (!lru) + { + if (retCode) + *retCode = NwDiskIoError; + break; + } + + for (i = (voffset / 512); + (i < (voffset + vsize) / 512) && (i < 8); + i++) + { + if ((lru->bad_bits >> i) & 1) + { + ReleaseLRU(lru_handle, lru); + if (retCode) + *retCode = NwDiskIoError; + break; + } + } + + if (as) + NWFSCopy(buf, &lru->buffer[voffset], vsize); + else + { + if (NWFSCopyToUserSpace(buf, &lru->buffer[voffset], vsize)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + + ReleaseLRU(lru_handle, lru); + + buf += vsize; + bytesRead += vsize; + bytesLeft -= vsize; + } + } + + if (workbuffer) + NWFSFree(workbuffer); + return bytesRead; +} + +ULONG WriteClusterWithOffset(VOLUME *volume, ULONG Cluster, + ULONG offset, BYTE *buf, ULONG size, + ULONG as, ULONG *retCode, ULONG priority) +{ + register long bytesLeft, voffset, vsize, vindex; + register ULONG StartIndex, StartOffset, i; + register ULONG bytesWritten = 0; + register LRU *lru; + register LRU_HANDLE *lru_handle = &DataLRU; + register BYTE *workbuffer = 0; + ULONG mirror = (ULONG)-1; + + if (retCode) + *retCode = 0; + + if (Cluster >= volume->MountedVolumeClusters) + { + NWFSPrint("bad cluster address in ReadVolumeCluster [%X]\n", + (unsigned int) Cluster); + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + if ((offset + size) > volume->ClusterSize) + { + NWFSPrint("read size bad in ReadClusterWithOffset\n"); + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + if (priority == RAW_PRIORITY) + { + register ULONG ccode; + + workbuffer = NWFSAlloc(IO_BLOCK_SIZE, BLOCK_TAG); + if (!workbuffer) + return NwInsufficientResources; + + StartIndex = offset / volume->BlockSize; + StartOffset = offset % volume->BlockSize; + + for (bytesLeft = size, vindex = StartIndex; + (vindex < (long)volume->BlocksPerCluster) && (bytesLeft > 0); + vindex++) + { + voffset = 0; + if (vindex == (long)StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->BlockSize - voffset)) + ? (volume->BlockSize - voffset) : bytesLeft; + + if ((voffset != 0) || + ((voffset == 0) && (vsize != (long)volume->BlockSize))) + { + ccode = nwvp_vpartition_block_read(volume->nwvp_handle, + (Cluster * volume->BlocksPerCluster) + vindex, + 1, workbuffer); + if (ccode) + { + if (retCode) + *retCode = NwDiskIoError; + break; + } + } + + if (as) + NWFSCopy(&workbuffer[voffset], buf, vsize); + else + { + if (NWFSCopyFromUserSpace(&workbuffer[voffset], buf, vsize)) + { + if (retCode) + *retCode = NwMemoryFault; + if (workbuffer) + NWFSFree(workbuffer); + return bytesWritten; + } + } + + ccode = nwvp_vpartition_block_write(volume->nwvp_handle, + (Cluster * volume->BlocksPerCluster) + vindex, + 1, workbuffer); + if (ccode) + { + if (retCode) + *retCode = NwDiskIoError; + break; + } + + buf += vsize; + bytesWritten += vsize; + bytesLeft -= vsize; + } + } + else + { + switch (priority) + { + case FAT_PRIORITY: + lru_handle = &FATLRU; + break; + + case DIRECTORY_PRIORITY: + lru_handle = &JournalLRU; + break; + + default: + break; + } + + StartIndex = offset / volume->BlockSize; + StartOffset = offset % volume->BlockSize; + + for (bytesLeft = size, vindex = StartIndex; + (vindex < (long)volume->BlocksPerCluster) && (bytesLeft > 0); + vindex++) + { + voffset = 0; + if (vindex == (long)StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->BlockSize - voffset)) + ? (volume->BlockSize - voffset) : bytesLeft; + + if ((voffset == 0) && (vsize == (long)volume->BlockSize)) + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + vindex, + 0, priority, 1, &mirror); + else + lru = ReadLRU(lru_handle, volume, + (Cluster * volume->BlocksPerCluster) + vindex, + 1, priority, 1, &mirror); + + if (!lru) + { + if (retCode) + *retCode = NwDiskIoError; + break; + } + + for (i = (voffset / 512); + (i < (voffset + vsize) / 512) && (i < 8); + i++) + { + lru->bad_bits &= ~(1 << i); + } + + if (as) + NWFSCopy(&lru->buffer[voffset], buf, vsize); + else + { + if (NWFSCopyFromUserSpace(&lru->buffer[voffset], buf, vsize)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesWritten; + } + } + + ReleaseDirtyLRU(lru_handle, lru); + + buf += vsize; + bytesWritten += vsize; + bytesLeft -= vsize; + } + } + + if (workbuffer) + NWFSFree(workbuffer); + return bytesWritten; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/create.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/create.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/create.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/create.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,753 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : CREATE.C +* DESCRIP : NWFS VFS Directory Create Module for Linux +* DATE : January 26, 1999 +* +* +***************************************************************************/ + +#include "globals.h" + +ULONG nwfs_to_linux_error(ULONG NwfsError) +{ + switch (NwfsError) + { + case NwSuccess: + return 0; + + case NwFatCorrupt: + case NwFileCorrupt: + case NwDirectoryCorrupt: + case NwVolumeCorrupt: + case NwHashCorrupt: + case NwMissingSegment: + return -ENFILE; + + case NwHashError: + case NwNoEntry: + return -ENOENT; + + case NwDiskIoError: + case NwMirrorGroupFailure: + case NwNoMoreMirrors: + return -EIO; + + case NwInsufficientResources: + return -ENOMEM; + + case NwFileExists: + return -EEXIST; + + case NwInvalidParameter: + case NwBadName: + return -EINVAL; + + case NwVolumeFull: + return -ENOSPC; + + case NwNotEmpty: + return -ENOTEMPTY; + + case NwAccessError: + return -EACCES; + + case NwNotPermitted: + return -EPERM; + + case NwMemoryFault: + return -EFAULT; + + case NwOtherError: + case NwEndOfFile: + default: + return -EACCES; + } +} + +int nwfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) dir->u.generic_ip; + register ULONG retCode; + ULONG DirNo; + register struct inode *inode; + register ino_t ino; + +#if (VFS_VERBOSE) + NWFSPrint("create %s\n", dentry->d_name.name); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory in create\n"); + return -ENOENT; + } + + if (!hash) + return -ENOENT; + + // if there is a name collision, then report that the file exists + ino = get_directory_number(volume, name, namelen, dir->i_ino); + if (ino) + return -EEXIST; + + retCode = NWCreateDirectoryEntry(volume, (BYTE *)name, namelen, + 0, dir->i_ino, + NW_NAMED_FILE, + current->fsuid, + ((dir->i_mode & S_ISGID) + ? dir->i_gid + : current->fsgid), + 0, mode, + &DirNo, + (ULONG) -1, 0, + (ULONG) -1, 0, + 0, 0); + if (retCode) + return (nwfs_to_linux_error(retCode)); + + if (!(inode = iget(dir->i_sb, DirNo)) < 0) + { + NWFSPrint("nwfs: iget failed in create\n"); + return -EBADF; + } + + inode->i_uid = current->fsuid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; + mark_inode_dirty(inode); + + // bump directory link count and size + dir->i_mtime = NWFSGetSystemTime(); + dir->i_nlink++; + dir->i_size += sizeof(ROOT); + mark_inode_dirty(dir); + + d_instantiate(dentry, inode); + + return 0; + +} + +int nwfs_unlink(struct inode *dir, struct dentry *dentry) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register struct inode *inode = dentry->d_inode; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *hash; + register ULONG retCode; + register ino_t ino; + DOS dosst; + register DOS *dos = &dosst; + +#if (VFS_VERBOSE) + NWFSPrint("unlink %s\n", name); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory\n"); + return -EBADF; + } + + hash = get_directory_hash(volume, name, namelen, dir->i_ino); + if (!hash) + return -ENOENT; + + ino = hash->DirNo; + + retCode = ReadDirectoryRecord(volume, dos, ino); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) read dir error [%d] (unlink)\n", + (int)ino, (int)retCode); + return -EIO; + } + +#if (SALVAGEABLE_FS) + + retCode = NWShadowDirectoryEntry(volume, dos, hash); + if (retCode) + return nwfs_to_linux_error(retCode); + +#else + + if (hash->Flags & HARD_LINKED_FILE) + { + retCode = NWDeleteDirectoryEntry(volume, dos, hash); + if (retCode) + return nwfs_to_linux_error(retCode); + } + else + { + retCode = NWDeleteDirectoryEntryAndData(volume, dos, hash); + if (retCode) + return nwfs_to_linux_error(retCode); + } + +#endif + + // adjust directory link count and size + dir->i_ctime = dir->i_mtime = NWFSGetSystemTime(); + if (dir->i_nlink) + dir->i_nlink--; + if (dir->i_size) + dir->i_size -= sizeof(ROOT); + mark_inode_dirty(dir); + + inode->i_nlink--; + inode->i_ctime = dir->i_ctime; + mark_inode_dirty(inode); + + d_delete(dentry); + + return 0; + +} + +int nwfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) dir->u.generic_ip; + register ULONG retCode; + ULONG DirNo; + register struct inode *inode; + register ino_t ino; + +#if (VFS_VERBOSE) + NWFSPrint("mkdir %s\n", dentry->d_name.name); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory in mkdir\n"); + return -ENOTDIR; + } + + if (!hash) + return -ENOENT; + + // if there is a name collision, then report that the directory exists + ino = get_directory_number(volume, name, namelen, dir->i_ino); + if (ino) + return -EEXIST; + + retCode = NWCreateDirectoryEntry(volume, (BYTE *)name, namelen, + SUBDIRECTORY, dir->i_ino, + NW_SUBDIRECTORY_FILE, + current->fsuid, + ((dir->i_mode & S_ISGID) + ? dir->i_gid + : current->fsgid), + 0, mode, &DirNo, + (ULONG) -1, 0, + (ULONG) -1, 0, + 0, 0); + if (retCode) + return (nwfs_to_linux_error(retCode)); + + if (!(inode = iget(dir->i_sb, DirNo)) < 0) + { + NWFSPrint("nwfs: iget failed in mkdir\n"); + return -EINVAL; + } + + inode->i_uid = current->fsuid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; + mark_inode_dirty(inode); + + // bump directory link count and size + dir->i_mtime = NWFSGetSystemTime(); + dir->i_nlink++; + dir->i_size += sizeof(ROOT); + mark_inode_dirty(dir); + + d_instantiate(dentry, inode); + + return 0; + +} + +int nwfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register struct inode *inode = dentry->d_inode; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *dirhash = (HASH *) dir->u.generic_ip; + register HASH *hash; + register ULONG retCode; + register ino_t ino; + DOS dosst; + register DOS *dos = &dosst; + +#if (VFS_VERBOSE) + NWFSPrint("rmdir %s\n", name); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory\n"); + return -ENOTDIR; + } + + if (!dirhash) + return -ENOENT; + + hash = get_directory_hash(volume, name, namelen, dir->i_ino); + if (!hash) + return -ENOENT; + ino = hash->DirNo; + + // don't allow DELETED.SAV to be removed from the root directory + if ((!hash->Parent) && (!NWFSCompare((BYTE *)name, "DELETED.SAV", 11))) + return -EPERM; + + retCode = ReadDirectoryRecord(volume, dos, ino); + if (retCode) + return -EIO; + +#if (SALVAGEABLE_FS) + retCode = NWShadowDirectoryEntry(volume, dos, hash); + if (retCode) + return nwfs_to_linux_error(retCode); + +#else + + // really delete the file from the volume + retCode = NWDeleteDirectoryEntryAndData(volume, dos, hash); + + if (retCode) + return nwfs_to_linux_error(retCode); +#endif + + // adjust directory link count and size + dir->i_mtime = NWFSGetSystemTime(); + if (dir->i_nlink) + dir->i_nlink--; + if (dir->i_size) + dir->i_size -= sizeof(ROOT); + mark_inode_dirty(dir); + + // if we are deleting the last instance of a busy directory + // then make directory empty + + inode->i_nlink = 0; // zap the link count + inode->i_size = 0; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); + + d_delete(dentry); + + return 0; +} + +int nwfs_rename(struct inode *oldDir, struct dentry *old_dentry, + struct inode *newDir, struct dentry *new_dentry) +{ + const char *newName = new_dentry->d_name.name; + size_t newLen = new_dentry->d_name.len; + const char *oldName = old_dentry->d_name.name; + size_t oldLen = old_dentry->d_name.len; + register VOLUME *volume = (VOLUME *) oldDir->i_sb->u.generic_sbp; + register HASH *odirhash = (HASH *) oldDir->u.generic_ip; + register HASH *ndirhash = (HASH *) newDir->u.generic_ip; + register HASH *hash; + register ULONG retCode, oldDirNo, newDirNo; + register ino_t ino; + DOS dosst; + register DOS *dos = &dosst; + +#if (VFS_VERBOSE) + NWFSPrint("rename %s -> %s\n", old_dentry->d_name.name, + new_dentry->d_name.name); +#endif + + if (!oldDir || !S_ISDIR(oldDir->i_mode)) + { + NWFSPrint("nwfs: old inode is NULL or not a directory\n"); + return -EBADF; + } + + if (!newDir || !S_ISDIR(newDir->i_mode)) + { + NWFSPrint("nwfs_rename: new inode is NULL or not a directory\n"); + return -EBADF; + } + + if (!odirhash) + return -ENOENT; + + if (!ndirhash) + return -ENOENT; + + oldDirNo = odirhash->DirNo; + newDirNo = ndirhash->DirNo; + + // if there is a name collision, then remove the target file + ino = get_directory_number(volume, newName, newLen, newDir->i_ino); + if (ino) + { + retCode = nwfs_unlink(newDir, new_dentry); + if (retCode) + return retCode; + } + + hash = get_directory_hash(volume, oldName, oldLen, oldDir->i_ino); + if (!hash) + return -ENOENT; + + // read source file record + retCode = ReadDirectoryRecord(volume, dos, oldDir->i_ino); + if (retCode) + return -EIO; + + retCode = NWRenameEntry(volume, dos, hash, (BYTE *)newName, newLen, + newDir->i_ino); + + if (retCode) + return (nwfs_to_linux_error(retCode)); + + // adjust old directory link count and size + oldDir->i_mtime = NWFSGetSystemTime(); + if (oldDir->i_nlink) + oldDir->i_nlink--; + if (oldDir->i_size) + oldDir->i_size -= sizeof(ROOT); + mark_inode_dirty(oldDir); + + // bump new directory link count and size + newDir->i_mtime = NWFSGetSystemTime(); + newDir->i_nlink++; + newDir->i_size += sizeof(ROOT); + mark_inode_dirty(newDir); + + return 0; +} + +int nwfs_symlink(struct inode *dir, struct dentry *dentry, const char *path) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) dir->u.generic_ip; + register ULONG retCode; + ULONG DirNo; + register struct inode *inode; + register ino_t ino; + +#if (VFS_VERBOSE) + NWFSPrint("symlink %s\n", dentry->d_name.name); +#endif + + // don't allow symlinks unless the NFS namespace is present + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + return -EPERM; + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory in symlink\n"); + return -EBADF; + } + + if (!hash) + return -ENOENT; + + // if there is a name collision, then report that the file exists + ino = get_directory_number(volume, name, namelen, dir->i_ino); + if (ino) + return -EEXIST; + + retCode = NWCreateDirectoryEntry(volume, (BYTE *)name, namelen, + 0, dir->i_ino, + NW_SYMBOLIC_FILE, + current->fsuid, + ((dir->i_mode & S_ISGID) + ? dir->i_gid + : current->fsgid), + 0, + (S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO), + &DirNo, + (ULONG) -1, 0, + (ULONG) -1, 0, + path, strlen(path)); + + if (retCode) + return (nwfs_to_linux_error(retCode)); + + if (!(inode = iget(dir->i_sb, DirNo)) < 0) + { + NWFSPrint("nwfs: iget failed in symlink\n"); + return -EBADF; + } + + // bump directory link count and size + dir->i_mtime = NWFSGetSystemTime(); + dir->i_nlink++; + dir->i_size += sizeof(ROOT); + mark_inode_dirty(dir); + + d_instantiate(dentry, inode); + + return 0; +} + +int nwfs_link(struct dentry *olddentry, struct inode *dir, struct dentry *dentry) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *dirhash = (HASH *) dir->u.generic_ip; + struct inode *oldinode = olddentry->d_inode; + register HASH *hash = (HASH *) oldinode->u.generic_ip; + register HASH *newHash; + register ULONG retCode; + ULONG DirNo, NFSDirNo, NewNFSDirNo; + register struct inode *inode; + register ino_t ino; + DOS dosst; + register DOS *dos = &dosst; + NFS nfsst; + register NFS *nfs = &nfsst; + NFS nfsNewst; + register NFS *nfsNew = &nfsNewst; + +#if (VFS_VERBOSE) + NWFSPrint("link %s\n", dentry->d_name.name); +#endif + + // don't allow hard links unless the NFS namespace is present + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + return -EPERM; + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory in hardlink\n"); + return -EBADF; + } + + // get the target file hash + if (!dirhash) + return -ENOENT; + + // get the target file hash + if (!hash) + return -ENOENT; + + if (hash->Flags & SUBDIRECTORY_FILE) + return -EPERM; + + // if there is a name collision, then report that the file exists + ino = get_directory_number(volume, name, namelen, dir->i_ino); + if (ino) + return -EEXIST; + + // get the nfs name space directory number for this file + NFSDirNo = get_namespace_directory_number(volume, hash, UNIX_NAME_SPACE); + if (NFSDirNo == (ULONG) -1) + return -ENOENT; + + retCode = ReadDirectoryRecord(volume, (DOS *)nfs, NFSDirNo); + if (retCode) + return -EIO; + + // read the root directory record + retCode = ReadDirectoryRecord(volume, dos, hash->DirNo); + if (retCode) + return -EIO; + + retCode = NWCreateDirectoryEntry(volume, (BYTE *)name, namelen, + 0, dir->i_ino, + NW_HARD_LINKED_FILE, + current->fsuid, + ((dir->i_mode & S_ISGID) + ? dir->i_gid + : current->fsgid), + nfs->rdev, nfs->mode, + &DirNo, + dos->FirstBlock, + dos->FileSize, + (ULONG) -1, 0, + 0, 0); + + if (retCode) + return (nwfs_to_linux_error(retCode)); + + // get the new file hash + newHash = get_directory_record(volume, DirNo); + if (!newHash) + return -ENOENT; + + // get the nfs name space directory number for this file + NewNFSDirNo = get_namespace_directory_number(volume, newHash, UNIX_NAME_SPACE); + if (NewNFSDirNo == (ULONG) -1) + return -ENOENT; + + // read new NFS record + retCode = ReadDirectoryRecord(volume, (DOS *)nfsNew, NewNFSDirNo); + if (retCode) + return -EIO; + + nfs->LinkedFlag = NFS_HASSTREAM_HARD_LINK; + nfs->FirstCreated = 0; +// nfs->nlinks++; + + nfsNew->LinkedFlag = NFS_HARD_LINK; + nfsNew->FirstCreated = 1; + nfsNew->mode = 0; + nfsNew->LinkEndDirNo = NFSDirNo; + + // write the new NFS record + retCode = WriteDirectoryRecord(volume, (DOS *)nfsNew, NewNFSDirNo); + if (retCode) + return -EIO; + + // write the root NFS record + retCode = WriteDirectoryRecord(volume, (DOS *)nfs, NFSDirNo); + if (retCode) + return -EIO; + + if (!(inode = iget(dir->i_sb, DirNo)) < 0) + { + NWFSPrint("nwfs: iget failed in link\n"); + return -EBADF; + } + + // bump directory link count and size + dir->i_mtime = NWFSGetSystemTime(); + dir->i_nlink++; + dir->i_size += sizeof(ROOT); + mark_inode_dirty(dir); + + d_instantiate(dentry, inode); + + return 0; + +} + +int nwfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) +{ + const char *name = dentry->d_name.name; + size_t namelen = dentry->d_name.len; + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) dir->u.generic_ip; + register ULONG retCode; + ULONG DirNo; + register struct inode *inode; + register ino_t ino; + +#if (VFS_VERBOSE) + NWFSPrint("mknod %s\n", dentry->d_name.name); +#endif + + // don't allow device files unless the NFS namespace is present + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + return -EPERM; + + if (!dir || !S_ISDIR(dir->i_mode)) + { + NWFSPrint("nwfs: inode is NULL or not a directory in mknod\n"); + return -EBADF; + } + + if (!hash) + return -ENOENT; + + // if there is a name collision, then report that the file exists + ino = get_directory_number(volume, name, namelen, dir->i_ino); + if (ino) + return -EEXIST; + + retCode = NWCreateDirectoryEntry(volume, (BYTE *)name, namelen, + 0, dir->i_ino, + NW_DEVICE_FILE, + current->fsuid, + ((dir->i_mode & S_ISGID) + ? dir->i_gid + : current->fsgid), + rdev, mode, + &DirNo, + (ULONG) -1, 0, + (ULONG) -1, 0, + 0, 0); + + if (retCode) + return (nwfs_to_linux_error(retCode)); + + if (!(inode = iget(dir->i_sb, DirNo)) < 0) + { + NWFSPrint("nwfs: iget failed in mknod\n"); + return -EBADF; + } + +#if (VFS_VERBOSE) + NWFSPrint("nwfs: mknod mode-%X rdev-%X inode-mode-%X\n", + (unsigned int)mode, (unsigned int)rdev, + (unsigned int)inode->i_mode); + + NWFSPrint("nwfs: IFBLK-%X IFCHR-%X IFLNK-%X\n", + (unsigned int)S_IFBLK,(unsigned int)S_IFCHR, + (unsigned int)S_IFLNK); +#endif + + // bump directory link count and size + dir->i_mtime = NWFSGetSystemTime(); + dir->i_nlink++; + dir->i_size += sizeof(ROOT); + mark_inode_dirty(dir); + + d_instantiate(dentry, inode); + + return 0; +} + + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/date.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/date.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/date.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/date.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,244 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : DATE.C +* DESCRIP : NWFS Netware and Unix Date/Time conversion routines +* DATE : January 30, 1999 +* +* +***************************************************************************/ + +#include "globals.h" + +ULONG MakeNWTime(ULONG second, ULONG minute, ULONG hour, + ULONG day, ULONG month, ULONG year) +{ + ULONG DateAndTime = 0; + + // 32-bit format for NetWare date and time + // Y - year bits + // M - month bits + // D - day bits + // H - hour bits + // m - minute bits + // S - second bits + // [ YYYYYYYM MMMDDDDD HHHHHmmm mmmSSSSS ] + + DateAndTime |= second >> 1; + DateAndTime |= minute << 5; + DateAndTime |= hour << 11; + DateAndTime |= day << 16; + DateAndTime |= month << 21; + + // year is delta of 1980 + year = year % 100; + if (year >= 80) + { + // year is relative to 1980 + DateAndTime |= (year - 80) << 25; + } + else + { + // year is relative to 2000 + DateAndTime |= (year + 80) << 25; + } + return DateAndTime; + +} + +void GetNWTime(ULONG DateAndTime, + ULONG *second, ULONG *minute, ULONG *hour, + ULONG *day, ULONG *month, ULONG *year) +{ + if (second) + *second = (DateAndTime & 0x1F) << 1; + if (minute) + *minute = (DateAndTime >> 5) & 0x3F; + if (hour) + *hour = (DateAndTime >> 11) & 0x1F; + if (day) + *day = (DateAndTime >> 16) & 0x1F; + if (month) + *month = (DateAndTime >> 21) & 0xF; + if (year) + { + *year = (DateAndTime >> 25); + if ((*year) >= 80) + *year = ((*year) - 80) + 2000; + else + *year = (*year) + 1980; + } + return; +} + + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +// +// NOTE: all dates in the Netware file system are relative to +// 1980. Novell's current date format can handle dates +// from 1980 through 2079. This means that NetWare has +// a year 2079 problem where the date format would be assumed +// to "flip" over from 2079 to the next century (i.e. the +// date format would be assumed to be 2080 through 2179). +// +// The date/time support routines in this modules all perform +// date calculations relative to the year 1980. This could easily +// be changed to become relative to 2080. +// + +ULONG NWFSGetSeconds(void) +{ + return CURRENT_TIME; +} + +ULONG NWFSGetSystemTime(void) +{ + return (CURRENT_TIME & ~3); +} + +ULONG NWFSSystemToNetwareTime(ULONG SystemTime) +{ + ULONG year, month, day, hour, minute, second; + + GetUnixTime(SystemTime, &second, &minute, &hour, &day, &month, &year); + return (MakeNWTime(second, minute, hour, day, month, year)); +} + +ULONG NWFSNetwareToSystemTime(ULONG NetwareTime) +{ + ULONG year, month, day, hour, minute, second; + + GetNWTime(NetwareTime, &second, &minute, &hour, &day, &month, &year); + return (MakeUnixTime(second, minute, hour, day, month, year)); +} + +// The time conversion portion of the functions below come from +// the fat file system. MakeUnixTime is derived from the +// mktime function. + +/* Linear day numbers of the respective 1sts in non-leap years. */ +int day_n[] = +{ + 0, 31, 59, 90, 120, 151, 181, 212, + 243, 273, 304, 334, 0, 0, 0, 0 +}; +/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + +extern struct timezone sys_tz; + +ULONG MakeUnixTime(ULONG second, ULONG minute, ULONG hour, + ULONG day, ULONG month, ULONG year) +{ + ULONG secs; + + year = year % 100; + if (year >= 80) + year -= 80; + else + year += 20; + + month = (month & 15) - 1; + secs = (second & 31) * 2 + 60 * (minute & 63) + hour * 3600 + 86400 * + ((day & 31) - 1 + day_n[month] + + (year / 4) + year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653); + + /* days since 1.1.70 plus 80's leap day */ + secs += sys_tz.tz_minuteswest * 60; + if (sys_tz.tz_dsttime) + { + secs -= 3600; + } + return secs; +} + +void GetUnixTime(ULONG unixdate, ULONG *second, ULONG *minute, ULONG *hour, + ULONG *day, ULONG *month, ULONG *year) +{ + int lday, lyear, nl_day, lmonth; + + unixdate -= sys_tz.tz_minuteswest * 60; + + if (sys_tz.tz_dsttime) + unixdate += 3600; + + if (second) + *second = (unixdate % 60) / 2; + if (minute) + *minute = (unixdate / 60) % 60; + if (hour) + *hour = (unixdate / 3600) % 24; + + lday = unixdate / 86400 - 3652; + lyear = lday / 365; + if ((lyear + 3) / 4 + 365 * lyear > lday) + lyear--; + + lday -= (lyear + 3) / 4 + 365 * lyear; + if ((lday == 59) && !(lyear & 3)) + { + nl_day = lday; + lmonth = 2; + } + else + { + nl_day = (lyear & 3) || lday <= 59 ? lday : lday - 1; + for (lmonth = 0; lmonth < 12; lmonth++) + { + if (day_n[lmonth] > nl_day) + break; + } + } + if (day) + *day = nl_day-day_n[lmonth - 1] + 1; + if (month) + *month = lmonth; + if (year) + *year = (lyear + 1980); + +} + +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/dir.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/dir.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/dir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/dir.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,248 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : DIR.C +* DESCRIP : NWFS VFS Dir Module for Linux +* DATE : December 5, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + + +int nwfs_dentry_validate(struct dentry *dentry, int flags) +{ + struct inode *inode = dentry->d_inode; + +#if (VERBOSE) + NWFSPrint("dentry validate\n"); +#endif + + if (!inode) + return 1; + + // see if this inode is the root entry + if (inode->i_sb->s_root->d_inode == inode) + return 1; + + // see if this inode is still valid. + if (is_bad_inode(inode)) + return 0; + + if (atomic_read(&dentry->d_count) > 1) + return 1; + + return 0; +} + +int nwfs_delete_dentry(struct dentry * dentry) +{ +#if (VERBOSE) + NWFSPrint("dentry delete\n"); +#endif + + if (!dentry->d_inode) + return 0; + + if (is_bad_inode(dentry->d_inode)) + return 1; + + return 0; +} + +struct dentry_operations nwfs_dentry_operations = +{ + d_revalidate: nwfs_dentry_validate, + d_delete: nwfs_delete_dentry, +}; + +struct file_operations nwfs_dir_operations = { + read: generic_read_dir, + readdir: nwfs_dir_readdir, + ioctl: nwfs_dir_ioctl, +}; + +struct inode_operations nwfs_dir_inode_operations = +{ + create: nwfs_create, + lookup: nwfs_dir_lookup, +// link: nwfs_link, // does not work at present. + unlink: nwfs_unlink, + symlink: nwfs_symlink, + mkdir: nwfs_mkdir, + rmdir: nwfs_rmdir, + mknod: nwfs_mknod, + rename: nwfs_rename, + setattr: nwfs_notify_change, +}; + +int nwfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + register ULONG i, count = 0; + struct inode *inode = filp->f_dentry->d_inode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = 0; + HASH *dirHash = 0; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -ENOTDIR; + + i = filp->f_pos; + switch (i) + { + case 0: + if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) + goto readdir_end; + filp->f_pos++; + count++; + case 1: + if (filldir(dirent, "..", 2, filp->f_pos, + filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + goto readdir_end; + filp->f_pos++; + count++; + + default: + while (1) + { + hash = get_subdirectory_record(volume, (filp->f_pos - 2), + inode->i_ino, + &dirHash); + if (!hash) + break; + + // provide name and root name space (MSDOS) record DirNo + if (filldir(dirent, hash->Name, hash->NameLength, + (hash->Root + 2), hash->Root, DT_UNKNOWN) < 0) + + goto readdir_end; + + filp->f_pos = (hash->Root + 2); + filp->f_pos++; + count++; + } + break; + } + +readdir_end:; + +#if (VERBOSE) + NWFSPrint("readdir count=%d pos1-%d pos2-%d\n", (int)count, + (int)i, (int)filp->f_pos); +#endif + + return count; +} + +int nwfs_dir_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + +#if (VERBOSE) + NWFSPrint("ioctl cmd-%d\n", (int)cmd); +#endif + + switch (cmd) + { + default: + return -EINVAL; + } + return 0; +} + +struct dentry *nwfs_dir_lookup(struct inode *dir, struct dentry *dentry) +{ + register VOLUME *volume = (VOLUME *) dir->i_sb->u.generic_sbp; + register ino_t ino; + struct inode **result = &(dentry->d_inode); + +#if (VERBOSE) + NWFSPrint("lookup %s\n", dentry->d_name.name); +#endif + + *result = NULL; + if (!dir) + return ERR_PTR(-ENOENT); + + if (!S_ISDIR(dir->i_mode)) + return ERR_PTR(-ENOENT); + + if ((dentry->d_name.len == 0) || ((dentry->d_name.name[0] == '.') && + (dentry->d_name.len == 1))) + { + *result = dir; + return 0; + } + + ino = get_directory_number(volume, + &dentry->d_name.name[0], + dentry->d_name.len, + dir->i_ino); + if (ino) + { + *result = iget(dir->i_sb, ino); + if (!(*result)) + { + d_add(dentry, NULL); // assume create or mkdir being attempted + dentry->d_time = 0; + dentry->d_op = &nwfs_dentry_operations; + return 0; + } + + d_add(dentry, *result); + dentry->d_time = 0; + dentry->d_op = &nwfs_dentry_operations; + return 0; + } + else + { + d_add(dentry, NULL); // assume create or mkdir being attempted + dentry->d_time = 0; + dentry->d_op = &nwfs_dentry_operations; + return 0; + } +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/disk.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/disk.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/disk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/disk.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,968 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : DISK.C +* DESCRIP : NWFS PC Platform Disk Support +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + + +ULONG TotalDisks = 0; +ULONG TotalNWParts = 0; +ULONG MaximumDisks = 0; +ULONG MaximumNWParts = 0; +ULONG FirstValidDisk = 0; + + +#if (MULTI_MACHINE_EMULATION) +#define TotalDisks machine->TotalDisks +#define TotalNWParts machine->TotalNWParts +#define MaximumDisks machine->MaximumDisks +#define MaximumNWParts machine->MaximumNWParts +#define FirstValidDisk machine->FirstValidDisk +uint8 disk_file[] = "./m2machXX/m2diskXX.dat"; +BYTE NwPartSignature[16] = { 0, 'N', 'w', '_', 'P', 'a', 'R', 't', 'I', + 't', 'I', 'o', 'N', 0, 0, 0 }; +#else + +extern NWDISK *SystemDisk[MAX_DISKS]; +uint8 disk_file[] = "m2diskXX.dat"; + +#endif + +// +// Linux Block Device Assignments +// +// Linux Defines 8 IDE + 2 ESDI + 16 SCSI = 26 disks total +// +// block device 3 (ATA and IDE Disks and CD-ROMs, 1st IDE Adapter) +// /dev/hda 3:0 +// /dev/hdb 3:64 +// +// block device 8 (SCSI Disks, 1st SCSI Adapter) +// /dev/sda 8:0 +// /dev/sdb 8:16 +// /dev/sdc 8:32 +// /dev/sdd 8:48 +// /dev/sde 8:64 +// /dev/sdf 8:80 +// /dev/sdg 8:96 +// /dev/sdh 8:112 +// +// /dev/sdi 8:128 +// /dev/sdj 8:144 +// /dev/sdk 8:160 +// /dev/sdl 8:176 +// /dev/sdm 8:192 +// /dev/sdn 8:208 +// /dev/sdo 8:224 +// /dev/sdp 8:240 +// +// block device 22 (ATA and IDE Disks and CD-ROMs, 2nd IDE Adapter) +// /dev/hdc 22:0 +// /dev/hdd 22:64 +// +// block device 33 (ATA and IDE Disks and CD-ROMs, 3rd IDE Adapter) +// /dev/hde 33:0 +// /dev/hdf 33:64 +// +// block device 34 (ATA and IDE Disks and CD-ROMs, 4th IDE Adapter) +// /dev/hdg 34:0 +// /dev/hdh 34:64 +// +// block device 36 (MCA ESDI Disks) +// /dev/eda 36:0 +// /dev/edb 36:64 +// +// Partition Types +// +// 0x01 FAT 12 Partition +// 0x02 Xenix Root Partition +// 0x03 Xenix Usr Partition +// 0x04 FAT 16 Partition < 32MB +// 0x05 Extended DOS Partition +// 0x06 FAT 16 Partition >= 32MB +// 0x07 IFS (HPFS) Partition +// 0x08 AIX Partition +// 0x09 AIX Boot Partition +// 0x0A OS/2 Boot Manager +// 0x0B FAT 32 Partition +// 0x0C FAT 32 Partition (Int 13 Extensions) +// 0x0E FAT 16 Partition (Win95 Int 13 Extensions) +// 0x0F Extended DOS Partition (Int 13 Extensions) +// 0x40 Venix 286 Partition +// 0x41 Power PC (PReP) Partition +// 0x51 Novell [???] +// 0x52 Microport/CPM Partition +// 0x57 VNDI Partition +// 0x63 Unix Partition (GNU Hurd) +// 0x64 Netware 286 Partition +// 0x65 Netware 386 Partition +// 0x66 Netware SMS Partition +// 0x69 Netware NSS Partition +// 0x75 PC/IX +// 0x77 VNDI Partition +// 0x80 MINIX Partition +// 0x81 Linux/MINIX Partition +// 0x82 Linux SWAP Partition +// 0x83 Linux Native Partition +// 0x93 Amoeba Partition +// 0x94 Amoeba Bad Block Table Partition +// 0xA5 BSD/386 Partition +// 0xB7 BSDI File System Partition +// 0xB8 BSDI Swap Partition +// 0xC0 NTFT Partition +// 0xC7 Syrinx Partition +// 0xDB CP/M Partition +// 0xE1 DOS access Parititon +// 0xE3 DOS R/O Partition +// 0xF2 DOS Secondary Partition +// 0xFF Bad Block Table Partition +// +// + + +// This function verifies the reported partition extants and checks +// for any overlapping or out of bounds partition definitions. + +extern ULONG FirstValidDisk; + +ULONG ValidatePartitionExtants(ULONG disk) +{ + register ULONG i; + register ULONG cEnd, nEnd, cStart, nStart, cSize, nSize; + +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + if ((!SystemDisk[disk]) || (!SystemDisk[disk]->PhysicalDiskHandle)) + return -1; + + for (i=0; i < 4; i++) + { + if (!SystemDisk[disk]->PartitionTable[i].SysFlag) + continue; + + if ((SystemDisk[disk]->PartitionTable[i].StartLBA + + SystemDisk[disk]->PartitionTable[i].nSectorsTotal) > (ULONG) + (SystemDisk[disk]->Cylinders * + SystemDisk[disk]->TracksPerCylinder * + SystemDisk[disk]->SectorsPerTrack)) + return -1; + + if (SystemDisk[disk]->PartitionTable[i].StartLBA < + SystemDisk[disk]->SectorsPerTrack) + return -1; + + if ((i + 1) < 4) + { + for (; (i + 1) < 4; i++) + { + if (SystemDisk[disk]->PartitionTable[i + 1].SysFlag) + { + cEnd = SystemDisk[disk]->PartitionTable[i].StartLBA + + SystemDisk[disk]->PartitionTable[i].nSectorsTotal; + nEnd = SystemDisk[disk]->PartitionTable[i + 1].StartLBA + + SystemDisk[disk]->PartitionTable[i + 1].nSectorsTotal; + cStart = SystemDisk[disk]->PartitionTable[i].StartLBA; + nStart = SystemDisk[disk]->PartitionTable[i + 1].StartLBA; + cSize = SystemDisk[disk]->PartitionTable[i].nSectorsTotal; + nSize = SystemDisk[disk]->PartitionTable[i + 1].nSectorsTotal; + + if ((cStart >= nStart) && (cStart < nEnd)) + return -1; + + if ((cEnd > nStart) && (cEnd < nEnd)) + return -1; + + if ((cStart < nStart) && (cEnd > nEnd)) + return -1; + } + } + } + } + return 0; + +} + +// +// Netware partitions use their own unique method for recording +// cyl/head/sector addressing for big partitions. This method +// is detailed below. +// + +ULONG SetPartitionTableGeometry(BYTE *hd, BYTE *sec, BYTE *cyl, + ULONG LBA, ULONG TracksPerCylinder, + ULONG SectorsPerTrack) +{ + ULONG offset, cylinders, head, sector; + +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + if (!cyl || !hd || !sec) + return -1; + + cylinders = (LBA / (TracksPerCylinder * SectorsPerTrack)); + offset = LBA % (TracksPerCylinder * SectorsPerTrack); + head = (WORD)(offset / SectorsPerTrack); + sector = (WORD)(offset % SectorsPerTrack) + 1; + + if (cylinders < 1023) + { + *sec = (BYTE)sector; + *hd = (BYTE)head; + *cyl = (BYTE)(cylinders & 0xff); + *sec |= (BYTE)((cylinders >> 2) & 0xC0); + } + else + { + *sec = (BYTE)(SectorsPerTrack | 0xC0); + *hd = (BYTE)(TracksPerCylinder - 1); + *cyl = (BYTE)0xFE; + } + + return 0; +} + +ULONG SetPartitionTableValues(struct PartitionTableEntry *Part, + ULONG Type, + ULONG StartingLBA, + ULONG EndingLBA, + ULONG Flag, + ULONG TracksPerCylinder, + ULONG SectorsPerTrack) +{ + + Part->SysFlag = (BYTE) Type; + Part->fBootable = (BYTE) Flag; + Part->StartLBA = StartingLBA; + Part->nSectorsTotal = (EndingLBA - StartingLBA) + 1; + + SetPartitionTableGeometry(&Part->HeadStart, &Part->SecStart, &Part->CylStart, + StartingLBA, TracksPerCylinder, SectorsPerTrack); + + SetPartitionTableGeometry(&Part->HeadEnd, &Part->SecEnd, &Part->CylEnd, + EndingLBA, TracksPerCylinder, SectorsPerTrack); + + return 0; + +} + +BYTE *get_partition_type(ULONG type) +{ + switch (type) + { + case 0x01: + return "FAT 12"; + + case 0x02: + return "Xenix Root"; + + case 0x03: + return "Xenix USR"; + + case 0x04: + return "FAT 16 < 32MB"; + + case 0x05: + return "Extended DOS"; + + case 0x06: + return "FAT 16 >= 32MB"; + + case 0x07: + return "IFS (HPFS/NTFS)"; + + case 0x08: + return "AIX Partition"; + + case 0x09: + return "AIX Boot"; + + case 0x0A: + return "OS/2 Boot Manager"; + + case 0x0B: + return "FAT 32"; + + case 0x0C: + return "FAT 32 (Int 13 Ext)"; + + case 0x0E: + return "FAT 16 (Int 13 Ext)"; + + case 0x0F: + return "Ext DOS (Int 13 Ext)"; + + case 0x40: + return "Venix 286"; + + case 0x41: + return "Power PC (PReP)"; + + case 0x51: + return "Novell [???]"; + + case 0x52: + return "Microport/CPM"; + + case 0x57: + return "NWFS"; + + case 0x63: + return "Unix (GNU Hurd)"; + + case 0x64: + return "Netware 286"; + + case 0x65: + return "Netware 386"; + + case 0x66: + return "Netware SMS"; + + case 0x75: + return "PC/IX"; + + case 0x77: + return "M2FS"; + + case 0x80: + return "MINIX"; + + case 0x81: + return "Linux/MINIX"; + + case 0x82: + return "LINUX SWAP"; + + case 0x83: + return "LINUX Native"; + + case 0x93: + return "Amoeba"; + + case 0x94: + return "Amoeba BBT"; + + case 0xA5: + return "BSD/386"; + + case 0xB7: + return "BSDI File System"; + + case 0xB8: + return "BSDI Swap"; + + case 0xC0: + return "NTFT"; + + case 0xC7: + return "Syrinx"; + + case 0xDB: + return "CP/M"; + + case 0xE1: + return "DOS access"; + + case 0xE3: + return "DOS R/O"; + + case 0xF2: + return "DOS Secondary"; + + case 0xFF: + return "BBT"; + + default: + return "Unknown"; + } +} + + +void GetNumberOfDisks(ULONG *disk_count) +{ +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + m2group_get_context(&machine); +#endif + if (disk_count) + *disk_count = TotalDisks; +} + +ULONG GetDiskInfo(ULONG disk_number, DISK_INFO *disk_info) +{ + register ULONG i; +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + + if (SystemDisk[disk_number] != 0) + { + disk_info->disk_number = disk_number; + disk_info->partition_count = 0; + + for (i=0; i < 4; i++) + { + if (SystemDisk[disk_number]->PartitionTable[i].nSectorsTotal != 0) + disk_info->partition_count ++; + } + + disk_info->total_sectors = (ULONG) + (SystemDisk[disk_number]->Cylinders * + SystemDisk[disk_number]->TracksPerCylinder * + SystemDisk[disk_number]->SectorsPerTrack); + + if ((disk_info->cylinder_size = (ULONG) + (SystemDisk[disk_number]->TracksPerCylinder * + SystemDisk[disk_number]->SectorsPerTrack)) == 0) + disk_info->cylinder_size = 0x40; + + disk_info->track_size = (ULONG) SystemDisk[disk_number]->SectorsPerTrack; + disk_info->bytes_per_sector = (ULONG) SystemDisk[disk_number]->BytesPerSector; + + return (0); + } + return (-1); +} + +ULONG GetPartitionInfo(ULONG disk_number, + ULONG partition_number, + PARTITION_INFO *part_info) +{ +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + if (SystemDisk[disk_number] != 0) + { + if (SystemDisk[disk_number]->PartitionTable[partition_number].nSectorsTotal != 0) + { + part_info->disk_number = disk_number; + part_info->partition_number = partition_number; + + part_info->total_sectors = (ULONG) + (SystemDisk[disk_number]->Cylinders * + SystemDisk[disk_number]->TracksPerCylinder * + SystemDisk[disk_number]->SectorsPerTrack); + + if ((part_info->cylinder_size = (ULONG) + (SystemDisk[disk_number]->TracksPerCylinder * + SystemDisk[disk_number]->SectorsPerTrack)) == 0) + part_info->cylinder_size = 0x40; + + part_info->partition_type = SystemDisk[disk_number]->PartitionTable[partition_number].SysFlag; + part_info->boot_flag = SystemDisk[disk_number]->PartitionTable[partition_number].fBootable; + part_info->sector_offset = SystemDisk[disk_number]->PartitionTable[partition_number].StartLBA; + part_info->sector_count = SystemDisk[disk_number]->PartitionTable[partition_number].nSectorsTotal; + + return (0); + } + } + return (-1); +} +#if (FILE_DISK_EMULATION) + +void RemoveDiskDevices(void) +{ + register ULONG j; +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; +#endif + for (j=0; j < MAX_DISKS; j++) + { + if (SystemDisk[j]) + { + m2_fclose((uint32) SystemDisk[j]->PhysicalDiskHandle); + NWFSFree(SystemDisk[j]); + SystemDisk[j] = 0; + if (TotalDisks) + TotalDisks--; + } + } +} + +uint32 quick_parse_disk_file( + uint8 *bptr, + uint32 *capacity, + uint32 *part_info) +{ + uint32 index = 0; + uint32 value; + uint32 base_index; + NWFSSet(part_info, 0, 16 * 4); + *capacity = 0; + while ((bptr[0] != 0) && (index < 16)) + { + if ((bptr[0] == '0') && ((bptr[1] == 'x') || (bptr[1] == 'X'))) + { + bptr += 2; + value = 0; + while (1) + { + if ((bptr[0] >= '0') && (bptr[0] <= '9')) + value = (value * 16) + (bptr[0] - '0'); + else + if ((bptr[0] >= 'a') && (bptr[0] <= 'f')) + value = (value * 16) + (bptr[0] - 'a') + 10; + else + if ((bptr[0] >= 'A') && (bptr[0] <= 'F')) + value = (value * 16) + (bptr[0] - 'A') + 10; + else + break; + bptr ++; + } + if ((index % 4) == 0) + { + base_index = value; + } + if (base_index < 4) + { + part_info[(base_index * 4) + (index % 4)] = value; + if ((index % 4) == 3) + { + if ((part_info[(base_index * 4) + 2] + part_info[(base_index * 4) + 3]) > *capacity) + *capacity = part_info[(base_index * 4) + 2] + part_info[(base_index * 4) + 3]; + } + + } + index ++; + } + bptr ++; + } + + return((*capacity == 0) ? -1 : 0); +} + +uint32 scan_init_flag = 0; +void ScanDiskDevices(void) +{ + uint32 i, j, k; + uint32 free_index; + uint32 retCode; + uint32 file_handle; + uint32 capacity; + uint8 *Sector; + uint32 part_info[16]; +#if (MULTI_MACHINE_EMULATION) + m2machine *machine; + NWDISK **SystemDisk; + m2group_get_context(&machine); + SystemDisk = (NWDISK **) &machine->LSystemDisk; + disk_file[8] = ((machine->file_number / 10) % 10) + '0'; + disk_file[9] = (machine->file_number % 10) + '0'; +#endif + + if (scan_init_flag == 0) + { + NWFSSet(&SystemDisk[0], 0, MAX_DISKS * 4); + scan_init_flag = 1; + } + + Sector = NWFSIOAlloc(IO_BLOCK_SIZE, DISKBUF_TAG); + + for (i=0; i<32; i++) + { + free_index = 0xFFFFFFFF; + for (j=0; jDiskNumber == i) + break; + } + else + { + if (free_index == 0xFFFFFFFF) + free_index = j; + } + } + if ((j == MAX_DISKS) && (free_index != 0xFFFFFFFF)) + { + j = free_index; +#if (MULTI_MACHINE_EMULATION) + disk_file[17] = ((i / 10) % 10) + '0'; + disk_file[18] = (i % 10) + '0'; +#else + disk_file[6] = ((i / 10) % 10) + '0'; + disk_file[7] = (i % 10) + '0'; +#endif + + if (m2_fopen(&file_handle, &disk_file[0], M2READ_WRITE) == 0) + { + Sector[510] = 0; + Sector[511] = 0; + fread(Sector, 1, 512, (FILE *) file_handle); + if ((Sector[510] != 0x55) || (Sector[511] != 0xAA)) + { + if (quick_parse_disk_file(Sector, &capacity, &part_info[0]) == 0) + { + for (k=0; k<4; k++) + { + if (part_info[(k * 4) + 1] != 0) + SetPartitionTableValues((PARTITION_INFO *) &Sector[(512-66) + (k*16)], part_info[(k*4)+1], part_info[(k*4)+2], part_info[(k*4)+3] + part_info[(k*4)+2] - 1, 0, 32, 32); + } + Sector[510] = 0x55; + Sector[511] = 0xAA; + m2_fwrite(file_handle, SECTOR_SIZE, 0, SECTORS_PER_BLOCK, (uint8 *) Sector); + m2_fwrite(file_handle, SECTOR_SIZE, capacity - SECTORS_PER_BLOCK, SECTORS_PER_BLOCK, (uint8 *) Sector); + } + } + + + capacity = m2_fsize(file_handle) / 512; + SystemDisk[j] = (NWDISK *) NWFSAlloc(sizeof(NWDISK), NWDISK_TAG); + NWFSSet(SystemDisk[j], 0, sizeof(NWDISK)); + + SystemDisk[j]->DiskNumber = i; + SystemDisk[j]->PhysicalDiskHandle = (void *) file_handle; + SystemDisk[j]->Cylinders = capacity / (32 * 32); + SystemDisk[j]->TracksPerCylinder = 32; + SystemDisk[j]->SectorsPerTrack = 32; + SystemDisk[j]->BytesPerSector = 512; + SystemDisk[j]->driveSize = (LONGLONG) + (SystemDisk[j]->Cylinders * + SystemDisk[j]->TracksPerCylinder * + SystemDisk[j]->SectorsPerTrack * + SystemDisk[j]->BytesPerSector); + TotalDisks ++; + + + + NWFSCopy(&SystemDisk[j]->partitionSignature, &Sector[0x01FE], 2); + + if (SystemDisk[j]->partitionSignature == 0xAA55) + { + NWFSCopy(&SystemDisk[j]->PartitionTable[0].fBootable, + &Sector[0x01BE], 64); + +// scan for Netware Partitions and detect 3.x and 4.x/5.x partition types + for (k=0; k < 4; k++) + { + if (SystemDisk[j]->PartitionTable[k].SysFlag == NETWARE_386_ID) + { + retCode = ReadDiskSectors(j, + SystemDisk[j]->PartitionTable[k].StartLBA, + Sector, + IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector, + IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector); + if (!retCode) + { + NWFSPrint("nwfs: disk-%d read error in ScanDiskDevices (part)\n", (int)j); + } + + if (!NWFSCompare(Sector, NwPartSignature, 16)) + SystemDisk[j]->PartitionVersion[k] = NW4X_PARTITION; + else + SystemDisk[j]->PartitionVersion[k] = NW3X_PARTITION; + } + } + } + } + } + } + NWFSFree(Sector); + return; +} + +#else + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +ULONG LocateDevice(kdev_t dev) +{ + register ULONG major = MAJOR(dev); + register ULONG minor = MINOR(dev); + register ULONG dev_number, end_minor; + struct gendisk *search; + +#if (LINUX_22 | LINUX_24) + lock_kernel(); +#endif + search = gendisk_head; + while (search) + { + if (search->major == major) + { + // get the minor device index + dev_number = (minor >> search->minor_shift); + + // determine the last valid minor device number +#if (LINUX_20 | LINUX_22) + end_minor = search->max_nr * search->max_p; +#elif (LINUX_24) + end_minor = search->max_p; +#endif + // check if this minor device is present + // and that it begins at sector 0 (Physical HDD Device) + if ((dev_number < end_minor) && (search->part) && + (search->part[dev_number].nr_sects)) + { +#if (VERBOSE) + NWFSPrint("dev-%s major-%d:%d ns-%d ss-%d t-%d\n", + search->major_name, (int)search->major,(int)minor, + (int)search->part[dev_number].nr_sects, + (int)search->part[dev_number].start_sect, + (int)search->part[dev_number].type); +#endif + +#if (LINUX_22 | LINUX_24) + unlock_kernel(); +#endif + return TRUE; + } +#if (LINUX_22 | LINUX_24) + unlock_kernel(); +#endif + return 0; + } + search = search->next; + } +#if (LINUX_22 | LINUX_24) + unlock_kernel(); +#endif + return 0; +} + +#endif + +extern ULONG MaxDisksSupported; +extern ULONG MaxHandlesSupported; + +void RemoveDiskDevices(void) +{ + register ULONG j; + + for (j=0; j < MAX_DISKS; j++) + { + if (SystemDisk[j]) + { + SyncDevice((ULONG)SystemDisk[j]->PhysicalDiskHandle); + blkdev_put(SystemDisk[j]->inode.i_bdev, BDEV_FILE); + NWFSFree(SystemDisk[j]); + SystemDisk[j] = 0; + if (TotalDisks) + TotalDisks--; + } + } +} + +extern struct blk_dev_struct blk_dev[MAX_BLKDEV]; +extern int *blk_size[MAX_BLKDEV]; +extern int *blksize_size[MAX_BLKDEV]; +extern int *hardsect_size[MAX_BLKDEV]; + +void ScanDiskDevices(void) +{ + register kdev_t dev; + register ULONG size; + register ULONG j, i, retCode, len, major, minor; + struct hd_geometry geometry; + struct page *page; + BYTE *Sector; + + page = alloc_page(GFP_ATOMIC); + if (!page) + return; + + Sector = (BYTE *)page_address(page); + if (!Sector) + { + NWFSPrint("nwfs: allocation error in AddDiskDevices\n"); + return; + } + + for (FirstValidDisk = (ULONG)-1, j = 0; j < MAX_DISKS; j++) + { + if (!SystemDisk[j]) + { + if (!DiskDevices[j]) + break; + + dev = DiskDevices[j]; + major = MAJOR(dev); + minor = MINOR(dev); + + // search the gendisk head and see if this device exists + if (!LocateDevice(dev)) + continue; + + SystemDisk[j] = (NWDISK *) NWFSAlloc(sizeof(NWDISK), NWDISK_TAG); + if (!SystemDisk[j]) + { + NWFSPrint("nwfs: memory allocation failure in AddDiskDevices\n"); + continue; + } + NWFSSet(SystemDisk[j], 0, sizeof(NWDISK)); + + init_special_inode(&SystemDisk[j]->inode, S_IFBLK | S_IRUSR, dev); + retCode = blkdev_open(&SystemDisk[j]->inode, &SystemDisk[j]->filp); + if (retCode) + { + if (SystemDisk[j]) + NWFSFree(SystemDisk[j]); + SystemDisk[j] = 0; + continue; + } + + // perform a get drive geometry call to determine if it's a hard + // disk or CDROM + +#if (LINUX_22 | LINUX_24) + lock_kernel(); +#endif + retCode = ioctl_by_bdev(SystemDisk[j]->inode.i_bdev, HDIO_GETGEO, + (ULONG)&geometry); +#if (LINUX_22 | LINUX_24) + unlock_kernel(); +#endif + + if (retCode) + { + if (SystemDisk[j]) + NWFSFree(SystemDisk[j]); + SystemDisk[j] = 0; + continue; + } + + set_blocksize(dev, LogicalBlockSize); + + if (FirstValidDisk == (ULONG)-1) + FirstValidDisk = j; + + SystemDisk[j]->DiskNumber = j; + SystemDisk[j]->DeviceBlockSize = LogicalBlockSize; + SystemDisk[j]->Cylinders = (LONGLONG) geometry.cylinders; + SystemDisk[j]->TracksPerCylinder = geometry.heads; + SystemDisk[j]->SectorsPerTrack = geometry.sectors; + SystemDisk[j]->PhysicalDiskHandle = (void *)((ULONG)dev); + SystemDisk[j]->BytesPerSector = hardsect_size[major] ? hardsect_size[major][minor] : 512; + + size = (blk_size[major] ? (ULONG) blk_size[major][minor] : (ULONG) blk_size[major]); + SystemDisk[j]->driveSize = (LONGLONG)((LONGLONG) size * + (LONGLONG) SystemDisk[j]->BytesPerSector); + + TotalDisks++; + if (TotalDisks > MaximumDisks) + MaximumDisks = TotalDisks; + + } + + retCode = ReadDiskSectors(j, 0, Sector, + IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector, + IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector); + if (!retCode) + { + NWFSPrint("nwfs: disk-%d read error in ScanDiskDevices\n", (int)j); + continue; + } + + len = SystemDisk[j]->BytesPerSector; + + NWFSCopy(&SystemDisk[j]->partitionSignature, + &Sector[0x01FE], 2); + + if (SystemDisk[j]->partitionSignature != 0xAA55) + { +#if (VERBOSE) + NWFSPrint("nwfs: partition signature 0xAA55 not found disk(%d)\n", j); +#endif + NWFSSet(&SystemDisk[j]->PartitionTable[0].fBootable, 0, 64); + continue; + } + else + { + NWFSCopy(&SystemDisk[j]->PartitionTable[0].fBootable, + &Sector[0x01BE], 64); + } + + // scan for Netware Partitions and detect 3.x and 4.x/5.x partition types + for (i=0; i < 4; i++) + { + if (SystemDisk[j]->PartitionTable[i].SysFlag == NETWARE_386_ID) + { + retCode = ReadDiskSectors(j, + SystemDisk[j]->PartitionTable[i].StartLBA, + Sector, + IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector, + IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector); + if (!retCode) + { + NWFSPrint("nwfs: disk-%d read error in ScanDiskDevices (part)\n", (int)j); + continue; + } + + if (!NWFSCompare(Sector, NwPartSignature, 16)) + SystemDisk[j]->PartitionVersion[i] = NW4X_PARTITION; + else + SystemDisk[j]->PartitionVersion[i] = NW3X_PARTITION; + } + } + } + __free_page(page); + return; +} + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/fat.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/fat.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/fat.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/fat.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,1512 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : FAT.C +* DESCRIP : NWFS FAT Module +* DATE : November 16, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +void NWLockFat(VOLUME *volume) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&volume->FatSemaphore) == -EINTR) + NWFSPrint("lock fat was interrupted\n"); +#endif +} + +void NWUnlockFat(VOLUME *volume) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&volume->FatSemaphore); +#endif +} + +MIRROR_LRU *RemoveFAT(VOLUME *volume, MIRROR_LRU *lru) +{ + NWLockFat(volume); + if (volume->FATListHead == lru) + { + volume->FATListHead = (void *) lru->next; + if (volume->FATListHead) + volume->FATListHead->prior = NULL; + else + volume->FATListTail = NULL; + } + else + { + lru->prior->next = lru->next; + if (lru != volume->FATListTail) + lru->next->prior = lru->prior; + else + volume->FATListTail = lru->prior; + } + if (volume->FATListBlocks) + volume->FATListBlocks--; + NWUnlockFat(volume); + return lru; + +} + +void InsertFAT(VOLUME *volume, MIRROR_LRU *lru) +{ + NWLockFat(volume); + if (!volume->FATListHead) + { + volume->FATListHead = lru; + volume->FATListTail = lru; + lru->next = lru->prior = 0; + } + else + { + volume->FATListTail->next = lru; + lru->next = 0; + lru->prior = volume->FATListTail; + volume->FATListTail = lru; + } + volume->FATListBlocks++; + NWUnlockFat(volume); + return; + +} + +void InsertFATTop(VOLUME *volume, MIRROR_LRU *lru) +{ + NWLockFat(volume); + if (!volume->FATListHead) + { + volume->FATListHead = lru; + volume->FATListTail = lru; + lru->next = lru->prior = 0; + } + else + { + lru->next = volume->FATListHead; + lru->prior = 0; + volume->FATListHead->prior = lru; + volume->FATListHead = lru; + } + volume->FATListBlocks++; + NWUnlockFat(volume); + return; + +} + +ULONG InitializeFAT_LRU(VOLUME *volume) +{ + volume->FATListHead = volume->FATListTail = 0; + volume->FATListBlocks = 0; + + volume->FATBlockHash = NWFSCacheAlloc(BLOCK_NUMBER_HASH_SIZE, FATHASH_TAG); + if (!volume->FATBlockHash) + return -1; + + volume->FATBlockHashLimit = NUMBER_OF_BLOCK_HASH_ENTRIES; + NWFSSet(volume->FATBlockHash, 0, BLOCK_NUMBER_HASH_SIZE); + + return 0; +} + +ULONG FreeFATLists(VOLUME *volume) +{ + register MIRROR_LRU *lru; + + while (volume->FATListHead) + { + lru = RemoveFAT(volume, (MIRROR_LRU *)volume->FATListHead); + if (lru) + { + NWFSFree(lru->CacheBuffer); + NWFSFree(lru); + } + } + + if (volume->FATBlockHash) + NWFSFree(volume->FATBlockHash); + volume->FATBlockHashLimit =0; + volume->FATBlockHash = 0; + + return 0; + +} + +#if (CACHE_FAT_TABLES) + +ULONG FreeFAT_LRU(VOLUME *volume) +{ + register MIRROR_LRU *lru; + + while (volume->FATListHead) + { + lru = volume->FATListHead; + volume->FATListHead = volume->FATListHead->next; + if (!volume->FATListHead) + volume->FATListTail = 0; + + if (lru->BlockState == L_DIRTY) + { + if (lru->Cluster1 != (ULONG) -1) + { + if (WritePhysicalVolumeCluster(volume, + lru->Cluster1, + lru->CacheBuffer, + lru->ClusterSize, + FAT_PRIORITY)) + { + NWFSPrint("dirty fat LRU block #%u [%X] write failed\n", + (unsigned int)lru->Cluster1, + (unsigned int)lru->Cluster1); + } + } + + if (lru->Cluster2 != (ULONG) -1) + { + if (WritePhysicalVolumeCluster(volume, + lru->Cluster2, + lru->CacheBuffer, + lru->ClusterSize, + FAT_PRIORITY)) + { + NWFSPrint("dirty fat LRU mirror #%u [%X] write failed\n", + (unsigned int)lru->Cluster2, (unsigned int)lru->Cluster2); + } + } + lru->BlockState = L_DATAVALID; + } + NWFSFree(lru->CacheBuffer); + NWFSFree(lru); + } + + if (volume->FATBlockHash) + NWFSFree(volume->FATBlockHash); + volume->FATBlockHashLimit =0; + volume->FATBlockHash = 0; + + return 0; + +} + +MIRROR_LRU *AllocateFAT_LRUElement(VOLUME *volume) +{ + register MIRROR_LRU *lru; + + lru = NWFSAlloc(sizeof(MIRROR_LRU), FATLRU_TAG); + if (!lru) + return 0; + + NWFSSet(lru, 0, sizeof(MIRROR_LRU)); + lru->BlockState = L_FREE; + lru->Cluster1 = -1; + lru->Cluster2 = -1; + lru->ClusterSize = volume->ClusterSize; + + lru->CacheBuffer = NWFSCacheAlloc(volume->ClusterSize, FAT_TAG); + if (!lru->CacheBuffer) + { + NWFSFree(lru); + return 0; + } + NWFSSet(lru->CacheBuffer, 0, volume->ClusterSize); + return lru; +} + +void FreeFAT_LRUElement(MIRROR_LRU *lru) +{ + if (lru->CacheBuffer) + NWFSFree(lru->CacheBuffer); + NWFSFree(lru); + return; +} + +ULONG FlushFAT(VOLUME *volume) +{ + register MIRROR_LRU *lru; + + lru = volume->FATListHead; + while (lru) + { + if (lru->BlockState == L_DIRTY) + { + + if (lru->Cluster1 != (ULONG) -1) + { + if (WritePhysicalVolumeCluster(volume, + lru->Cluster1, + lru->CacheBuffer, + lru->ClusterSize, + FAT_PRIORITY)) + continue; + } + + if (lru->Cluster2 != (ULONG) -1) + { + if (WritePhysicalVolumeCluster(volume, + lru->Cluster2, + lru->CacheBuffer, + lru->ClusterSize, + FAT_PRIORITY)) + continue; + } + lru->BlockState = L_DATAVALID; + } + lru = lru->next; + } + + return 0; +} + +ULONG FlushFATBuffer(VOLUME *volume, MIRROR_LRU *lru, ULONG cluster) +{ + register ULONG EntriesPerCluster; + register ULONG Offset, cbytes; + register FAT_ENTRY *Table; + ULONG retCode = 0; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Offset = cluster % EntriesPerCluster; + + Table = (FAT_ENTRY *) lru->CacheBuffer; + if (lru->Cluster1 != (ULONG) -1) + { + cbytes = WriteClusterWithOffset(volume, + lru->Cluster1, + Offset * sizeof(FAT_ENTRY), + (BYTE *)&Table[Offset], + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) + { + if (lru->Cluster2 != (ULONG) -1) + { +#if (!CREATE_FAT_MISMATCH) + cbytes = WriteClusterWithOffset(volume, + lru->Cluster2, + Offset * sizeof(FAT_ENTRY), + (BYTE *)&Table[Offset], + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) +#endif + return 0; + } + } + } + return -1; + +} + +ULONG WriteFATEntry(VOLUME *volume, MIRROR_LRU *lru, + FAT_ENTRY *fat, ULONG Cluster) +{ + register FAT_ENTRY *Table; + register ULONG EntriesPerCluster; + register ULONG Offset; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Offset = Cluster % EntriesPerCluster; + + Table = (FAT_ENTRY *) lru->CacheBuffer; + if (fat) + { + NWFSCopy(&Table[Offset], fat, sizeof(FAT_ENTRY)); + return 0; + } + return -1; +} + +MIRROR_LRU *CreateFatLRU(VOLUME *volume, ULONG cluster, + ULONG mirror, ULONG index) +{ + register MIRROR_LRU *lru; + register ULONG retCode; + + lru = AllocateFAT_LRUElement(volume); + if (lru) + { + retCode = ReadPhysicalVolumeCluster(volume, cluster, lru->CacheBuffer, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + FreeFAT_LRUElement(lru); + return 0; + } + lru->ModLock = 0; + lru->BlockState = L_DATAVALID; + lru->Cluster1 = cluster; + lru->Cluster2 = mirror; + lru->BlockIndex = index; + InsertFAT(volume, lru); + + retCode = AddToFATHash(volume, lru); + if (retCode) + { + RemoveFAT(volume, lru); + FreeFAT_LRUElement(lru); + return 0; + } + + retCode = SetAssignedClusterValue(volume, cluster, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set cluster-%X\n", + (unsigned int)cluster); + } + + retCode = SetAssignedClusterValue(volume, mirror, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set mirror-%X\n", + (unsigned int)mirror); + } + return lru; + } + return 0; + +} + +FAT_ENTRY *GetFatEntry(VOLUME *volume, ULONG Cluster, FAT_ENTRY *fat) +{ + register LRU_HASH_LIST *HashTable; + register FAT_ENTRY *Table; + register MIRROR_LRU *lru; + register ULONG hash; + register ULONG EntriesPerCluster; + register ULONG Block, Offset; + + if ((Cluster == (ULONG) -1) || (Cluster & 0x80000000)) + return 0; + + if (Cluster > (volume->MountedVolumeClusters - 1)) + return 0; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Block = Cluster / EntriesPerCluster; + Offset = Cluster % EntriesPerCluster; + + hash = (Block & (volume->FATBlockHashLimit - 1)); + HashTable = (LRU_HASH_LIST *) volume->FATBlockHash; + if (!HashTable) + { + return 0; + } + + lru = (MIRROR_LRU *) HashTable[hash].head; + while (lru) + { + if (lru->BlockIndex == Block) + { + Table = (FAT_ENTRY *) lru->CacheBuffer; + if (fat) + { + NWFSCopy(fat, &Table[Offset], sizeof(FAT_ENTRY)); + return fat; + } + return 0; + } + lru = lru->hashNext; + } + return 0; + +} + +FAT_ENTRY *GetFatEntryAndLRU(VOLUME *volume, ULONG Cluster, + MIRROR_LRU **rlru, FAT_ENTRY *fat) +{ + register LRU_HASH_LIST *HashTable; + register FAT_ENTRY *Table; + register MIRROR_LRU *lru; + register ULONG hash; + register ULONG EntriesPerCluster; + register ULONG Block, Offset; + + if ((Cluster == (ULONG) -1) || (Cluster & 0x80000000)) + return 0; + + if (Cluster > (volume->MountedVolumeClusters - 1)) + return 0; + + if (rlru) + *rlru = 0; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Block = Cluster / EntriesPerCluster; + Offset = Cluster % EntriesPerCluster; + + hash = (Block & (volume->FATBlockHashLimit - 1)); + HashTable = (LRU_HASH_LIST *) volume->FATBlockHash; + if (!HashTable) + return 0; + + lru = (MIRROR_LRU *) HashTable[hash].head; + while (lru) + { + if (lru->BlockIndex == Block) + { + Table = (FAT_ENTRY *) lru->CacheBuffer; + if (rlru) + *rlru = lru; + if (fat) + { + NWFSCopy(fat, &Table[Offset], sizeof(FAT_ENTRY)); + return fat; + } + return 0; + } + lru = lru->hashNext; + } + return 0; + +} + +ULONG ReadFATTable(VOLUME *volume) +{ + register MIRROR_LRU *lru; + register FAT_ENTRY *FAT1, *FAT2, *verify; + FAT_ENTRY FAT1_S, FAT2_S, VFAT_S; + register ULONG retCode; + register long index1, index2; + register ULONG Block, cluster1, cluster2, i, rebuild_flag = 0; + register ULONG last_cluster1, last_cluster2; + register BYTE *FATCopy; + + FATCopy = NWFSCacheAlloc(volume->ClusterSize, FAT_WORKSPACE_TAG); + if (!FATCopy) + return -3; + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Reading FAT Tables ***\n"); +#endif + +ReadTable:; + Block = 0; + last_cluster1 = 0; + last_cluster2 = 0; + cluster1 = volume->FirstFAT; + cluster2 = volume->SecondFAT; + + if (!cluster2) + { + NWFSPrint("ffat-%X sfat-%x fdir-%x sdir-%X\n", + (unsigned int) volume->FirstFAT, + (unsigned int) volume->SecondFAT, + (unsigned int) volume->FirstDirectory, + (unsigned int) volume->SecondDirectory); + + NWFSPrint("nwfs: second FAT is NULL\n"); + NWFSFree(FATCopy); + return -1; + } + + lru = CreateFatLRU(volume, cluster1, cluster2, Block); + if (!lru) + { + NWFSPrint("nwfs: could not allocate LRU element in ReadFATTables\n"); + NWFSFree(FATCopy); + return -1; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, FATCopy, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: could not read volume cluster in ReadFATTables\n"); + NWFSFree(FATCopy); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadFATTables\n"); + NWFSFree(FATCopy); + return -1; + } + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + while (TRUE) + { + if (NWFSCompare(lru->CacheBuffer, FATCopy, volume->ClusterSize)) + { + nwvp_fat_fix_info fix_info; + + // if we get a mirror mismatch, rebuild the + // FAT tables and attempt remount of the volume fat. + + // if we have already attempted fat table repair once, and it + // failed, then abort the mount and report a mirror mismatch. + + if (rebuild_flag) + { + extern void dumpRecordBytes(BYTE *, ULONG); + register BYTE *p = lru->CacheBuffer; + + for (i=0; i < (volume->ClusterSize / 64); i++) + { + if (NWFSCompare(&p[i * 64], &FATCopy[i * 64], 64)) + { + NWFSPrint("nwfs: FAT data mirror mismatch\n"); + NWFSPrint("offset into cluster is 0x%X (%u bytes)\n", + (unsigned)(i * 64), (unsigned)(i * 64)); + + NWFSPrint("index1-%d cluster1-[%08X] next1-[%08X]\n", (int)index1, + (unsigned int)cluster1, + (unsigned int)FAT1->FATCluster); + dumpRecordBytes(&p[i * 64], 64); + + NWFSPrint("index2-%d cluster2-[%08X] next2-[%08X]\n", (int)index2, + (unsigned int)cluster2, + (unsigned int)FAT2->FATCluster); + dumpRecordBytes(&FATCopy[i * 64], 64); + break; + } + } + NWFSFree(FATCopy); + return -3; + } + rebuild_flag++; + + NWFSPrint("nwfs: Fat Mismatch Volume %s - Recovering Fat Journal\n", + volume->VolumeName); + + FlushVolumeLRU(volume); + FreeFATLists(volume); + + retCode = nwvp_vpartition_fat_fix(volume->nwvp_handle, &fix_info, 1); + if (retCode) + { + NWFSPrint("nwfs: could not resolve volume fat table errors\n"); + NWFSFree(FATCopy); + return -3; + } + + retCode = InitializeFAT_LRU(volume); + if (retCode) + { + NWFSPrint("nwfs: could not allocate space for volume fat\n"); + NWFSFree(FATCopy); + return -3; + } + + goto ReadTable; + } + + if (FAT1->FATCluster == (ULONG) -1) + break; + + if (FAT2->FATCluster == (ULONG) -1) + break; + + if (!FAT1->FATCluster) + { + NWFSPrint("nwfs: Free Cluster Detected in FAT1 Chain\n"); + NWFSFree(FATCopy); + return -3; + } + + if (!FAT2->FATCluster) + { + NWFSPrint("nwfs: Free Cluster Detected in FAT2 Chain\n"); + NWFSFree(FATCopy); + return -3; + } + + if (FAT1->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in FAT1\n"); + NWFSFree(FATCopy); + return -3; + } + + if (FAT2->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in FAT2\n"); + NWFSFree(FATCopy); + return -3; + } + + Block++; + last_cluster1 = cluster1; + last_cluster2 = cluster2; + cluster1 = FAT1->FATCluster; + cluster2 = FAT2->FATCluster; + + if (last_cluster1 > cluster1) + { + NWFSPrint("nwfs: FAT1 chain overlaps on itself\n"); + NWFSFree(FATCopy); + return -1; + } + + if (last_cluster2 > cluster2) + { + NWFSPrint("nwfs: FAT2 chain overlaps on itself\n"); + NWFSFree(FATCopy); + return -1; + } + + lru = CreateFatLRU(volume, cluster1, cluster2, Block); + if (!lru) + { + NWFSPrint("nwfs: could not allocate LRU element in ReadFATTables\n"); + NWFSFree(FATCopy); + return -1; + } + + retCode = ReadPhysicalVolumeCluster(volume, + cluster2, + FATCopy, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error FAT2 returned %d\n", (int)retCode); + NWFSFree(FATCopy); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadFATTables\n"); + NWFSFree(FATCopy); + return -1; + } + + if (index1 > FAT1->FATIndex) + { + NWFSPrint("nwfs: FAT1 index overlaps on itself\n"); + NWFSFree(FATCopy); + return -1; + } + + if (index2 > FAT2->FATIndex) + { + NWFSPrint("nwfs: FAT2 index overlaps on itself\n"); + NWFSFree(FATCopy); + return -1; + } + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + } + NWFSFree(FATCopy); + + if (FAT1->FATCluster != FAT2->FATCluster) + { + NWFSPrint("nwfs: FAT Table chain mirror mismatch\n"); + return -3; + } + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Verifying FAT Tables ***\n"); +#endif + + for (i=0; i < volume->MountedVolumeClusters; i++) + { + verify = GetFatEntry(volume, i, &VFAT_S); + if (verify) + { + if (verify->FATCluster) + { + retCode = SetFreeClusterValue(volume, i, 1); // block is allocated + if (retCode) + { + NWFSPrint("nwfs: bit block value not set cluster-%X [1]\n", + (unsigned int)i); + } + + // this is a sanity check for ECC memory bit errors + if (!GetFreeClusterValue(volume, i)) + { + NWFSPrint("nwfs: bit block value incorrect cluster-%X [1]\n", + (unsigned int)i); + } + volume->VolumeAllocatedClusters++; + } + else + { + retCode = SetFreeClusterValue(volume, i, 0); // block is free + if (retCode) + { + NWFSPrint("nwfs: bit block value not set cluster-%X [0]\n", + (unsigned int)i); + } + + // this is a sanity check for ECC memory bit errors + if (GetFreeClusterValue(volume, i)) + { + NWFSPrint("nwfs: bit block value incorrect cluster-%X [0]\n", + (unsigned int)i); + } + volume->VolumeFreeClusters++; + } + } + else + { + NWFSPrint("nwfs: FAT Table data errors detected\n"); + return -1; + } + } + + return 0; + +} + +#else + +ULONG FreeFAT_LRU(VOLUME *volume) +{ + register MIRROR_LRU *lru; + + while (volume->FATListHead) + { + lru = RemoveFAT(volume, (MIRROR_LRU *)volume->FATListHead); + if (lru) + NWFSFree(lru); + } + + if (volume->FATBlockHash) + NWFSFree(volume->FATBlockHash); + volume->FATBlockHashLimit =0; + volume->FATBlockHash = 0; + + return 0; + +} + +MIRROR_LRU *AllocateFAT_LRUElement(VOLUME *volume) +{ + register MIRROR_LRU *lru; + + lru = NWFSAlloc(sizeof(MIRROR_LRU), FATLRU_TAG); + if (!lru) + return 0; + + NWFSSet(lru, 0, sizeof(MIRROR_LRU)); + lru->BlockState = L_FREE; + lru->Cluster1 = -1; + lru->Cluster2 = -1; + lru->ClusterSize = volume->ClusterSize; + + return lru; +} + +void FreeFAT_LRUElement(MIRROR_LRU *lru) +{ + NWFSFree(lru); + return; +} + +ULONG WriteFATEntry(VOLUME *volume, MIRROR_LRU *lru, + FAT_ENTRY *fat, ULONG Cluster) +{ + register ULONG EntriesPerCluster; + register ULONG Offset, cbytes; + ULONG retCode = 0; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Offset = Cluster % EntriesPerCluster; + + if (lru->Cluster1 != (ULONG) -1) + { + cbytes = WriteClusterWithOffset(volume, + lru->Cluster1, + Offset * sizeof(FAT_ENTRY), + (BYTE *)fat, + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) + { + if (lru->Cluster2 != (ULONG) -1) + { +#if (!CREATE_FAT_MISMATCH) + cbytes = WriteClusterWithOffset(volume, + lru->Cluster2, + Offset * sizeof(FAT_ENTRY), + (BYTE *)fat, + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) +#endif + return 0; + } + } + } + return -1; +} + +MIRROR_LRU *CreateFatLRU(VOLUME *volume, ULONG cluster, + ULONG mirror, ULONG index) +{ + register MIRROR_LRU *lru; + register ULONG retCode; + + lru = AllocateFAT_LRUElement(volume); + if (lru) + { + lru->ModLock = 0; + lru->BlockState = L_DATAVALID; + lru->Cluster1 = cluster; + lru->Cluster2 = mirror; + lru->BlockIndex = index; + InsertFAT(volume, lru); + + retCode = AddToFATHash(volume, lru); + if (retCode) + { + RemoveFAT(volume, lru); + FreeFAT_LRUElement(lru); + return 0; + } + + retCode = SetAssignedClusterValue(volume, cluster, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set cluster-%X\n", + (unsigned int)cluster); + } + + retCode = SetAssignedClusterValue(volume, mirror, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set mirror-%X\n", + (unsigned int)mirror); + } + return lru; + } + return 0; + +} + +FAT_ENTRY *GetFatEntry(VOLUME *volume, ULONG Cluster, FAT_ENTRY *fat) +{ + register LRU_HASH_LIST *HashTable; + register MIRROR_LRU *lru; + register ULONG hash, cbytes; + register ULONG EntriesPerCluster; + register ULONG Block, Offset; + ULONG retCode = 0; + + if ((Cluster == (ULONG) -1) || (Cluster & 0x80000000)) + return 0; + + if (Cluster > (volume->MountedVolumeClusters - 1)) + return 0; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Block = Cluster / EntriesPerCluster; + Offset = Cluster % EntriesPerCluster; + + hash = (Block & (volume->FATBlockHashLimit - 1)); + HashTable = (LRU_HASH_LIST *) volume->FATBlockHash; + if (!HashTable) + { + return 0; + } + + lru = (MIRROR_LRU *) HashTable[hash].head; + while (lru) + { + if (lru->BlockIndex == Block) + { + if (fat) + { + if (lru->Cluster1 != (ULONG) -1) + { + cbytes = ReadClusterWithOffset(volume, + lru->Cluster1, + Offset * sizeof(FAT_ENTRY), + (BYTE *)fat, + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) + return fat; + + if (lru->Cluster2 != (ULONG) -1) + { + cbytes = ReadClusterWithOffset(volume, + lru->Cluster2, + Offset * sizeof(FAT_ENTRY), + (BYTE *)fat, + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) + return fat; + } + } + } + return 0; + } + lru = lru->hashNext; + } + return 0; + +} + +FAT_ENTRY *GetFatEntryAndLRU(VOLUME *volume, ULONG Cluster, + MIRROR_LRU **rlru, FAT_ENTRY *fat) +{ + register LRU_HASH_LIST *HashTable; + register MIRROR_LRU *lru; + register ULONG hash, cbytes; + register ULONG EntriesPerCluster; + register ULONG Block, Offset; + ULONG retCode = 0; + + if ((Cluster == (ULONG) -1) || (Cluster & 0x80000000)) + return 0; + + if (Cluster > (volume->MountedVolumeClusters - 1)) + return 0; + + if (rlru) + *rlru = 0; + + EntriesPerCluster = volume->ClusterSize / sizeof(FAT_ENTRY); + Block = Cluster / EntriesPerCluster; + Offset = Cluster % EntriesPerCluster; + + hash = (Block & (volume->FATBlockHashLimit - 1)); + HashTable = (LRU_HASH_LIST *) volume->FATBlockHash; + if (!HashTable) + return 0; + + lru = (MIRROR_LRU *) HashTable[hash].head; + while (lru) + { + if (lru->BlockIndex == Block) + { + if (rlru) + *rlru = lru; + + if (fat) + { + if (lru->Cluster1 != (ULONG) -1) + { + cbytes = ReadClusterWithOffset(volume, + lru->Cluster1, + Offset * sizeof(FAT_ENTRY), + (BYTE *)fat, + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) + return fat; + + // if the read from the primary failed, then + // try to read from the mirrored fat tables + + if (lru->Cluster2 != (ULONG) -1) + { + cbytes = ReadClusterWithOffset(volume, + lru->Cluster2, + Offset * sizeof(FAT_ENTRY), + (BYTE *)fat, + sizeof(FAT_ENTRY), + KERNEL_ADDRESS_SPACE, + &retCode, + FAT_PRIORITY); + + if ((cbytes == sizeof(FAT_ENTRY)) && !retCode) + return fat; + } + } + } + return 0; + } + lru = lru->hashNext; + } + return 0; + +} + +ULONG ReadFATTable(VOLUME *volume) +{ + register MIRROR_LRU *lru; + register FAT_ENTRY *FAT1, *FAT2, *verify; + FAT_ENTRY FAT1_S, FAT2_S, VFAT_S; + register ULONG retCode; + register long index1, index2; + register ULONG Block, cluster1, cluster2, i, rebuild_flag = 0; + register ULONG last_cluster1, last_cluster2; + register BYTE *FATCopy, *FATPrimary; + + FATPrimary = NWFSCacheAlloc(volume->ClusterSize, FAT_WORKSPACE_TAG); + if (!FATPrimary) + return -3; + + FATCopy = NWFSCacheAlloc(volume->ClusterSize, FAT_WORKSPACE_TAG); + if (!FATCopy) + { + NWFSFree(FATPrimary); + return -3; + } + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Reading FAT Tables ***\n"); +#endif + +ReadTable:; + Block = 0; + last_cluster1 = 0; + last_cluster2 = 0; + cluster1 = volume->FirstFAT; + cluster2 = volume->SecondFAT; + + if (!cluster2) + { + NWFSPrint("ffat-%X sfat-%x fdir-%x sdir-%X\n", + (unsigned int) volume->FirstFAT, + (unsigned int) volume->SecondFAT, + (unsigned int) volume->FirstDirectory, + (unsigned int) volume->SecondDirectory); + + NWFSPrint("nwfs: second FAT is NULL\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + lru = CreateFatLRU(volume, cluster1, cluster2, Block); + if (!lru) + { + NWFSPrint("nwfs: could not allocate LRU element in ReadFATTables\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, FATPrimary, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: could not read volume cluster in ReadFATTables\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return retCode; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, FATCopy, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: could not read volume cluster in ReadFATTables\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadFATTables\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + while (TRUE) + { + if (NWFSCompare(FATPrimary, FATCopy, volume->ClusterSize)) + { + nwvp_fat_fix_info fix_info; + + // if we get a mirror mismatch, rebuild the + // FAT tables and attempt remount of the volume fat. + + // if we have already attempted fat table repair once, and it + // failed, then abort the mount and report a mirror mismatch. + + if (rebuild_flag) + { + extern void dumpRecordBytes(BYTE *, ULONG); + register BYTE *p = FATPrimary; + + for (i=0; i < (volume->ClusterSize / 64); i++) + { + if (NWFSCompare(&p[i * 64], &FATCopy[i * 64], 64)) + { + NWFSPrint("nwfs: FAT data mirror mismatch\n"); + NWFSPrint("offset into cluster is 0x%X (%u bytes)\n", + (unsigned)(i * 64), (unsigned)(i * 64)); + + NWFSPrint("index1-%d cluster1-[%08X] next1-[%08X]\n", (int)index1, + (unsigned int)cluster1, + (unsigned int)FAT1->FATCluster); + dumpRecordBytes(&p[i * 64], 64); + + NWFSPrint("index2-%d cluster2-[%08X] next2-[%08X]\n", (int)index2, + (unsigned int)cluster2, + (unsigned int)FAT2->FATCluster); + dumpRecordBytes(&FATCopy[i * 64], 64); + break; + } + } + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + rebuild_flag++; + + NWFSPrint("nwfs: Fat Mismatch Volume %s - Recovering Fat Journal\n", + volume->VolumeName); + + FlushVolumeLRU(volume); + FreeFATLists(volume); + + retCode = nwvp_vpartition_fat_fix(volume->nwvp_handle, &fix_info, 1); + if (retCode) + { + NWFSPrint("nwfs: could not resolve volume fat table errors\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + + retCode = InitializeFAT_LRU(volume); + if (retCode) + { + NWFSPrint("nwfs: could not allocate space for volume fat\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + + goto ReadTable; + } + + if (FAT1->FATCluster == (ULONG) -1) + break; + + if (FAT2->FATCluster == (ULONG) -1) + break; + + if (!FAT1->FATCluster) + { + NWFSPrint("nwfs: Free Cluster Detected in FAT1 Chain\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + + if (!FAT2->FATCluster) + { + NWFSPrint("nwfs: Free Cluster Detected in FAT2 Chain\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + + if (FAT1->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in FAT1\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + + if (FAT2->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in FAT2\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -3; + } + + Block++; + last_cluster1 = cluster1; + last_cluster2 = cluster2; + cluster1 = FAT1->FATCluster; + cluster2 = FAT2->FATCluster; + + if (last_cluster1 > cluster1) + { + NWFSPrint("nwfs: FAT1 chain overlaps on itself\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + if (last_cluster2 > cluster2) + { + NWFSPrint("nwfs: FAT2 chain overlaps on itself\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + lru = CreateFatLRU(volume, cluster1, cluster2, Block); + if (!lru) + { + NWFSPrint("nwfs: could not allocate LRU element in ReadFATTables\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + retCode = ReadPhysicalVolumeCluster(volume, + cluster1, + FATPrimary, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error FAT1 returned %d\n", (int)retCode); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return retCode; + } + + retCode = ReadPhysicalVolumeCluster(volume, + cluster2, + FATCopy, + volume->ClusterSize, + FAT_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error FAT2 returned %d\n", (int)retCode); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadFATTables\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + if (index1 > FAT1->FATIndex) + { + NWFSPrint("nwfs: FAT1 index overlaps on itself\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + if (index2 > FAT2->FATIndex) + { + NWFSPrint("nwfs: FAT2 index overlaps on itself\n"); + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + return -1; + } + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + } + NWFSFree(FATPrimary); + NWFSFree(FATCopy); + + if (FAT1->FATCluster != FAT2->FATCluster) + { + NWFSPrint("nwfs: FAT Table chain mirror mismatch\n"); + return -3; + } + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Verifying FAT Tables ***\n"); +#endif + + for (i=0; i < volume->MountedVolumeClusters; i++) + { + verify = GetFatEntry(volume, i, &VFAT_S); + if (verify) + { + if (verify->FATCluster) + { + retCode = SetFreeClusterValue(volume, i, 1); // block is allocated + if (retCode) + { + NWFSPrint("nwfs: bit block value not set cluster-%X [1]\n", + (unsigned int)i); + } + + // this is a sanity check for ECC memory bit errors + if (!GetFreeClusterValue(volume, i)) + { + NWFSPrint("nwfs: bit block value incorrect cluster-%X [1]\n", + (unsigned int)i); + } + volume->VolumeAllocatedClusters++; + } + else + { + retCode = SetFreeClusterValue(volume, i, 0); // block is free + if (retCode) + { + NWFSPrint("nwfs: bit block value not set cluster-%X [0]\n", + (unsigned int)i); + } + + // this is a sanity check for ECC memory bit errors + if (GetFreeClusterValue(volume, i)) + { + NWFSPrint("nwfs: bit block value incorrect cluster-%X [0]\n", + (unsigned int)i); + } + volume->VolumeFreeClusters++; + } + } + else + { + NWFSPrint("nwfs: FAT Table data errors detected\n"); + return -1; + } + } + return 0; + +} + +#endif + +ULONG AddToFATHash(VOLUME *volume, MIRROR_LRU *lru) +{ + register ULONG hash; + register LRU_HASH_LIST *HashTable; + + // This hash works on FAT sequence index. The Directory + // Hash is identical in structure. This method allows very + // rapid table searches of the directory file and the FAT + + NWLockFat(volume); + hash = (lru->BlockIndex & (volume->FATBlockHashLimit - 1)); + HashTable = (LRU_HASH_LIST *) volume->FATBlockHash; + if (HashTable) + { + if (!HashTable[hash].head) + { + HashTable[hash].head = lru; + HashTable[hash].tail = lru; + lru->hashNext = lru->hashPrior = 0; + } + else + { + HashTable[hash].tail->hashNext = lru; + lru->hashNext = 0; + lru->hashPrior = HashTable[hash].tail; + HashTable[hash].tail = lru; + } + NWUnlockFat(volume); + return 0; + } + NWUnlockFat(volume); + return -1; +} + +ULONG RemoveFATHash(VOLUME *volume, MIRROR_LRU *lru) +{ + register ULONG hash; + register LRU_HASH_LIST *HashTable; + + NWLockFat(volume); + hash = (lru->BlockIndex & (volume->FATBlockHashLimit - 1)); + HashTable = (LRU_HASH_LIST *) volume->FATBlockHash; + if (HashTable) + { + if (HashTable[hash].head == lru) + { + HashTable[hash].head = lru->hashNext; + if (HashTable[hash].head) + HashTable[hash].head->hashPrior = NULL; + else + HashTable[hash].tail = NULL; + } + else + { + lru->hashPrior->hashNext = lru->hashNext; + if (lru != HashTable[hash].tail) + lru->hashNext->hashPrior = lru->hashPrior; + else + HashTable[hash].tail = lru->hashPrior; + } + NWUnlockFat(volume); + return 0; + } + NWUnlockFat(volume); + return -1; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/file.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/file.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/file.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/file.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,720 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : FILE.C +* DESCRIP : NWFS VFS File Module for Linux +* DATE : December 6, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + + +extern ULONG nwfs_to_linux_error(ULONG NwfsError); + +int nwfs_open(struct inode *inode, struct file *file) +{ + // clear read ahead info + file->private_data = NULL; + return 0; +} + +int nwfs_close(struct inode *inode, struct file *file) +{ + register ULONG retCode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + DOS dos; + +#if (VFS_VERBOSE) + NWFSPrint("nwfs: close called\n"); +#endif + + // clear read ahead info + file->private_data = NULL; + + // We perform a truncate operation on the file during close to force + // allocation of a suballoc element. We do not allocate suballoc + // elements during write because this results in excessive copying + // and impacts performance very significantly . We actualy perform the + // suballocation only when we A) truncate a file, or B) close a file. + // In the case of close, we simply truncate the cluster chain to + // the reported file size. + + // if suballocation is disabled for this volume, then exit. + if (!(volume->VolumeFlags & SUB_ALLOCATION_ON)) + return 0; + + if (!hash) + return 0; + + NWLockFileExclusive(hash); + + // see if the modified flag was set for this file. if not, then + // the file is unchanged so we will exit. + if (!(hash->State & NWFS_MODIFIED)) + { + NWUnlockFile(hash); + return 0; + } + // clear modified flag + hash->State &= ~NWFS_MODIFIED; + + retCode = ReadDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) read dir error [%d]\n", + (int)inode->i_ino, (int)retCode); + return -EIO; + } + + // if this file does not allow suballocation, then exit. + if ((dos.FileAttributes & NO_SUBALLOC) || (dos.FileAttributes & TRANSACTION)) + { + NWUnlockFile(hash); + return 0; + } + + // if the fat chain is already empty, then don't try to truncate + // the file. Truncating the file to it's current filesize will + // force a suballocation. + + hash->TurboFATCluster = 0; + hash->TurboFATIndex = 0; + + retCode = TruncateClusterChain(volume, + &dos.FirstBlock, + 0, + 0, + inode->i_size, + TRUE, + dos.FileAttributes); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: error in truncate cluster chain (%d)\n", + (int)retCode); + return 0; + } + + // set file to new size. + dos.FileSize = inode->i_size; + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = dos.FirstBlock; + hash->FileSize = dos.FileSize; +#endif + + retCode = WriteDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + return 0; + } + + NWUnlockFile(hash); + return 0; +} + +int nwfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + register struct inode *inode = dentry->d_inode; + register VOLUME *volume = inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + register ULONG ccode = 0; + extern ULONG NWSyncFile(VOLUME *, HASH *); + + if (!hash) + return 0; + + NWLockFileExclusive(hash); + ccode = NWSyncFile(volume, hash); + NWUnlockFile(hash); + +#if (!DO_ASYNCH_IO && LINUX_BUFFER_CACHE) + // if we are double buffering in the Linux buffer cache, then flush + // any disks currently owned by NWFS + SyncDisks(); +#endif + + if (ccode) + ccode = -EPERM; + return ccode; +} + +void nwfs_truncate(struct inode *inode) +{ + register ULONG retCode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + DOS dos; + + if (!hash) + return; + + NWLockFileExclusive(hash); + + retCode = ReadDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) read dir error [%d]\n", + (int)inode->i_ino, (int)retCode); + return; + } + + // if the fat chain is already empty, then don't try to truncate + // the file + + hash->TurboFATCluster = 0; + hash->TurboFATIndex = 0; + + retCode = TruncateClusterChain(volume, + &dos.FirstBlock, + 0, + 0, + inode->i_size, + (volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0, + dos.FileAttributes); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: error in truncate cluster chain (%d)\n", + (int)retCode); + return; + } + +#if (VFS_VERBOSE) + NWFSPrint("truncate: FileSize(%d) -> NewSize(%d)\n", + (int)dos.FileSize, (int)inode->i_size); +#endif + + // set file to new size. + dos.FileSize = inode->i_size; + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = dos.FirstBlock; + hash->FileSize = dos.FileSize; +#endif + + // update NetWare directory entry with modified date and time + dos.LastUpdatedDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + + retCode = WriteDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + return; + } + + inode->i_mtime = NWFSGetSystemTime(); + mark_inode_dirty(inode); + + NWUnlockFile(hash); + return; +} + +int nwfs_file_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + register ULONG len, offset, next; + ULONG retCode; +#if (!HASH_FAT_CHAINS) + DOS dos; +#endif + off_t pos; + + pos = *ppos; + if ((pos + count) > inode->i_size) + count = inode->i_size - pos; + + if (count <= 0) + return 0; + + if (!hash) + return 0; + + NWLockFile(hash); + +#if (!HASH_FAT_CHAINS) + retCode = ReadDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) file read error [%d]\n", + (int)inode->i_ino, (int)retCode); + return -EIO; + } +#endif + + offset = (ULONG) pos; + next = (ULONG)file->private_data; + if (next == offset) + hash->State |= NWFS_SEQUENTIAL; + else + hash->State &= ~NWFS_SEQUENTIAL; + file->private_data = (void *)(offset + count); + + len = NWReadFile(volume, +#if (HASH_FAT_CHAINS) + &hash->FirstBlock, + hash->Flags, + hash->FileSize, +#else + &dos.FirstBlock, + dos.Flags, + dos.FileSize, +#endif + offset, + buf, + count, +#if (TURBO_FAT_ON) + &hash->TurboFATCluster, + &hash->TurboFATIndex, +#else + 0, 0, +#endif + &retCode, + USER_ADDRESS_SPACE, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0), +#if (HASH_FAT_CHAINS) + hash->FileAttributes, +#else + dos.FileAttributes, +#endif + (hash->State & NWFS_SEQUENTIAL) ? TRUE : 0); + +#if (VFS_VERBOSE) + NWFSPrint("read_file: context-%08X index-%08X offset-%d size-%d\n", + (unsigned int)hash->TurboFATCluster, + (unsigned int)hash->TurboFATIndex, + (int)offset, (int)count); +#endif + + if (retCode) + { + NWUnlockFile(hash); + return (nwfs_to_linux_error(retCode)); + } + + *ppos = (pos + len); + if (!IS_RDONLY(inode)) + { + inode->i_atime = NWFSGetSystemTime(); + mark_inode_dirty(inode); + } + + NWUnlockFile(hash); + return len; + +} + +int nwfs_read_file_link(struct inode *inode, char *buf, size_t count, + loff_t *ppos) +{ + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + register ULONG len, offset; + ULONG retCode; +#if (!HASH_FAT_CHAINS) + DOS dos; +#endif + off_t pos; + + pos = *ppos; + if ((pos + count) > inode->i_size) + count = inode->i_size - pos; + + if (count <= 0) + return 0; + + if (!hash) + return 0; + + NWLockFile(hash); + +#if (!HASH_FAT_CHAINS) + retCode = ReadDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) file read error [%d]\n", + (int)inode->i_ino, (int)retCode); + return -EIO; + } +#endif + + offset = (ULONG) pos; + len = NWReadFile(volume, +#if (HASH_FAT_CHAINS) + &hash->FirstBlock, + hash->Flags, + hash->FileSize, +#else + &dos.FirstBlock, + dos.Flags, + dos.FileSize, +#endif + offset, + buf, + count, +#if (TURBO_FAT_ON) + &hash->TurboFATCluster, + &hash->TurboFATIndex, +#else + 0, 0, +#endif + &retCode, + KERNEL_ADDRESS_SPACE, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0), +#if (HASH_FAT_CHAINS) + hash->FileAttributes, +#else + dos.FileAttributes, +#endif + (hash->State & NWFS_SEQUENTIAL) ? TRUE : 0); + +#if (VFS_VERBOSE) + NWFSPrint("read_kernel_file: ctx-%08X ndx-%08X off-%d sz-%d rc-%d len-%d\n", + (unsigned int)hash->TurboFATCluster, + (unsigned int)hash->TurboFATIndex, + (int)offset, (int)count, (int)retCode, (int)len); +#endif + + if (retCode) + { + NWUnlockFile(hash); + return (nwfs_to_linux_error(retCode)); + } + + *ppos = (pos + len); + if (!IS_RDONLY(inode)) + { + inode->i_atime = NWFSGetSystemTime(); + mark_inode_dirty(inode); + } + + NWUnlockFile(hash); + return len; + +} + +int nwfs_file_read_kernel(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + register ULONG len, offset, next; + ULONG retCode; +#if (!HASH_FAT_CHAINS) + DOS dos; +#endif + off_t pos; + + pos = *ppos; + if ((pos + count) > inode->i_size) + count = inode->i_size - pos; + + if (count <= 0) + return 0; + + if (!hash) + return 0; + + NWLockFile(hash); + +#if (!HASH_FAT_CHAINS) + retCode = ReadDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) file read error [%d]\n", + (int)inode->i_ino, (int)retCode); + return -EIO; + } +#endif + + offset = (ULONG) pos; + next = (ULONG)file->private_data; + if (next == offset) + hash->State |= NWFS_SEQUENTIAL; + else + hash->State &= ~NWFS_SEQUENTIAL; + file->private_data = (void *)(offset + count); + + len = NWReadFile(volume, +#if (HASH_FAT_CHAINS) + &hash->FirstBlock, + hash->Flags, + hash->FileSize, +#else + &dos.FirstBlock, + dos.Flags, + dos.FileSize, +#endif + offset, + buf, + count, +#if (TURBO_FAT_ON) + &hash->TurboFATCluster, + &hash->TurboFATIndex, +#else + 0, 0, +#endif + &retCode, + KERNEL_ADDRESS_SPACE, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0), +#if (HASH_FAT_CHAINS) + hash->FileAttributes, +#else + dos.FileAttributes, +#endif + (hash->State & NWFS_SEQUENTIAL) ? TRUE : 0); + +#if (VFS_VERBOSE) + NWFSPrint("read_kernel_file: context-%08X index-%08X offset-%d size-%d\n", + (unsigned int)hash->TurboFATCluster, + (unsigned int)hash->TurboFATIndex, + (int)offset, (int)count); +#endif + + if (retCode) + { + NWUnlockFile(hash); + return (nwfs_to_linux_error(retCode)); + } + + *ppos = (pos + len); + if (!IS_RDONLY(inode)) + { + inode->i_atime = NWFSGetSystemTime(); + mark_inode_dirty(inode); + } + + NWUnlockFile(hash); + return len; + +} + +int nwfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + ULONG retCode; + register ULONG len = 0; + DOS dos; + off_t pos; + + if (inode == NULL) + { + NWFSPrint("nwfs: inode = NULL\n"); + return -EINVAL; + } + + if (count <= 0) + return 0; + + pos = *ppos; + if (file->f_flags & O_APPEND) + { + pos = inode->i_size; + } + + if (!hash) + return -ENOENT; + + NWLockFileExclusive(hash); + + retCode = ReadDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) file write error [%d]\n", + (int)inode->i_ino, (int)retCode); + return -ENOENT; + } + + len = NWWriteFile(volume, + &dos.FirstBlock, + dos.Flags, + pos, + (void *)buf, + count, +#if (TURBO_FAT_ON) + &hash->TurboFATCluster, + &hash->TurboFATIndex, +#else + 0, 0, +#endif + &retCode, + USER_ADDRESS_SPACE, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0), + dos.FileAttributes); +#if (VFS_VERBOSE) + NWFSPrint("write_file: context-%08X index-%08X offset-%d size-%d\n", + (unsigned int)hash->TurboFATCluster, + (unsigned int)hash->TurboFATIndex, + (int)pos, (int)count); +#endif + + if (retCode) + { + NWUnlockFile(hash); + return (nwfs_to_linux_error(retCode)); + } + + pos += len; + *ppos = pos; + if (pos > inode->i_size) + { + inode->i_size = pos; + // file size changed, update directory entry + dos.FileSize = pos; + } + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = dos.FirstBlock; + hash->FileSize = dos.FileSize; +#endif + + // update NetWare directory entry with modified date and time + + dos.LastUpdatedDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + + retCode = WriteDirectoryRecord(volume, &dos, inode->i_ino); + if (retCode) + { + NWUnlockFile(hash); + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + return -EIO; + } + + // set the modified flag so close will know to perform suballocation + // of this file stream. + hash->State |= NWFS_MODIFIED; + + // update the modified time for this file. + inode->i_mtime = NWFSGetSystemTime(); + mark_inode_dirty(inode); + + NWUnlockFile(hash); + return len; + +} + +int nwfs_permission(struct inode *inode, int mask) +{ + unsigned short mode = inode->i_mode; + + // Nobody gets write access to a file on a readonly-fs + if ((mask & S_IWOTH) && (S_ISREG(mode) || S_ISDIR(mode) || + S_ISLNK(mode)) && IS_RDONLY(inode)) + return -EROFS; + + // Nobody gets write access to an immutable file +#ifndef CONFIG_VSERVERCTX + if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) +#else + if ((mask & S_IWOTH) && IS_IMMUTABLE_FILE(inode)) +#endif + return -EACCES; + // If no ACL, checks using the file mode + else + if (current->fsuid == inode->i_uid) + mode >>= 6; + else + if (in_group_p (inode->i_gid)) + mode >>= 3; + + // Access is always granted for root. We now check last, + // though, for BSD process accounting correctness + + if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE)) + return 0; + + if ((mask == S_IROTH) || (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH)))) + if (capable(CAP_DAC_READ_SEARCH)) + return 0; + + return -EACCES; +} + +struct file_operations nwfs_file_operations = +{ +#if (PAGE_CACHE_ON) + read: generic_file_read, + write: generic_file_write, +#else + read: nwfs_file_read, + write: nwfs_file_write, +#endif + ioctl: nwfs_ioctl, + mmap: generic_file_mmap, + open: nwfs_open, + release: nwfs_close, + fsync: nwfs_fsync +}; + +struct inode_operations nwfs_file_inode_operations = +{ + truncate: nwfs_truncate, + permission: nwfs_permission, + setattr: nwfs_notify_change, +}; + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/globals.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/globals.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/globals.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/globals.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,709 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : GLOBALS.C +* DESCRIP : NWFS Global Code Variables +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +// memory tracking labels + +TRACKING HOTFIX_TRACKING = { "HTFX", 0, 0 }; +TRACKING HOTFIX_DATA_TRACKING = { "HFDT", 0, 0 }; +TRACKING HOTFIX_TABLE_TRACKING = { "HFTB", 0, 0 }; +TRACKING MIRROR_TRACKING = { "MIRR", 0, 0 }; +TRACKING MIRROR_DATA_TRACKING = { "MIRD", 0, 0 }; +TRACKING HASH_TRACKING = { "HASH", 0, 0 }; +TRACKING EXT_HASH_TRACKING = { "EHSH", 0, 0 }; +TRACKING BITBLOCK_TRACKING = { "BITB", 0, 0 }; +TRACKING BITBUFFER_TRACKING = { "BBUF", 0, 0 }; +TRACKING NWPART_TRACKING = { "PART", 0, 0 }; +TRACKING NWDISK_TRACKING = { "DISK", 0, 0 }; +TRACKING DISKBUF_TRACKING = { "DSKB", 0, 0 }; +TRACKING TABLE_TRACKING = { "TBLE", 0, 0 }; +TRACKING FAT_TRACKING = { "FATM", 0, 0 }; +TRACKING FATLRU_TRACKING = { "FATL", 0, 0 }; +TRACKING FATHASH_TRACKING = { "FATH", 0, 0 }; +TRACKING DIRLRU_TRACKING = { "DIRL", 0, 0 }; +TRACKING DIRHASH_TRACKING = { "DIRH", 0, 0 }; +TRACKING DIR_TRACKING = { "DIRM", 0, 0 }; +TRACKING DIR_BLOCK_TRACKING = { "DIRB", 0, 0 }; +TRACKING DIR_BLOCKHASH_TRACKING = { "DRBH", 0, 0 }; +TRACKING EXT_BLOCK_TRACKING = { "EXTB", 0, 0 }; +TRACKING EXT_BLOCKHASH_TRACKING = { "EXBH", 0, 0 }; +TRACKING ASSN_BLOCK_TRACKING = { "ASNB", 0, 0 }; +TRACKING ASSN_BLOCKHASH_TRACKING = { "ASBH", 0, 0 }; +TRACKING BLOCK_TRACKING = { "BLKM", 0, 0 }; +TRACKING CREATE_TRACKING = { "CRET", 0, 0 }; +TRACKING TRUSTEE_TRACKING = { "TRST", 0, 0 }; +TRACKING USER_TRACKING = { "USER", 0, 0 }; +TRACKING NWDIR_TRACKING = { "NWDT", 0, 0 }; +TRACKING NWEXT_TRACKING = { "NWET", 0, 0 }; +TRACKING FAT_WORKSPACE_TRACKING = { "WRKF", 0, 0 }; +TRACKING DIR_WORKSPACE_TRACKING = { "WRKD", 0, 0 }; +TRACKING EXT_WORKSPACE_TRACKING = { "WRKE", 0, 0 }; +TRACKING CRT_WORKSPACE_TRACKING = { "WRKC", 0, 0 }; +TRACKING SA_WORKSPACE_TRACKING = { "WKSA", 0, 0 }; +TRACKING TRUNC_WORK_TRACKING = { "WKST", 0, 0 }; +TRACKING SECTOR_TRACKING = { "SECT", 0, 0 }; +TRACKING CLUSTER_TRACKING = { "CLST", 0, 0 }; +TRACKING VOLUME_TRACKING = { "VOLS", 0, 0 }; +TRACKING VOLUME_WS_TRACKING = { "VOLW", 0, 0 }; +TRACKING VOLUME_DATA_TRACKING = { "VOLD", 0, 0 }; +TRACKING LRU_TRACKING = { "LRUS", 0, 0 }; +TRACKING LRU_HASH_TRACKING = { "LRUH", 0, 0 }; +TRACKING LRU_BUFFER_TRACKING = { "LRUB", 0, 0 }; +TRACKING ALIGN_BUF_TRACKING = { "ALGN", 0, 0 }; +TRACKING NAM_HASH_TRACKING = { "NAMH", 0, 0 }; +TRACKING DNM_HASH_TRACKING = { "DNMH", 0, 0 }; +TRACKING PAR_HASH_TRACKING = { "PARH", 0, 0 }; +TRACKING EXD_HASH_TRACKING = { "EXDH", 0, 0 }; +TRACKING TRS_HASH_TRACKING = { "TRSH", 0, 0 }; +TRACKING DEL_HASH_TRACKING = { "DELH", 0, 0 }; +TRACKING QUO_HASH_TRACKING = { "QUOH", 0, 0 }; +TRACKING SUBALLOC_HEAD_TRACKING = { "SUBH", 0, 0 }; +TRACKING PAGED_FAT_BUF_TRACKING = { "PGFT", 0, 0 }; +TRACKING PAGED_WORK_BUF_TRACKING = { "PGWK", 0, 0 }; +TRACKING PAGED_PART_BUF_TRACKING = { "PGPT", 0, 0 }; +TRACKING PAGED_VOL_BUF_TRACKING = { "PGVL", 0, 0 }; +TRACKING PAGED_SECT_BUF_TRACKING = { "PGSC", 0, 0 }; +TRACKING SEMAPHORE_TRACKING = { "SEMA", 0, 0 }; +TRACKING NAME_STORAGE_TRACKING = { "NAME", 0, 0 }; +TRACKING NWVP_TRACKING = { "NWVP", 0, 0 }; +TRACKING BH_TRACKING = { "BHBH", 0, 0 }; +TRACKING ASYNCH_HASH_TRACKING = { "AIOH", 0, 0 }; + +TRACKING *tracked_memory[]= +{ + &HOTFIX_TRACKING, + &HOTFIX_DATA_TRACKING, + &HOTFIX_TABLE_TRACKING, + &MIRROR_TRACKING, + &MIRROR_DATA_TRACKING, + &HASH_TRACKING, + &EXT_HASH_TRACKING, + &BITBLOCK_TRACKING, + &BITBUFFER_TRACKING, + &NWPART_TRACKING, + &NWDISK_TRACKING, + &DISKBUF_TRACKING, + &TABLE_TRACKING, + &FAT_TRACKING, + &FATLRU_TRACKING, + &FATHASH_TRACKING, + &DIRLRU_TRACKING, + &DIRHASH_TRACKING, + &DIR_TRACKING, + &DIR_BLOCK_TRACKING, + &DIR_BLOCKHASH_TRACKING, + &EXT_BLOCK_TRACKING, + &EXT_BLOCKHASH_TRACKING, + &ASSN_BLOCK_TRACKING, + &ASSN_BLOCKHASH_TRACKING, + &BLOCK_TRACKING, + &CREATE_TRACKING, + &TRUSTEE_TRACKING, + &USER_TRACKING, + &NWDIR_TRACKING, + &NWEXT_TRACKING, + &FAT_WORKSPACE_TRACKING, + &DIR_WORKSPACE_TRACKING, + &EXT_WORKSPACE_TRACKING, + &CRT_WORKSPACE_TRACKING, + &SA_WORKSPACE_TRACKING, + &TRUNC_WORK_TRACKING, + &SECTOR_TRACKING, + &CLUSTER_TRACKING, + &VOLUME_TRACKING, + &VOLUME_WS_TRACKING, + &VOLUME_DATA_TRACKING, + &LRU_TRACKING, + &LRU_HASH_TRACKING, + &LRU_BUFFER_TRACKING, + &ALIGN_BUF_TRACKING, + &NAM_HASH_TRACKING, + &DNM_HASH_TRACKING, + &PAR_HASH_TRACKING, + &EXD_HASH_TRACKING, + &TRS_HASH_TRACKING, + &DEL_HASH_TRACKING, + &QUO_HASH_TRACKING, + &SUBALLOC_HEAD_TRACKING, + &PAGED_FAT_BUF_TRACKING, + &PAGED_WORK_BUF_TRACKING, + &PAGED_PART_BUF_TRACKING, + &PAGED_VOL_BUF_TRACKING, + &PAGED_SECT_BUF_TRACKING, + &SEMAPHORE_TRACKING, + &NAME_STORAGE_TRACKING, + &NWVP_TRACKING, + &BH_TRACKING, + &ASYNCH_HASH_TRACKING, +}; + +ULONG tracked_memory_count = sizeof(tracked_memory) / sizeof(TRACKING *); + +ULONG MajorVersion = 0, MinorVersion = 0, BuildVersion = 0; +ULONG exitFlag = 0; +ULONG consoleHandle = 0; +ULONG MaximumNumberOfVolumes = 0; +ULONG NumberOfVolumes = 0; + +ULONG MemoryAllocated = 0; +ULONG MemoryFreed = 0; +ULONG MemoryInUse = 0; + +ULONG PagedMemoryAllocated = 0; +ULONG PagedMemoryFreed = 0; +ULONG PagedMemoryInUse = 0; + +NWDISK *SystemDisk[MAX_DISKS]; +VOLUME *VolumeTable[MAX_VOLUMES]; +ULONG VolumeMountedTable[MAX_VOLUMES]; +ULONG InstanceCounter = 1; +ULONG (*RemirrorProcessPtr)(ULONG) = 0; + +ULONG DataLRUActive = 0; +ULONG JournalLRUActive = 0; +ULONG FATLRUActive = 0; +ULONG LogicalBlockSize = 512; + +LRU_HANDLE DataLRU; +LRU_HANDLE JournalLRU; +LRU_HANDLE FATLRU; + +ASYNCH_IO *aio_free_head = 0; +ASYNCH_IO *aio_free_tail = 0; +ULONG aio_free_count; + +ULONG HOTFIX_TRACK_OFFSET[MULTI_TRACK_COUNT]= +{ + HOTFIX_LOCATION_0, HOTFIX_LOCATION_1, HOTFIX_LOCATION_2, + HOTFIX_LOCATION_3 +}; + +ULONG MIRROR_TRACK_OFFSET[MULTI_TRACK_COUNT]= +{ + MIRROR_LOCATION_0, MIRROR_LOCATION_1, MIRROR_LOCATION_2, + MIRROR_LOCATION_3 +}; + +ULONG VOLTABLE_TRACK_OFFSET[MULTI_TRACK_COUNT]= +{ + VOLUME_TABLE_LOCATION_0, VOLUME_TABLE_LOCATION_1, VOLUME_TABLE_LOCATION_2, + VOLUME_TABLE_LOCATION_3 +}; + +#if (LINUX) + +ULONG DiskDevices[MAX_DISKS] = +{ + // IDE (hda - hdt) + 0x0300, 0x0340, 0x1600, 0x1640, 0x2100, 0x2140, 0x2200, 0x2240, + 0x3800, 0x3840, 0x3900, 0x3940, 0x5800, 0x5840, 0x5900, 0x5940, + 0x5A00, 0x5A40, 0x5B00, 0x5B40, + + // SCSI 0-15 (sda - sdp) + 0x0800, 0x0810, 0x0820, 0x0830, 0x0840, 0x0850, 0x0860, 0x0870, + 0x0880, 0x0890, 0x08a0, 0x08b0, 0x08c0, 0x08d0, 0x08e0, 0x08f0, + + // SCSI 16-31 (sdq - sdaf) + 0x4100, 0x4110, 0x4120, 0x4130, 0x4140, 0x4150, 0x4160, 0x4170, + 0x4180, 0x4190, 0x41a0, 0x41b0, 0x41c0, 0x41d0, 0x41e0, 0x41f0, + + // SCSI 32-47 (sdag - sdav) + 0x4200, 0x4210, 0x4220, 0x4230, 0x4240, 0x4250, 0x4260, 0x4270, + 0x4280, 0x4290, 0x42a0, 0x42b0, 0x42c0, 0x42d0, 0x42e0, 0x42f0, + + // SCSI 48-63 (sdaw - sdbl) + 0x4300, 0x4310, 0x4320, 0x4330, 0x4340, 0x4350, 0x4360, 0x4370, + 0x4380, 0x4390, 0x43a0, 0x43b0, 0x43c0, 0x43d0, 0x43e0, 0x43f0, + + // SCSI 64-79 (sdbm - sdcb) + 0x4400, 0x4410, 0x4420, 0x4430, 0x4440, 0x4450, 0x4460, 0x4470, + 0x4480, 0x4490, 0x44a0, 0x44b0, 0x44c0, 0x44d0, 0x44e0, 0x44f0, + + // SCSI 80-95 (sdcc - sdcr) + 0x4500, 0x4510, 0x4520, 0x4530, 0x4540, 0x4550, 0x4560, 0x4570, + 0x4580, 0x4590, 0x45a0, 0x45b0, 0x45c0, 0x45d0, 0x45e0, 0x45f0, + + // SCSI 96-111 (sdcs - sddh) + 0x4600, 0x4610, 0x4620, 0x4630, 0x4640, 0x4650, 0x4660, 0x4670, + 0x4680, 0x4690, 0x46a0, 0x46b0, 0x46c0, 0x46d0, 0x46e0, 0x46f0, + + // SCSI 112-127 (sddi - sddx) + 0x4700, 0x4710, 0x4720, 0x4730, 0x4740, 0x4750, 0x4760, 0x4770, + 0x4780, 0x4790, 0x47a0, 0x47b0, 0x47c0, 0x47d0, 0x47e0, 0x47f0, + + // MCA EDSI (eda, edb) + 0x2400, 0x2440, + + // metadisk groups + 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, + 0x0908, 0x0909, 0x090a, 0x090b, 0x090c, 0x090d, 0x090e, 0x090f, + + // XT disks + 0x0D00, 0x0D40, + + // Acorn MFM disks + 0x1500, 0x1540, + + // Parallel Port ATA disks + 0x2F00, 0x2F01, 0x2F02, 0x2F03, + +#if (I2O_DEVICES) + // I2O 0-15 (hda - hdp) + 0x5000, 0x5010, 0x5020, 0x5030, 0x5040, 0x5050, 0x5060, 0x5070, + 0x5080, 0x5090, 0x50a0, 0x50b0, 0x50c0, 0x50d0, 0x50e0, 0x50f0, + + // I2O 16-31 (hdq - hdaf) + 0x5100, 0x5110, 0x5120, 0x5130, 0x5140, 0x5150, 0x5160, 0x5170, + 0x5180, 0x5190, 0x51a0, 0x51b0, 0x51c0, 0x51d0, 0x51e0, 0x51f0, + + // I2O 32-47 (hdag - hdav) + 0x5200, 0x5210, 0x5220, 0x5230, 0x5240, 0x5250, 0x5260, 0x5270, + 0x5280, 0x5290, 0x52a0, 0x52b0, 0x52c0, 0x52d0, 0x52e0, 0x52f0, + + // I2O 48-63 (hdaw - hdbl) + 0x5300, 0x5310, 0x5320, 0x5330, 0x5340, 0x5350, 0x5360, 0x5370, + 0x5380, 0x5390, 0x53a0, 0x53b0, 0x53c0, 0x53d0, 0x53e0, 0x53f0, + + // I2O 64-79 (hdbm - hdcb) + 0x5400, 0x5410, 0x5420, 0x5430, 0x5440, 0x5450, 0x5460, 0x5470, + 0x5480, 0x5490, 0x54a0, 0x54b0, 0x54c0, 0x54d0, 0x54e0, 0x54f0, + + // I2O 80-95 (hdcc - hdcr) + 0x5500, 0x5510, 0x5520, 0x5530, 0x5540, 0x5550, 0x5560, 0x5570, + 0x5580, 0x5590, 0x55a0, 0x55b0, 0x55c0, 0x55d0, 0x55e0, 0x55f0, + + // I2O 96-111 (hdcs - hddh) + 0x5600, 0x5610, 0x5620, 0x5630, 0x5640, 0x5650, 0x5660, 0x5670, + 0x5680, 0x5690, 0x56a0, 0x56b0, 0x56c0, 0x56d0, 0x56e0, 0x56f0, + + // I2O 112-127 (hddi - hddx) + 0x5700, 0x5710, 0x5720, 0x5730, 0x5740, 0x5750, 0x5760, 0x5770, + 0x5780, 0x5790, 0x57a0, 0x57b0, 0x57c0, 0x57d0, 0x57e0, 0x57f0, +#endif + +#if (COMPAQ_SMART2_RAID) + // COMPAQ SMART2 Array 0-15 (ida0a - ida0p) + 0x4800, 0x4810, 0x4820, 0x4830, 0x4840, 0x4850, 0x4860, 0x4870, + 0x4880, 0x4890, 0x48a0, 0x48b0, 0x48c0, 0x48d0, 0x48e0, 0x48f0, + + // COMPAQ SMART2 Array 16-31 (ida1a - ida1p) + 0x4900, 0x4910, 0x4920, 0x4930, 0x4940, 0x4950, 0x4960, 0x4970, + 0x4980, 0x4990, 0x49a0, 0x49b0, 0x49c0, 0x49d0, 0x49e0, 0x49f0, + + // COMPAQ SMART2 Array 32-47 (ida2a - ida2p) + 0x4A00, 0x4A10, 0x4A20, 0x4A30, 0x4A40, 0x4A50, 0x4A60, 0x4A70, + 0x4A80, 0x4A90, 0x4Aa0, 0x4Ab0, 0x4Ac0, 0x4Ad0, 0x4Ae0, 0x4Af0, + + // COMPAQ SMART2 Array 48-63 (ida3a - ida3p) + 0x4B00, 0x4B10, 0x4B20, 0x4B30, 0x4B40, 0x4B50, 0x4B60, 0x4B70, + 0x4B80, 0x4B90, 0x4Ba0, 0x4Bb0, 0x4Bc0, 0x4Bd0, 0x4Be0, 0x4Bf0, + + // COMPAQ SMART2 Array 64-79 (ida4a - ida4p) + 0x4C00, 0x4C10, 0x4C20, 0x4C30, 0x4C40, 0x4C50, 0x4C60, 0x4C70, + 0x4C80, 0x4C90, 0x4Ca0, 0x4Cb0, 0x4Cc0, 0x4Cd0, 0x4Ce0, 0x4Cf0, + + // COMPAQ SMART2 Array 80-95 (ida5a - ida5p) + 0x4D00, 0x4D10, 0x4D20, 0x4D30, 0x4D40, 0x4D50, 0x4D60, 0x4D70, + 0x4D80, 0x4D90, 0x4Da0, 0x4Db0, 0x4Dc0, 0x4Dd0, 0x4De0, 0x4Df0, + + // COMPAQ SMART2 Array 96-111 (ida6a - ida6p) + 0x4E00, 0x4E10, 0x4E20, 0x4E30, 0x4E40, 0x4E50, 0x4E60, 0x4E70, + 0x4E80, 0x4E90, 0x4Ea0, 0x4Eb0, 0x4Ec0, 0x4Ed0, 0x4Ee0, 0x4Ef0, + + // COMPAQ SMART2 Array 112-127 (ida7a - ida7p) + 0x4F00, 0x4F10, 0x4F20, 0x4F30, 0x4F40, 0x4F50, 0x4F60, 0x4F70, + 0x4F80, 0x4F90, 0x4Fa0, 0x4Fb0, 0x4Fc0, 0x4Fd0, 0x4Fe0, 0x4Ff0, +#endif + +#if (DAC960_RAID) + // DAC960 Raid Array 0-15 (ida0a - ida0p) + 0x3000, 0x3010, 0x3020, 0x3030, 0x3040, 0x3050, 0x3060, 0x3070, + 0x3080, 0x3090, 0x30a0, 0x30b0, 0x30c0, 0x30d0, 0x30e0, 0x30f0, + + // DAC960 Raid Array 16-31 (ida1a - ida1p) + 0x3100, 0x3110, 0x3120, 0x3130, 0x3140, 0x3150, 0x3160, 0x3170, + 0x3180, 0x3190, 0x31a0, 0x31b0, 0x31c0, 0x31d0, 0x31e0, 0x31f0, + + // DAC960 Raid Array 32-47 (ida2a - ida2p) + 0x3200, 0x3210, 0x3220, 0x3230, 0x3240, 0x3250, 0x3260, 0x3270, + 0x3280, 0x3290, 0x32a0, 0x32b0, 0x32c0, 0x32d0, 0x32e0, 0x32f0, + + // DAC960 Raid Array 48-63 (ida3a - ida3p) + 0x3300, 0x3310, 0x3320, 0x3330, 0x3340, 0x3350, 0x3360, 0x3370, + 0x3380, 0x3390, 0x33a0, 0x33b0, 0x33c0, 0x33d0, 0x33e0, 0x33f0, + + // DAC960 Raid Array 64-79 (ida4a - ida4p) + 0x3400, 0x3410, 0x3420, 0x3430, 0x3440, 0x3450, 0x3460, 0x3470, + 0x3480, 0x3490, 0x34a0, 0x34b0, 0x34c0, 0x34d0, 0x34e0, 0x34f0, + + // DAC960 Raid Array 80-95 (ida5a - ida5p) + 0x3500, 0x3510, 0x3520, 0x3530, 0x3540, 0x3550, 0x3560, 0x3570, + 0x3580, 0x3590, 0x35a0, 0x35b0, 0x35c0, 0x35d0, 0x35e0, 0x35f0, + + // DAC960 Raid Array 96-111 (ida6a - ida6p) + 0x3600, 0x3610, 0x3620, 0x3630, 0x3640, 0x3650, 0x3660, 0x3670, + 0x3680, 0x3690, 0x36a0, 0x36b0, 0x36c0, 0x36d0, 0x36e0, 0x36f0, + + // DAC960 Raid Array 112-127 (ida7a - ida7p) + 0x3700, 0x3710, 0x3720, 0x3730, 0x3740, 0x3750, 0x3760, 0x3770, + 0x3780, 0x3790, 0x37a0, 0x37b0, 0x37c0, 0x37d0, 0x37e0, 0x37f0, +#endif + + 0, 0, 0, 0, + +}; + +BYTE *PhysicalDiskNames[MAX_DISKS]= +{ + // IDE disks + "/dev/hda", "/dev/hdb", "/dev/hdc", "/dev/hdd", + "/dev/hde", "/dev/hdf", "/dev/hdg", "/dev/hdh", + "/dev/hdi", "/dev/hdj", "/dev/hdk", "/dev/hdl", + "/dev/hdm", "/dev/hdn", "/dev/hdo", "/dev/hdp", + "/dev/hdq", "/dev/hdr", "/dev/hds", "/dev/hdt", + + // *** 20 *** + + // SCSI disks 0-15 + "/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd", + "/dev/sde", "/dev/sdf", "/dev/sdg", "/dev/sdh", + "/dev/sdi", "/dev/sdj", "/dev/sdk", "/dev/sdl", + "/dev/sdm", "/dev/sdn", "/dev/sdo", "/dev/sdp", + + // SCSI disks 15-31 + "/dev/sdq", "/dev/sdr", "/dev/sds", "/dev/sdt", + "/dev/sdu", "/dev/sdv", "/dev/sdw", "/dev/sdx", + "/dev/sdy", "/dev/sdz", "/dev/sdaa", "/dev/sdab", + "/dev/sdac", "/dev/sdad", "/dev/sdae", "/dev/sdaf", + + // SCSI disks 32-47 + "/dev/sdag", "/dev/sdah", "/dev/sdai", "/dev/sdaj", + "/dev/sdak", "/dev/sdal", "/dev/sdam", "/dev/sdan", + "/dev/sdao", "/dev/sdap", "/dev/sdaq", "/dev/sdar", + "/dev/sdas", "/dev/sdat", "/dev/sdau", "/dev/sdav", + + // SCSI disks 48-63 + "/dev/sdaw", "/dev/sdax", "/dev/sday", "/dev/sdaz", + "/dev/sdba", "/dev/sdbb", "/dev/sdbc", "/dev/sdbd", + "/dev/sdbe", "/dev/sdbf", "/dev/sdbg", "/dev/sdbh", + "/dev/sdbi", "/dev/sdbj", "/dev/sdbk", "/dev/sdbl", + + // SCSI disks 64-79 + "/dev/sdbm", "/dev/sdbn", "/dev/sdbo", "/dev/sdbp", + "/dev/sdbq", "/dev/sdbr", "/dev/sdbs", "/dev/sdbt", + "/dev/sdbu", "/dev/sdbv", "/dev/sdbw", "/dev/sdbx", + "/dev/sdby", "/dev/sdbz", "/dev/sdca", "/dev/sdcb", + + // SCSI disks 80-95 + "/dev/sdcc", "/dev/sdcd", "/dev/sdce", "/dev/sdcf", + "/dev/sdcg", "/dev/sdch", "/dev/sdci", "/dev/sdcj", + "/dev/sdck", "/dev/sdcl", "/dev/sdcm", "/dev/sdcn", + "/dev/sdco", "/dev/sdcp", "/dev/sdcq", "/dev/sdcr", + + // SCSI disks 96-111 + "/dev/sdcs", "/dev/sdct", "/dev/sdcu", "/dev/sdcv", + "/dev/sdcw", "/dev/sdcx", "/dev/sdcy", "/dev/sdcz", + "/dev/sdda", "/dev/sddb", "/dev/sddc", "/dev/sddd", + "/dev/sdde", "/dev/sddf", "/dev/sddg", "/dev/sddh", + + // SCSI disks 112-127 + "/dev/sddi", "/dev/sddj", "/dev/sddk", "/dev/sddl", + "/dev/sddm", "/dev/sddn", "/dev/sddo", "/dev/sddp", + "/dev/sddq", "/dev/sddr", "/dev/sdds", "/dev/sddt", + "/dev/sddu", "/dev/sddv", "/dev/sddw", "/dev/sddx", + + // MCA ESDI disks + "/dev/eda", "/dev/edb", + + // *** 150 *** + + // metadisk groups + "/dev/md0", "dev/md1", "/dev/md2", "dev/md3", + "/dev/md4", "dev/md5", "/dev/md6", "dev/md7", + "/dev/md8", "dev/md9", "/dev/md10", "dev/md11", + "/dev/md12", "dev/md13", "/dev/md14", "dev/md15", + + // XT disks + "/dev/xda", "/dev/xdb", + + // Acorn MFM disks + "/dev/mfma", "/dev/mfmb", + + // Parallel Port ATA disks + "/dev/pf0", "/dev/pf1", "/dev/pf2", "/dev/pf3", + + // *** 174 *** + +#if (I2O_DEVICES) + // I2O disks 0-15 + "/dev/i2o/hda", "/dev/i2o/hdb", "/dev/i2o/hdc", "/dev/i2o/hdd", + "/dev/i2o/hde", "/dev/i2o/hdf", "/dev/i2o/hdg", "/dev/i2o/hdh", + "/dev/i2o/hdi", "/dev/i2o/hdj", "/dev/i2o/hdk", "/dev/i2o/hdl", + "/dev/i2o/hdm", "/dev/i2o/hdn", "/dev/i2o/hdo", "/dev/i2o/hdp", + + // I2O disks 16-31 + "/dev/i2o/hdq", "/dev/i2o/hdr", "/dev/i2o/hds", "/dev/i2o/hdt", + "/dev/i2o/hdu", "/dev/i2o/hdv", "/dev/i2o/hdw", "/dev/i2o/hdx", + "/dev/i2o/hdy", "/dev/i2o/hdz", "/dev/i2o/hdaa", "/dev/i2o/hdab", + "/dev/i2o/hdac", "/dev/i2o/hdad", "/dev/i2o/hdae", "/dev/i2o/hdaf", + + // I2O disks 32-47 + "/dev/i2o/hdag", "/dev/i2o/hdah", "/dev/i2o/hdai", "/dev/i2o/hdaj", + "/dev/i2o/hdak", "/dev/i2o/hdal", "/dev/i2o/hdam", "/dev/i2o/hdan", + "/dev/i2o/hdao", "/dev/i2o/hdap", "/dev/i2o/hdaq", "/dev/i2o/hdar", + "/dev/i2o/hdas", "/dev/i2o/hdat", "/dev/i2o/hdau", "/dev/i2o/hdav", + + // I2O disks 48-63 + "/dev/i2o/hdaw", "/dev/i2o/hdax", "/dev/i2o/hday", "/dev/i2o/hdaz", + "/dev/i2o/hdba", "/dev/i2o/hdbb", "/dev/i2o/hdbc", "/dev/i2o/hdbd", + "/dev/i2o/hdbe", "/dev/i2o/hdbf", "/dev/i2o/hdbg", "/dev/i2o/hdbh", + "/dev/i2o/hdbi", "/dev/i2o/hdbj", "/dev/i2o/hdbk", "/dev/i2o/hdbl", + + // I2O disks 64-79 + "/dev/i2o/hdbm", "/dev/i2o/hdbn", "/dev/i2o/hdbo", "/dev/i2o/hdbp", + "/dev/i2o/hdbq", "/dev/i2o/hdbr", "/dev/i2o/hdbs", "/dev/i2o/hdbt", + "/dev/i2o/hdbu", "/dev/i2o/hdbv", "/dev/i2o/hdbw", "/dev/i2o/hdbx", + "/dev/i2o/hdby", "/dev/i2o/hdbz", "/dev/i2o/hdca", "/dev/i2o/hdcb", + + // I2O disks 80-95 + "/dev/i2o/hdcc", "/dev/i2o/hdcd", "/dev/i2o/hdce", "/dev/i2o/hdcf", + "/dev/i2o/hdcg", "/dev/i2o/hdch", "/dev/i2o/hdci", "/dev/i2o/hdcj", + "/dev/i2o/hdck", "/dev/i2o/hdcl", "/dev/i2o/hdcm", "/dev/i2o/hdcn", + "/dev/i2o/hdco", "/dev/i2o/hdcp", "/dev/i2o/hdcq", "/dev/i2o/hdcr", + + // I2O disks 96-111 + "/dev/i2o/hdcs", "/dev/i2o/hdct", "/dev/i2o/hdcu", "/dev/i2o/hdcv", + "/dev/i2o/hdcw", "/dev/i2o/hdcx", "/dev/i2o/hdcy", "/dev/i2o/hdcz", + "/dev/i2o/hdda", "/dev/i2o/hddb", "/dev/i2o/hddc", "/dev/i2o/hddd", + "/dev/i2o/hdde", "/dev/i2o/hddf", "/dev/i2o/hddg", "/dev/i2o/hddh", + + // I2O disks 112-127 + "/dev/i2o/hddi", "/dev/i2o/hddj", "/dev/i2o/hddk", "/dev/i2o/hddl", + "/dev/i2o/hddm", "/dev/i2o/hddn", "/dev/i2o/hddo", "/dev/i2o/hddp", + "/dev/i2o/hddq", "/dev/i2o/hddr", "/dev/i2o/hdds", "/dev/i2o/hddt", + "/dev/i2o/hddu", "/dev/i2o/hddv", "/dev/i2o/hddw", "/dev/i2o/hddx", +#endif + + // *** 302 *** + +#if (COMPAQ_SMART2_RAID) + // COMPAQ Smart2 disks 0-15 + "/dev/ida0a", "/dev/ida0b", "/dev/ida0c", "/dev/ida0d", + "/dev/ida0e", "/dev/ida0f", "/dev/ida0g", "/dev/ida0h", + "/dev/ida0i", "/dev/ida0j", "/dev/ida0k", "/dev/ida0l", + "/dev/ida0m", "/dev/ida0n", "/dev/ida0o", "/dev/ida0p", + + // COMPAQ Smart2 disks 16-31 + "/dev/ida1a", "/dev/ida1b", "/dev/ida1c", "/dev/ida1d", + "/dev/ida1e", "/dev/ida1f", "/dev/ida1g", "/dev/ida1h", + "/dev/ida1i", "/dev/ida1j", "/dev/ida1k", "/dev/ida1l", + "/dev/ida1m", "/dev/ida1n", "/dev/ida1o", "/dev/ida1p", + + // COMPAQ Smart2 disks 32-47 + "/dev/ida2a", "/dev/ida2b", "/dev/ida2c", "/dev/ida2d", + "/dev/ida2e", "/dev/ida2f", "/dev/ida2g", "/dev/ida2h", + "/dev/ida2i", "/dev/ida2j", "/dev/ida2k", "/dev/ida2l", + "/dev/ida2m", "/dev/ida2n", "/dev/ida2o", "/dev/ida2p", + + // COMPAQ Smart2 disks 48-63 + "/dev/ida3a", "/dev/ida3b", "/dev/ida3c", "/dev/ida3d", + "/dev/ida3e", "/dev/ida3f", "/dev/ida3g", "/dev/ida3h", + "/dev/ida3i", "/dev/ida3j", "/dev/ida3k", "/dev/ida3l", + "/dev/ida3m", "/dev/ida3n", "/dev/ida3o", "/dev/ida3p", + + // COMPAQ Smart2 disks 64-79 + "/dev/ida4a", "/dev/ida4b", "/dev/ida4c", "/dev/ida4d", + "/dev/ida4e", "/dev/ida4f", "/dev/ida4g", "/dev/ida4h", + "/dev/ida4i", "/dev/ida4j", "/dev/ida4k", "/dev/ida4l", + "/dev/ida4m", "/dev/ida4n", "/dev/ida4o", "/dev/ida4p", + + // COMPAQ Smart2 disks 80-95 + "/dev/ida5a", "/dev/ida5b", "/dev/ida5c", "/dev/ida5d", + "/dev/ida5e", "/dev/ida5f", "/dev/ida5g", "/dev/ida5h", + "/dev/ida5i", "/dev/ida5j", "/dev/ida5k", "/dev/ida5l", + "/dev/ida5m", "/dev/ida5n", "/dev/ida5o", "/dev/ida5p", + + // COMPAQ Smart2 disks 96-111 + "/dev/ida6a", "/dev/ida6b", "/dev/ida6c", "/dev/ida6d", + "/dev/ida6e", "/dev/ida6f", "/dev/ida6g", "/dev/ida6h", + "/dev/ida6i", "/dev/ida6j", "/dev/ida6k", "/dev/ida6l", + "/dev/ida6m", "/dev/ida6n", "/dev/ida6o", "/dev/ida6p", + + // COMPAQ Smart2 disks 112-127 + "/dev/ida7a", "/dev/ida7b", "/dev/ida7c", "/dev/ida7d", + "/dev/ida7e", "/dev/ida7f", "/dev/ida7g", "/dev/ida7h", + "/dev/ida7i", "/dev/ida7j", "/dev/ida7k", "/dev/ida7l", + "/dev/ida7m", "/dev/ida7n", "/dev/ida7o", "/dev/ida7p", +#endif + + // *** 430 *** + +#if (DAC960_RAID) + // DAC960 Raid disks 0-15 + "/dev/rd/c0d0", "/dev/rd/c0d0p1", "/dev/rd/c0d0p2", "/dev/rd/c0d0p3", + "/dev/rd/c0d0p4", "/dev/rd/c0d0p5", "/dev/rd/c0d0p6", "/dev/rd/c0d0p7", + "/dev/rd/c0d1", "/dev/rd/c0d1p1", "/dev/rd/c0d1p2", "/dev/rd/c0d1p3", + "/dev/rd/c0d1p4", "/dev/rd/c0d1p5", "/dev/rd/c0d1p6", "/dev/rd/c0d1p7", + + // DAC960 Raid disks 16-31 + "/dev/rd/c0d2", "/dev/rd/c0d2p1", "/dev/rd/c0d2p2", "/dev/rd/c0d2p3", + "/dev/rd/c0d2p4", "/dev/rd/c0d2p5", "/dev/rd/c0d2p6", "/dev/rd/c0d2p7", + "/dev/rd/c0d3", "/dev/rd/c0d3p1", "/dev/rd/c0d3p2", "/dev/rd/c0d3p3", + "/dev/rd/c0d3p4", "/dev/rd/c0d3p5", "/dev/rd/c0d3p6", "/dev/rd/c0d3p7", + + // DAC960 Raid disks 32-47 + "/dev/rd/c0d4", "/dev/rd/c0d4p1", "/dev/rd/c0d4p2", "/dev/rd/c0d4p3", + "/dev/rd/c0d4p4", "/dev/rd/c0d4p5", "/dev/rd/c0d4p6", "/dev/rd/c0d4p7", + "/dev/rd/c0d5", "/dev/rd/c0d5p1", "/dev/rd/c0d5p2", "/dev/rd/c0d5p3", + "/dev/rd/c0d5p4", "/dev/rd/c0d5p5", "/dev/rd/c0d5p6", "/dev/rd/c0d5p7", + + // DAC960 Raid disks 48-63 + "/dev/rd/c0d6", "/dev/rd/c0d6p1", "/dev/rd/c0d6p2", "/dev/rd/c0d6p3", + "/dev/rd/c0d6p4", "/dev/rd/c0d6p5", "/dev/rd/c0d6p6", "/dev/rd/c0d6p7", + "/dev/rd/c0d7", "/dev/rd/c0d7p1", "/dev/rd/c0d7p2", "/dev/rd/c0d7p3", + "/dev/rd/c0d7p4", "/dev/rd/c0d7p5", "/dev/rd/c0d7p6", "/dev/rd/c0d7p7", + + // DAC960 Raid disks 64-79 + "/dev/rd/c1d0", "/dev/rd/c1d0p1", "/dev/rd/c1d0p2", "/dev/rd/c1d0p3", + "/dev/rd/c1d0p4", "/dev/rd/c1d0p5", "/dev/rd/c1d0p6", "/dev/rd/c1d0p7", + "/dev/rd/c1d1", "/dev/rd/c1d1p1", "/dev/rd/c1d1p2", "/dev/rd/c1d1p3", + "/dev/rd/c1d1p4", "/dev/rd/c1d1p5", "/dev/rd/c1d1p6", "/dev/rd/c1d1p7", + + // DAC960 Raid disks 80-95 + "/dev/rd/c1d2", "/dev/rd/c1d2p1", "/dev/rd/c1d2p2", "/dev/rd/c1d2p3", + "/dev/rd/c1d2p4", "/dev/rd/c1d2p5", "/dev/rd/c1d2p6", "/dev/rd/c1d2p7", + "/dev/rd/c1d3", "/dev/rd/c1d3p1", "/dev/rd/c1d3p2", "/dev/rd/c1d3p3", + "/dev/rd/c1d3p4", "/dev/rd/c1d3p5", "/dev/rd/c1d3p6", "/dev/rd/c1d3p7", + + // DAC960 Raid disks 96-111 + "/dev/rd/c1d4", "/dev/rd/c1d4p1", "/dev/rd/c1d4p2", "/dev/rd/c1d4p3", + "/dev/rd/c1d4p4", "/dev/rd/c1d4p5", "/dev/rd/c1d4p6", "/dev/rd/c1d4p7", + "/dev/rd/c1d5", "/dev/rd/c1d5p1", "/dev/rd/c1d5p2", "/dev/rd/c1d5p3", + "/dev/rd/c1d5p4", "/dev/rd/c1d5p5", "/dev/rd/c1d5p6", "/dev/rd/c1d5p7", + + // DAC960 Raid disks 112-127 + "/dev/rd/c1d6", "/dev/rd/c1d6p1", "/dev/rd/c1d6p2", "/dev/rd/c1d6p3", + "/dev/rd/c1d6p4", "/dev/rd/c1d6p5", "/dev/rd/c1d6p6", "/dev/rd/c1d6p7", + "/dev/rd/c1d7", "/dev/rd/c1d7p1", "/dev/rd/c1d7p2", "/dev/rd/c1d7p3", + "/dev/rd/c1d7p4", "/dev/rd/c1d7p5", "/dev/rd/c1d7p6", "/dev/rd/c1d7p7", +#endif + + // *** 558 *** + + NULL, NULL, NULL, NULL, + +}; + +ULONG MaxDisksSupported = sizeof(DiskDevices) / sizeof(ULONG); +ULONG MaxHandlesSupported = sizeof(PhysicalDiskNames) / sizeof(BYTE *); + +#endif + +#if (LINUX_SPIN) +extern spinlock_t aio_spinlock; +extern spinlock_t cb_spinlock; +extern spinlock_t bh_spinlock; +extern spinlock_t HashFree_spinlock; +#endif + +void InitNWFS(void) +{ + register ULONG ccode, i; + extern ASYNCH_IO_HEAD asynch_io_head[MAX_DISKS]; + + // if we are being asked to override default device blocksize + // for NWFS, make sure the value is legal for us. + if ((LOGICAL_BLOCK_SIZE == 512) || (LOGICAL_BLOCK_SIZE == 1024) || + (LOGICAL_BLOCK_SIZE == 2048) || (LOGICAL_BLOCK_SIZE == 4096)) + LogicalBlockSize = LOGICAL_BLOCK_SIZE; + + ccode = InitializeLRU(&DataLRU, "Data LRU", WRITE_BACK_LRU, + MAX_VOLUME_LRU_BLOCKS, + MIN_VOLUME_LRU_BLOCKS, + LRU_AGE); + if (!ccode) + DataLRUActive = TRUE; + + ccode = InitializeLRU(&JournalLRU, "Dir LRU", WRITE_BACK_LRU, + MAX_DIRECTORY_LRU_BLOCKS, + MIN_DIRECTORY_LRU_BLOCKS, + JOURNAL_AGE); + if (!ccode) + JournalLRUActive = TRUE; + + ccode = InitializeLRU(&FATLRU, "Fat LRU", WRITE_BACK_LRU, + MAX_FAT_LRU_BLOCKS, + MIN_FAT_LRU_BLOCKS, + FAT_AGE); + if (!ccode) + FATLRUActive = TRUE; + + ZeroBuffer = NWFSIOAlloc(65536, DISKBUF_TAG); + if (!ZeroBuffer) + return; + NWFSSet(ZeroBuffer, 0, 65536); + + // initialize the asynch io heads + for (i=0; i < MAX_DISKS; i++) + NWFSSet(&asynch_io_head[i], 0, sizeof(ASYNCH_IO_HEAD)); + +#if (LINUX_SPIN) + spin_lock_init(&aio_spinlock); + spin_lock_init(&cb_spinlock); + spin_lock_init(&bh_spinlock); + spin_lock_init(&HashFree_spinlock); +#endif + + return; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/globals.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/globals.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/globals.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/globals.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,448 @@ + +/*************************************************************************** +* +* Copyright (c) 1997-2001 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. I will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : GLOBALS.H +* DESCRIP : NWFS Global Declarations +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#ifndef _NWFS_GLOBALS_ +#define _NWFS_GLOBALS_ + +#if (OVERRIDE) + +#if LINUX_DRIVER + +#if NATIVE_MODULE +#include +#include +#endif + +#if MODULE +#ifndef NWFSMOD_VERSION_INFO +#define __NO_VERSION__ +#endif +#if MODVERSIONS +#include +#endif +#include +#include +#endif +#include + +#if LINUX_VERSION_CODE >= 0x020400 +#define LINUX_24 1 +#elif LINUX_VERSION_CODE >= 0x020200 +#define LINUX_22 1 +#elif LINUX_VERSION_CODE >= 0x020000 +#define LINUX_20 1 +#endif + +#endif + +#else + +#define LINUX_20 0 +#define LINUX_22 0 +#define LINUX_24 1 + +#endif + +#define uint32 unsigned long +#define uint8 unsigned char + +#if (LINUX_20) +#define LINUX 1 +#define LINUX_SLEEP 1 +#define LINUX_SPIN 0 +#endif +#if (LINUX_22) +#define LINUX 1 +#define LINUX_SLEEP 1 +#define LINUX_SPIN 1 +#endif +#if (LINUX_24) +#define LINUX 1 +#define LINUX_SLEEP 1 +#define LINUX_SPIN 1 +#endif + +// +// define version of this utility +// + +#define MAJOR_VERSION 4 +#define MINOR_VERSION 0 +#define BUILD_VERSION 2 +#define BUILD_YEAR 2001 + +// debug flags +#define VERBOSE 0 // enable verbose output +#define VFS_VERBOSE 0 // trace VFS/NWFS interaction +#define MOUNT_VERBOSE 0 // enable verbose output during mounts +#define HOTFIX_VERBOSE 0 // trace hotfix table lookups +#define VOLUME_DUMP 0 // dump volume segment info as detected +#define DEBUG_SA 0 // trace suballocation reads/writes +#define CHECK_NLINK 0 // perform nlink validation during dir delete +#define DEBUG_DEADLOCKS 0 // allows deadlocks to receive EINTR signals +#define PROFILE_AIO_VERBOSE 0 // print profile aio efficiency stats +#define DEBUG_AIO 0 // trace linux AIO calls +#define DEBUG_LRU_AIO 0 // trace LRU/AIO interaction +#define CREATE_FAT_MISMATCH 0 // generate fat mismatches +#define CREATE_DIR_MISMATCH 0 // generate directory mismatches +#define CREATE_EDIR_MISMATCH 0 // generate extended directory mismatches +#define POST_IMMEDIATE 0 // force immediate post of I/O requests +#define DUMP_BUFFER_HEADS 0 // dump buffer heads to /var/log/messages +#define DEBUG_MIRRORING 0 // debug remirroring and validation +#define DEBUG_MIRROR_CONTROL 0 // debug remirroring control allocation +#define DUMP_LEAKED_MEMORY 0 // dump leaked memory headers +#define MONITOR_LRU_COUNT 0 // monitor lru cache sharing count +#define VERIFY_NAMESPACE_LIST 0 // verify name hash list before delete +#define PROFILE_BIT_SEARCH 0 // profile bit list search efficiency +#define BIT_SEARCH_THRESHOLD 2 // bit list search threshold +#define DEBUG_CODE 0 // enable debugging code subsystems + +// feature enable flags +#define PROFILE_AIO 1 // profile aio efficiency +#define TRUE_NETWARE_MODE 0 // enable full NetWare compatibility +#define SALVAGEABLE_FS 0 // enable the salvageable file system +#define TURBO_FAT_ON 1 // enable Turbo Fat Indexing +#define STRICT_NAMES 1 // strict name validation during mount +#define LRU_FACTOR 2 // % dirty for flush (1-100% 2-50% 3-33%) +#define LRU_AGE 2 // how many seconds to age dirty data blocks +#define JOURNAL_AGE 3 // how many seconds to age dirty dir blocks +#define FAT_AGE 3 // how many seconds to age dirty fat blocks +#define RAPID_MOUNT_AGE 3 // how many seconds to age dirty fat blocks +#define ALLOW_REMOUNT 1 // allow remounting of NetWare Volumes +#define PAGE_CACHE_ON 0 // enable Linux page cache interface +#define CACHE_FAT_TABLES 0 // cache and pin the fat tables in memory +#define SINGLE_DIRTY_LIST 1 // disables dirty lru skip list +#define AUTO_CREATE_META_FILES 0 // auto create volume meta files + +// extended raid and I2O Device Support +#define META_DISK 0 // enable /dev/mdXX Raid Devices +#define ALL_EXT_DEVICES 0 // enable all extended device support +#define COMPAQ_SMART2_RAID 0 // enable COMPAQ Smart2 Raid support +#define DAC960_RAID 0 // enable DAC960 Raid Support +#define I2O_DEVICES 0 // enable I2O Device Support + +// NOTE: if you disable this, then the elevator moves to the LRU +// otherwise the AIO manager maintains the elevator. +#define DO_ASYNCH_IO 1 // enable the asynch I/O subsystem +#define READ_AHEAD_ON 1 // enable read ahead capability +#define ASYNCH_READ_AHEAD 1 // enable asynch read ahead capability +#define LINUX_BUFFER_CACHE 0 // double buffer data in the linux cache +#define ZERO_FILL_SECTORS 0 // zero fill newly allocated sectors +#define CONSERVE_MEMORY 0 // conserve unused AIO/WorkSpace Memory +#define LINUX_AIO 1 // use Linux 2.2/2.4 AIO subsystem +#define HASH_FAT_CHAINS 1 // hash file FAT chain heads +#define FREE_UNUSED_DIR_SPACE 1 // release unclaimed dir space during mount +#define LOGICAL_BLOCK_SIZE 512 // set to 512, 1024, 2048, 4096 block size + +#if (TRUE_NETWARE_MODE) +#undef LOGICAL_BLOCK_SIZE +#define LOGICAL_BLOCK_SIZE 512 // NetWare mode defaults to 512 block size +#endif + +// these values can be changed if you want to increase the numbers of +// disks/volumes that NWFS will support + +#define MAX_DISKS 256 // max disks +#define MAX_DOS_DISKS 128 // max disks supported by MSDOS +#define MAX_PARTITIONS MAX_DISKS * 4 +#define MAX_VOLUMES 256 // netware supports 256 volumes/server +#define MAX_BUFFER_HEADS 4096 // buffer head pool for AIO +#define MAX_WORKSPACE_BUFFERS 32 // max workspaces/volume +#define MAX_MACHINES 200 // max nodes per cluster + +// these values are architecture dependent and should not be changed +#define MAX_VOLUME_ENTRIES 8 // 8 entries per volume table (partition) +#define MAX_SEGMENTS 32 // a volume can have 32 segments +#define MAX_MIRRORS 8 // NetWare max is 8 +#define MAX_NAMESPACES 10 // 12 in 4.x, 10 in 3.x +#define MAX_NAMESPACE_EXTANTS 3 // max number of extended namespaces +#define MAX_SUBALLOC_NODES 5 // max number of suballoc headers/volume +#define MAX_SUBALLOC_SPAN 2 // max suballoc nodes an entry can span +#define SUBALLOC_BLOCK_SIZE 512 // minumum suballocation size +#define MAX_HOTFIX_BLOCKS 30 // max hotfix block list table entries + +#define IO_BLOCK_SIZE 4096 // volume block size default +#define BIT_BLOCK_SIZE IO_BLOCK_SIZE +#define HOTFIX_BLOCK_SIZE IO_BLOCK_SIZE + + +#if (ALL_EXT_DEVICES) +#undef COMPAQ_SMART2_RAID +#undef DAC960_RAID +#undef I2O_DEVICES +#define COMPAQ_SMART2_RAID 1 +#define DAC960_RAID 1 +#define I2O_DEVICES 1 +#endif + +#if (COMPAQ_SMART2_RAID | DAC960RAID | I2O_DEVICES) +#undef MAX_DISKS +#define MAX_DISKS 600 +#endif + +// this defines the maximum size of the SMP LRU for NWFS. If you +// start getting "virtual memory exhausted" messages, you may want +// to crank down this value for Linux. + +#define MIN_RAPID_MOUNT_BLOCKS 0 +#define MAX_RAPID_MOUNT_BLOCKS 100 +#define MIN_FAT_LRU_BLOCKS 0 +#define MAX_FAT_LRU_BLOCKS 100 +#define MIN_DIRECTORY_LRU_BLOCKS 10 +#define MAX_DIRECTORY_LRU_BLOCKS 500 +#define MIN_VOLUME_LRU_BLOCKS 10 +#define MAX_VOLUME_LRU_BLOCKS 1000 + +#if (LINUX_20 | LINUX_22) +#undef MAX_VOLUME_LRU_BLOCKS +#undef MAX_DIRECTORY_LRU_BLOCKS +#undef MAX_FAT_LRU_BLOCKS +#if (LINUX_BUFFER_CACHE) +#define MAX_VOLUME_LRU_BLOCKS 500 +#define MAX_DIRECTORY_LRU_BLOCKS 500 +#define MAX_FAT_LRU_BLOCKS 100 +#else +#define MAX_VOLUME_LRU_BLOCKS 1000 +#define MAX_DIRECTORY_LRU_BLOCKS 500 +#define MAX_FAT_LRU_BLOCKS 100 +#endif +#endif + +#if (LINUX_24) +#undef MAX_VOLUME_LRU_BLOCKS +#undef MAX_DIRECTORY_LRU_BLOCKS +#undef MAX_FAT_LRU_BLOCKS +#if (LINUX_BUFFER_CACHE) +#define MAX_VOLUME_LRU_BLOCKS 500 +#define MAX_DIRECTORY_LRU_BLOCKS 500 +#define MAX_FAT_LRU_BLOCKS 100 +#else +#define MAX_VOLUME_LRU_BLOCKS 1000 +#define MAX_DIRECTORY_LRU_BLOCKS 500 +#define MAX_FAT_LRU_BLOCKS 100 +#endif +#endif + +#define MAX_LRU_BLOCKS (MAX_VOLUME_LRU_BLOCKS + MAX_DIRECTORY_LRU_BLOCKS + MAX_FAT_LRU_BLOCKS) + +// LRU Eviction priority values +#define DATA_PRIORITY 1 +#define DIRECTORY_PRIORITY 2 +#define FAT_PRIORITY 3 +#define RAW_PRIORITY 4 + + +#if (LINUX_24) + +#if (M2FS) +#define CONFIG_NAME " M2FS Clustered File System" +#define IMAGER_NAME " M2FS Clustered File System" +#else +#define CONFIG_NAME " NWFS NetWare File System" +#define IMAGER_NAME " NWFS NetWare File System" +#endif + +#define COPYRIGHT_NOTICE1 " Copyright (c) 1997-2001 Jeff V. Merkey All Rights Reserved." +#define COPYRIGHT_NOTICE2 " " + +#define TargetOS "Linux 24" + +#define NWFSInitMutex(s) DECLARE_MUTEX(s) +#define NWFSInitSemaphore(s) DECLARE_MUTEX_LOCKED(s) + +#define TRUE 1 +#define FALSE 0 + +#ifndef LONGLONG +typedef long long LONGLONG; +#endif + +typedef unsigned long ULONG; +typedef unsigned short WORD; +typedef unsigned char BYTE; + +#define NWFSPrint printk + +#if MODULE +#ifndef NWFSMOD_VERSION_INFO +#define __NO_VERSION__ +#endif +#if MODVERSIONS +#include +#endif +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __KERNEL_SYSCALLS__ +#include + +#include "nwfs.h" +#include "nwhash.h" +#include "nwstruct.h" +#include "nwerror.h" +#include "nwdir.h" +#include "nwproc.h" + +#include "nwvphal.h" +#include "nwvp.h" + +#include "nwvfs.h" + +#endif + +// +// +// + +#if (LINUX_UTIL) + +#if (M2FS) +#define CONFIG_NAME " M2FS Volume Manager for Linux" +#define IMAGER_NAME " M2FS Volume IMAGER for Linux" +#else +#define CONFIG_NAME " NWFS Volume Manager for Linux" +#define IMAGER_NAME " NWFS Volume IMAGER for Linux" +#endif + +#define COPYRIGHT_NOTICE1 " Copyright (c) 1997-2001 Jeff V. Merkey All Rights Reserved." +#define COPYRIGHT_NOTICE2 " " + +#define TargetOS "Linux" + +extern int log_printf(char *format, ...); +extern int log_sprintf(char *buffer, char *format, ...); + +#define NWFSPrint log_printf + +#define VCS_RESERVED 4 + +#include +#include +#include +#include +#include +#include + +#include "unistd.h" +#include "stdio.h" +#include "stdlib.h" +#include "fcntl.h" +#include "ctype.h" +#include "time.h" + +#ifndef M2FS_SERVER +#include "asm/string.h" +#endif + +#include "ncurses.h" +#include "termios.h" + +#ifndef LONGLONG +typedef long long LONGLONG; +#endif + +typedef unsigned long ULONG; +typedef unsigned short WORD; +typedef unsigned char BYTE; + +#include +#include +#include +#include +#include +#include +#include + +#include "nwfs.h" +#include "nwhash.h" +#include "nwstruct.h" +#include "nwerror.h" +#include "nwdir.h" +#include "nwproc.h" + +#include "nwvphal.h" +#include "nwvp.h" + +#include "nwmenu.h" + +#endif + +#endif // _NWFS_GLOBALS_ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/hash.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/hash.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/hash.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/hash.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,3223 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : HASH.C +* DESCRIP : NWFS Directory Management +* DATE : November 1, 1998 +* +***************************************************************************/ + +#include "globals.h" + +extern HASH *GetDeletedHashFromName(VOLUME *volume, BYTE *PathString, ULONG len, + ULONG NameSpace, ULONG Parent); + +#define MAX_FREE_HASH_ELEMENTS 50 + +HASH *HashHead = 0; +HASH *HashTail = 0; +ULONG FreeHashCount = 0; + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) +spinlock_t HashFree_spinlock; +ULONG HashFree_flags = 0; +#else +NWFSInitMutex(HashFreeSemaphore); +#endif +#endif + +void NWLockHashFreeList(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&HashFree_spinlock, HashFree_flags); +#else + if (WaitOnSemaphore(&HashFreeSemaphore) == -EINTR) + NWFSPrint("lock hash free list was interrupted\n"); +#endif +#endif +} + +void NWUnlockHashFreeList(void) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&HashFree_spinlock, HashFree_flags); +#else + SignalSemaphore(&HashFreeSemaphore); +#endif +#endif +} + + +void PutHashNode(HASH *hash) +{ + NWLockHashFreeList(); + + if (hash->Name) + NWFSFree(hash->Name); + hash->Name = 0; + hash->TurboFATCluster = 0; + hash->TurboFATIndex = 0; + + if (!HashHead) + { + HashHead = HashTail = hash; + hash->next = hash->prior = 0; + } + else + { + HashTail->next = hash; + hash->next = 0; + hash->prior = HashTail; + HashTail = hash; + } + FreeHashCount++; + +#if (CONSERVE_HASH_MEMORY) + // check if we have exceeded the max free list size, and discard + // the next free element. + if (FreeHashCount > MAX_FREE_HASH_ELEMENTS) + { + if (HashHead) + { + hash = HashHead; + HashHead = hash->next; + if (HashHead) + HashHead->prior = NULL; + else + HashTail = NULL; + + hash->Signature = 0; + + if (FreeHashCount) + FreeHashCount--; + + NWFSFree(hash); + + NWUnlockHashFreeList(); + return; + } + } +#endif + + NWUnlockHashFreeList(); + return; +} + +HASH *GetHashNode(void) +{ + register HASH *hash; + + NWLockHashFreeList(); + if (HashHead) + { + hash = HashHead; + HashHead = hash->next; + if (HashHead) + HashHead->prior = NULL; + else + HashTail = NULL; + + hash->Signature = (ULONG)"HASH"; + if (!InstanceCounter) + InstanceCounter = 1; + + if (FreeHashCount) + FreeHashCount--; + NWUnlockHashFreeList(); + return hash; + } + NWUnlockHashFreeList(); + return 0; +} + +BYTE *NSDescription(ULONG ns) +{ + switch (ns) + { + case 0: + return "DOS"; + + case 1: + return "MAC"; + + case 2: + return "NFS"; + + case 3: + return "FTAM"; + + case 4: + return "LONG"; + + case 5: + return "NT/NAFS"; + + default: + return "UNKN"; + } + +} + +// +// Linux directory shim functions +// + +ULONG get_directory_number(VOLUME *volume, const char *name, + ULONG len, ULONG Parent) +{ + register HASH *hash = 0; + + if ((len == 1) && (name[0] == '.')) + return Parent; + else + if ((len == 2) && (name[0] == '.') && (name[1] == '.')) + return get_parent_directory_number(volume, Parent); + else + { + if (volume->DeletedDirNo && (Parent == volume->DeletedDirNo)) + hash = GetDeletedHashFromName(volume, + (BYTE *)name, + len, + volume->NameSpaceDefault, + DELETED_DIRECTORY); + else + hash = GetHashFromName(volume, + (BYTE *)name, + len, + volume->NameSpaceDefault, + Parent); + } + + // map to the root namespace DirNo + if (hash) + return (ULONG) (hash->Root); + return 0; +} + +HASH *get_directory_hash(VOLUME *volume, const char *name, + ULONG len, ULONG Parent) +{ + register HASH *hash; + + if (volume->DeletedDirNo && (Parent == volume->DeletedDirNo)) + hash = GetDeletedHashFromName(volume, + (BYTE *)name, + len, + volume->NameSpaceDefault, + DELETED_DIRECTORY); + else + hash = GetHashFromName(volume, + (BYTE *)name, + len, + volume->NameSpaceDefault, + Parent); + + // map to the root namespace hash + if (hash) + return (HASH *) (hash->nlroot); + return 0; +} + +ULONG get_parent_directory_number(VOLUME *volume, ULONG DirNo) +{ + register HASH *hash; + + hash = GetHashFromDirectoryNumber(volume, DirNo); + if (hash) + { + if (hash->Parent == DELETED_DIRECTORY) + { + if (volume->DeletedDirNo) + return volume->DeletedDirNo; + else + return 0; + } + return (hash->Parent); + } + return 0; +} + +HASH *get_directory_record(VOLUME *volume, ULONG DirNo) +{ + if (volume->DeletedDirNo && (DirNo == DELETED_DIRECTORY)) + return (GetHashFromDirectoryNumber(volume, volume->DeletedDirNo)); + else + return (GetHashFromDirectoryNumber(volume, DirNo)); +} + +HASH *get_subdirectory_record(VOLUME *volume, ULONG entry, ULONG Parent, + HASH **dir) +{ + if (volume->DeletedDirNo && (Parent == volume->DeletedDirNo)) + return (GetHashNameSpaceEntry(volume, entry, volume->NameSpaceDefault, + DELETED_DIRECTORY, dir)); + else + return (GetHashNameSpaceEntry(volume, entry, volume->NameSpaceDefault, + Parent, dir)); +} + +ULONG get_namespace_dir_record(VOLUME *volume, DOS *dos, HASH *root, + ULONG NameSpace) +{ + register ULONG ccode; + register HASH *nlhash; + + nlhash = root; + while (nlhash) + { + if (nlhash->NameSpace == NameSpace) + { + ccode = ReadDirectoryRecord(volume, dos, nlhash->DirNo); + if (ccode) + return (ULONG) -1; + + return (ULONG) nlhash->DirNo; + } + nlhash = nlhash->nlnext; + } + return (ULONG) -1; +} + +ULONG get_namespace_directory_number(VOLUME *volume, HASH *root, + ULONG NameSpace) +{ + register HASH *nlhash; + + nlhash = root; + while (nlhash) + { + if (nlhash->NameSpace == NameSpace) + return (ULONG) nlhash->DirNo; + nlhash = nlhash->nlnext; + } + return (ULONG) -1; +} + +ULONG is_deleted(VOLUME *volume, HASH *hash) +{ + if ((hash->Flags & NW4_DELETED_FILE) || (hash->Flags & NW3_DELETED_FILE)) + { + return 1; + } + return 0; +} + +ULONG is_deleted_file(VOLUME *volume, HASH *hash) +{ + if ((hash->Flags & NW4_DELETED_FILE) || (hash->Flags & NW3_DELETED_FILE)) + { + if (!(hash->Flags & SUBDIRECTORY_FILE)) + return 1; + else + return 0; + } + return 0; +} + +ULONG is_deleted_dir(VOLUME *volume, HASH *hash) +{ + if ((hash->Flags & NW4_DELETED_FILE) || (hash->Flags & NW3_DELETED_FILE)) + { + if ((hash->Flags & SUBDIRECTORY_FILE) || (hash->Parent == (ULONG) -1)) + return 1; + else + return 0; + } + return 0; +} + + +#if (LINUX | LINUX_UTIL) + +// +// basic string hash function, but gives very good distribution +// model with standard ascii text. +// + +ULONG HornerStringHash(BYTE *v, ULONG len, ULONG M) +{ + register ULONG h = 0, a = 127, i; + + if (!M) + { + NWFSPrint("nwfs: horner hash limit error [%s] lim-%u\n", + v, (unsigned int)M); + return -1; + } + + for (i = 0; i < len && *v; v++, i++) + h = ((a * h) + *v) % M; + + return h; + +} + +// +// very good universal string hash function with a built-in random +// number genrator, but has more computational overhead. +// + +ULONG UniversalStringHash(BYTE *v, ULONG len, ULONG M) +{ + register ULONG h, a = 31415, b = 27163, i; + + if (!M) + { + NWFSPrint("nwfs: universal hash limit error [%s] lim-%u\n", + v, (unsigned int)M); + return -1; + } + + for (i = 0, h = 0; i < len && *v; i++, v++, a = (a * b) % (M - 1)) + h = ((a * h) + *v) % M; + + return h; + +} + +#endif + + +void NWLockNameHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->NameHash_spinlock, volume->NameHash_flags); +#else + if (WaitOnSemaphore(&volume->NameHashSemaphore) == -EINTR) + NWFSPrint("lock name hash was interrupted\n"); +#endif +#endif +} +void NWUnlockNameHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->NameHash_spinlock, volume->NameHash_flags); +#else + SignalSemaphore(&volume->NameHashSemaphore); +#endif +#endif +} + +void NWLockDirectoryHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->DirHash_spinlock, volume->DirHash_flags); +#else + if (WaitOnSemaphore(&volume->DirHashSemaphore) == -EINTR) + NWFSPrint("lock dir hash was interrupted\n"); +#endif +#endif +} + +void NWUnlockDirectoryHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->DirHash_spinlock, volume->DirHash_flags); +#else + SignalSemaphore(&volume->DirHashSemaphore); +#endif +#endif +} + +void NWLockParentHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->ParentHash_spinlock, volume->ParentHash_flags); +#else + if (WaitOnSemaphore(&volume->ParentHashSemaphore) == -EINTR) + NWFSPrint("lock parent hash was interrupted\n"); +#endif +#endif +} + +void NWUnlockParentHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->ParentHash_spinlock, + volume->ParentHash_flags); +#else + SignalSemaphore(&volume->ParentHashSemaphore); +#endif +#endif +} + +void NWLockTrusteeHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->TrusteeHash_spinlock, volume->TrusteeHash_flags); +#else + if (WaitOnSemaphore(&volume->TrusteeHashSemaphore) == -EINTR) + NWFSPrint("lock trustee hash was interrupted\n"); +#endif +#endif +} + +void NWUnlockTrusteeHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->TrusteeHash_spinlock, + volume->TrusteeHash_flags); +#else + SignalSemaphore(&volume->TrusteeHashSemaphore); +#endif +#endif +} + +void NWLockQuotaHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->QuotaHash_spinlock, volume->QuotaHash_flags); +#else + if (WaitOnSemaphore(&volume->QuotaHashSemaphore) == -EINTR) + NWFSPrint("lock quota hash was interrupted\n"); +#endif +#endif +} + +void NWUnlockQuotaHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->QuotaHash_spinlock, + volume->QuotaHash_flags); +#else + SignalSemaphore(&volume->QuotaHashSemaphore); +#endif +#endif +} + +void NWLockExtHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->ExtHash_spinlock, volume->ExtHash_flags); +#else + if (WaitOnSemaphore(&volume->ExtHashSemaphore) == -EINTR) + NWFSPrint("lock ext hash was interrupted\n"); +#endif +#endif +} + +void NWUnlockExtHash(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->ExtHash_spinlock, volume->ExtHash_flags); +#else + SignalSemaphore(&volume->ExtHashSemaphore); +#endif +#endif +} + +void NWLockNS(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->NameSpace_spinlock, volume->NameSpace_flags); +#else + if (WaitOnSemaphore(&volume->NameSpaceSemaphore) == -EINTR) + NWFSPrint("lock ns was interrupted\n"); +#endif +#endif +} + +void NWUnlockNS(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->NameSpace_spinlock, + volume->NameSpace_flags); +#else + SignalSemaphore(&volume->NameSpaceSemaphore); +#endif +#endif +} + +// we use the horner string hashing function for now + +ULONG NWFSStringHash(BYTE *v, ULONG len, ULONG M) +{ + return (HornerStringHash(v, len, M)); +} + +// need to add a splay tree in place of the linked list for the +// name hash at some point in the future. + +HASH *GetHashFromName(VOLUME *volume, BYTE *PathString, ULONG len, + ULONG NameSpace, ULONG Parent) +{ + register HASH *name; + register HASH_LIST *HashTable; + register ULONG Value; + register BYTE *CName; + register ULONG CLength; + register ULONG i, retCode; + BYTE UpperCaseName[256]; + BYTE DOSName[13]; + ULONG DOSLength = 0; + extern BYTE DOSUpperCaseTable[256]; + + // set these two variables to PathString and len as defaults + CName = PathString; + CLength = len; + + // if the DOS namespace is the volume default, then uppercase + // and convert all names prior to calculating their hash + // values. + + if (NameSpace == DOS_NAME_SPACE) + { + for (i=0; i < CLength; i++) + UpperCaseName[i] = DOSUpperCaseTable[(BYTE)PathString[i]]; + + retCode = NWCreateUniqueName(volume, Parent, UpperCaseName, CLength, + DOSName, (BYTE *)&DOSLength, 1); + if (retCode) + return 0; + + CName = DOSName; + CLength = DOSLength; + } + + Value = NWFSStringHash(CName, CLength, + volume->VolumeNameHashLimit[NameSpace & 0xF]); + + if (Value == -1) + { + NWFSPrint("nwfs: hashing function error\n"); + return 0; + } + + NWLockNameHash(volume); + HashTable = (HASH_LIST *) volume->VolumeNameHash[NameSpace & 0xF]; + if (!HashTable) + { + NWUnlockNameHash(volume); + return 0; + } + + name = (HASH *) HashTable[Value].head; + while (name) + { + if ((CLength == name->NameLength) && + (name->nlroot->Parent != (ULONG) DELETED_DIRECTORY) && + (name->Parent == Parent) && (name->Root != (ULONG) -1)) + { + if (!NWFSCompare(name->Name, CName, CLength)) + { + NWUnlockNameHash(volume); + return (HASH *) name; + } + } + name = name->next; + } + NWUnlockNameHash(volume); + return 0; + +} + +HASH *GetDeletedHashFromName(VOLUME *volume, BYTE *PathString, ULONG len, + ULONG NameSpace, ULONG Parent) +{ + register HASH *name; + register HASH_LIST *HashTable; + register ULONG Value; + register BYTE *CName; + register ULONG CLength; + register ULONG i, retCode; + BYTE UpperCaseName[256]; + BYTE DOSName[13]; + ULONG DOSLength = 0; + extern BYTE DOSUpperCaseTable[256]; + + // set these two variables to PathString and len as defaults + CName = PathString; + CLength = len; + + // if the DOS namespace is the volume default, then uppercase + // and convert all names prior to calculating their hash + // values. + + if (NameSpace == DOS_NAME_SPACE) + { + for (i=0; i < CLength; i++) + UpperCaseName[i] = DOSUpperCaseTable[(BYTE)PathString[i]]; + + retCode = NWCreateUniqueName(volume, Parent, UpperCaseName, CLength, + DOSName, (BYTE *)&DOSLength, 1); + if (retCode) + return 0; + + CName = DOSName; + CLength = DOSLength; + } + + Value = NWFSStringHash(CName, CLength, + volume->VolumeNameHashLimit[NameSpace & 0xF]); + + if (Value == -1) + { + NWFSPrint("nwfs: hashing function error\n"); + return 0; + } + + NWLockNameHash(volume); + HashTable = (HASH_LIST *) volume->VolumeNameHash[NameSpace & 0xF]; + if (!HashTable) + { + NWUnlockNameHash(volume); + return 0; + } + + name = (HASH *) HashTable[Value].head; + while (name) + { + if ((CLength == name->NameLength) && + (name->nlroot->Parent == (ULONG) DELETED_DIRECTORY) && + (name->Parent == Parent) && (name->Root != (ULONG) -1)) + { + if (!NWFSCompare(name->Name, CName, CLength)) + { + NWUnlockNameHash(volume); + return (HASH *) name; + } + } + name = name->next; + } + NWUnlockNameHash(volume); + return 0; + +} + +HASH *GetHashFromDirectoryNumber(VOLUME *volume, ULONG Directory) +{ + register HASH *name; + register HASH_LIST *HashTable; + register ULONG Value; + + NWLockDirectoryHash(volume); + + Value = (Directory & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (HASH_LIST *) volume->DirectoryNumberHash; + if (!HashTable) + { + NWUnlockDirectoryHash(volume); + return 0; + } + + name = (HASH *) HashTable[Value].head; + while (name) + { + if ((name->DirNo == Directory) && (name->Root != (ULONG) -1)) + { + NWUnlockDirectoryHash(volume); + return (HASH *) name; + } + name = name->dnext; + } + NWUnlockDirectoryHash(volume); + return 0; + +} + +EXTENDED_DIR_HASH *GetHashFromExtendedDirectoryNumber(VOLUME *volume, + ULONG Parent) +{ + register EXTENDED_DIR_HASH *name; + register EXT_HASH_LIST *HashTable; + register ULONG Value; + + NWLockExtHash(volume); + + Value = (Parent & (volume->ExtDirHashLimit - 1)); + HashTable = (EXT_HASH_LIST *) volume->ExtDirHash; + if (!HashTable) + { + NWUnlockExtHash(volume); + return 0; + } + + name = (EXTENDED_DIR_HASH *) HashTable[Value].head; + while (name) + { + if ((name->Parent == Parent) && (name->Root != (ULONG) -1)) + { + NWUnlockExtHash(volume); + return (EXTENDED_DIR_HASH *) name; + } + name = name->next; + } + NWUnlockExtHash(volume); + return 0; + +} + +HASH *GetHashNameSpaceEntry(VOLUME *volume, ULONG entry, + ULONG NameSpace, ULONG Directory, + HASH **DirectoryHash) +{ + register HASH *name, *nlname; + register HASH_LIST *HashTable; + register ULONG Value; + +#if (VERBOSE) + NWFSPrint("get_hash_entry %d parent %X namespace %d\n", + (int)entry, (unsigned)Directory, (int)NameSpace); +#endif + + if (DirectoryHash) + *DirectoryHash = 0; + + NWLockParentHash(volume); + Value = (Directory & (volume->ParentHashLimit - 1)); + HashTable = (HASH_LIST *) volume->ParentHash; + if (!HashTable) + { + NWUnlockParentHash(volume); + return 0; + } + + name = (HASH *) HashTable[Value].head; + while (name) + { + // skip records flagged as invalid and any root entries in the + // parent hash + if ((name->Parent == Directory) && (name->Root != (ULONG) -1)) + { + if (name->Root >= entry) + { + nlname = name->nlroot; + while (nlname) + { + if (nlname->NameSpace == NameSpace) + { + NWUnlockParentHash(volume); + return nlname; + } + nlname = nlname->nlnext; + } + NWUnlockParentHash(volume); + return name; + } + } + name = name->pnext; + } + NWUnlockParentHash(volume); + return 0; + +} + +HASH *AllocHashNode(void) +{ + register HASH *hash; + + hash = GetHashNode(); + if (!hash) + { + hash = NWFSAlloc(sizeof(HASH_UNION), HASH_TAG); + if (hash) + { + NWFSSet(hash, 0, sizeof(HASH_UNION)); + + hash->Signature = (ULONG)"HASH"; + if (!InstanceCounter) + InstanceCounter = 1; + +#if (LINUX_SLEEP) + AllocateSemaphore(&hash->Semaphore, 1); +#endif + } + } + else + { + hash->Signature = (ULONG)"HASH"; + if (!InstanceCounter) + InstanceCounter = 1; + + if (hash->Name) + NWFSFree(hash->Name); + hash->Name = 0; + hash->Blocks = 0; + hash->TurboFATCluster = 0; + hash->TurboFATIndex = 0; + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = (ULONG)-1; + hash->FileSize = 0; +#endif + } + return hash; +} + +void FreeHashNode(HASH *hash) +{ + hash->Signature = 0; + hash->pnext = 0; + hash->pprior = 0; + hash->Blocks = 0; + hash->TurboFATCluster = 0; + hash->TurboFATIndex = 0; + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = (ULONG)-1; + hash->FileSize = 0; +#endif + PutHashNode(hash); + return; +} + +void FreeHashNodes(void) +{ + register HASH *hash; + + NWLockHashFreeList(); + while (HashHead) + { + hash = HashHead; + HashHead = HashHead->next; + + if (hash->Name) + NWFSFree(hash->Name); + hash->Name = 0; + hash->Blocks = 0; + hash->TurboFATCluster = 0; + hash->TurboFATIndex = 0; + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = (ULONG)-1; + hash->FileSize = 0; +#endif + NWFSFree(hash); + } + NWUnlockHashFreeList(); + return; +} + +HASH *CreateHashNode(DOS *dos, ULONG DirNo) +{ + register ROOT *root; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + register TRUSTEE *trustee; + register USER *user; + register HASH *name; + register THASH *tname; + register UHASH *uname; + + switch (dos->Subdirectory) + { + case TRUSTEE_NODE: + tname = (THASH *) NWFSAlloc(sizeof(HASH_UNION), HASH_TAG); + if (tname) + { + trustee = (TRUSTEE *) dos; + tname->Parent = trustee->Subdirectory; + tname->DirNo = DirNo; + tname->NextTrustee = trustee->NextTrusteeEntry; + tname->FileEntryNumber = trustee->FileEntryNumber; + tname->Flags = trustee->Flags; + tname->Attributes = trustee->Attributes; + return (HASH *) tname; + } + return 0; + + case RESTRICTION_NODE: + uname = (UHASH *) NWFSAlloc(sizeof(HASH_UNION), HASH_TAG); + if (uname) + { + user = (USER *) dos; + uname->Parent = user->Subdirectory; + uname->DirNo = DirNo; + uname->TrusteeCount = user->TrusteeCount; + return (HASH *) uname; + } + return 0; + + case SUBALLOC_NODE: + case FREE_NODE: + return 0; + + case ROOT_NODE: + name = (HASH *) AllocHashNode(); + if (name) + { + root = (ROOT *) dos; + name->NameLength = 0; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + { + NWFSFree(name); + return 0; + } + NWFSCopy(name->Name, "", name->NameLength); + name->Name[name->NameLength] = '\0'; + name->Parent = (ULONG) ROOT_NODE; + name->DirNo = DirNo; + name->Root = 0; // primary entry is assumed as zero + name->NameSpace = root->NameSpace; + name->NameLink = root->NameList; + name->Flags = root->Flags; + name->NextTrustee = root->NextTrusteeEntry; + +#if (HASH_FAT_CHAINS) + name->FileAttributes = root->FileAttributes; + name->FileSize = 0; + name->FirstBlock = 0; +#endif + + return name; + } + return 0; + + default: + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: + name = (HASH *) AllocHashNode(); + if (!name) + return 0; + + name->NameLength = dos->FileNameLength; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + { + NWFSFree(name); + return 0; + } + NWFSCopy(name->Name, dos->FileName, name->NameLength); + + name->Name[name->NameLength] = '\0'; + name->Parent = dos->Subdirectory; + name->DirNo = DirNo; + name->Root = dos->PrimaryEntry; + name->NameSpace = dos->NameSpace; + name->NameLink = dos->NameList; + name->Flags = dos->Flags; + name->NextTrustee = dos->NextTrusteeEntry; + +#if (HASH_FAT_CHAINS) + name->FileAttributes = dos->FileAttributes; + if (dos->Flags & SUBDIRECTORY_FILE) + { + name->FileSize = 0; + name->FirstBlock = 0; + } + else + { + name->FileSize = dos->FileSize; + name->FirstBlock = dos->FirstBlock; + } +#endif + + return name; + + case MAC_NAME_SPACE: + mac = (MACINTOSH *) dos; + name = (HASH *) AllocHashNode(); + if (!name) + return 0; + + name->NameLength = mac->FileNameLength; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + { + NWFSFree(name); + return 0; + } + NWFSCopy(name->Name, mac->FileName, name->NameLength); + + name->Name[name->NameLength] = '\0'; + name->Parent = mac->Subdirectory; + name->DirNo = DirNo; + name->Root = mac->PrimaryEntry; + name->NameSpace = mac->NameSpace; + name->NameLink = mac->NameList; + name->Flags = mac->Flags; + +#if (HASH_FAT_CHAINS) + name->FirstBlock = mac->ResourceFork; + name->FileSize = mac->ResourceForkSize; +#endif + + return name; + + case UNIX_NAME_SPACE: + nfs = (NFS *) dos; + name = (HASH *) AllocHashNode(); + if (!name) + return 0; + + name->NameLength = nfs->TotalFileNameLength; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + { + NWFSFree(name); + return 0; + } + NWFSCopy(name->Name, nfs->FileName, nfs->FileNameLength); + + name->Name[name->NameLength] = '\0'; + name->Parent = nfs->Subdirectory; + name->DirNo = DirNo; + name->Root = nfs->PrimaryEntry; + name->NameSpace = nfs->NameSpace; + name->NameLink = nfs->NameList; + name->Flags = nfs->Flags; + +#if (HASH_FAT_CHAINS) + name->FirstBlock = 0; +#endif + + return name; + + case LONG_NAME_SPACE: + longname = (LONGNAME *) dos; + name = (HASH *) AllocHashNode(); + if (!name) + return 0; + + name->NameLength = (WORD)(longname->FileNameLength + longname->ExtendedSpace); + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + { + NWFSFree(name); + return 0; + } + NWFSCopy(name->Name, longname->FileName, longname->FileNameLength); + + name->Name[name->NameLength] = '\0'; + name->Parent = longname->Subdirectory; + name->DirNo = DirNo; + name->Root = longname->PrimaryEntry; + name->NameSpace = longname->NameSpace; + name->NameLink = longname->NameList; + name->Flags = longname->Flags; + +#if (HASH_FAT_CHAINS) + name->FirstBlock = 0; +#endif + + return name; + + case NT_NAME_SPACE: + nt = (NTNAME *) dos; + name = (HASH *) AllocHashNode(); + if (!name) + return 0; + + name->NameLength = nt->FileNameLength + nt->LengthData; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + { + NWFSFree(name); + return 0; + } + NWFSCopy(name->Name, nt->FileName, nt->FileNameLength); + + name->Name[name->NameLength] = '\0'; + name->Parent = nt->Subdirectory; + name->DirNo = DirNo; + name->Root = nt->PrimaryEntry; + name->NameSpace = nt->NameSpace; + name->NameLink = nt->NameList; + name->Flags = nt->Flags; + +#if (HASH_FAT_CHAINS) + name->FirstBlock = 0; +#endif + + return name; + + case FTAM_NAME_SPACE: + default: + return 0; + } + return 0; + } + return 0; + +} + +BYTE *CreateNameField(DOS *dos, HASH *name) +{ + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: + name->NameLength = dos->FileNameLength; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + return name->Name; + NWFSCopy(name->Name, dos->FileName, name->NameLength); + name->Name[name->NameLength] = '\0'; + return name->Name; + + case MAC_NAME_SPACE: + mac = (MACINTOSH *) dos; + name->NameLength = mac->FileNameLength; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + return name->Name; + NWFSCopy(name->Name, mac->FileName, name->NameLength); + name->Name[name->NameLength] = '\0'; + return name->Name; + + case UNIX_NAME_SPACE: + nfs = (NFS *) dos; + name->NameLength = nfs->TotalFileNameLength; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + return name->Name; + NWFSCopy(name->Name, nfs->FileName, nfs->FileNameLength); + name->Name[name->NameLength] = '\0'; + return name->Name; + + case LONG_NAME_SPACE: + longname = (LONGNAME *) dos; + name->NameLength = (WORD)(longname->FileNameLength + longname->ExtendedSpace); + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + return name->Name; + NWFSCopy(name->Name, longname->FileName, longname->FileNameLength); + name->Name[name->NameLength] = '\0'; + return name->Name; + + case NT_NAME_SPACE: + nt = (NTNAME *) dos; + name->NameLength = nt->FileNameLength + nt->LengthData; + name->Name = NWFSAlloc(name->NameLength + 1, NAME_STORAGE_TAG); + if (!name->Name) + return name->Name; + NWFSCopy(name->Name, nt->FileName, nt->FileNameLength); + name->Name[name->NameLength] = '\0'; + return name->Name; + + case FTAM_NAME_SPACE: + default: + return 0; + } + return 0; + +} + +ULONG HashDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo) +{ + register HASH *dirHash; + register HASH *name; + register THASH *tname; + register UHASH *uname; + register ULONG retCode, i; + +#if (STRICT_NAMES) + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; +#endif + + // + // processor dependent max number of directories is addr max - 3 + // reserved dir numbers are as follows: + // + // 0 = root directory + // -1 = free dir block list + // -2 = deleted dir block list + // 1 to -3 = valid directory record numbers + // + + if ((!DirNo) && (dos->Subdirectory != ROOT_NODE)) + { + NWFSPrint("nwfs: root directory record is invalid\n"); + return NwHashError; + } + + if ((ULONG) DirNo > (ULONG) -3) + { + NWFSPrint("nwfs: directory number is a reserved value\n"); + return (ULONG) NwInvalidParameter; + } + + if (GetHashFromDirectoryNumber(volume, DirNo)) + { + NWFSPrint("nwfs: duplicate dir no detected (%d)\n", (int)DirNo); + return (ULONG) 0; + } + + switch (dos->Subdirectory) + { + case TRUSTEE_NODE: + tname = (THASH *) CreateHashNode(dos, DirNo); + if (!tname) + { + NWFSPrint("nwfs: could not alloc trustee hash DirNo-%d\n", (int)DirNo); + return NwHashError; + } + retCode = AddToTrusteeHash(volume, tname); + if (retCode) + { + NWFSFree((void *)tname); + NWFSPrint("nwfs: could not insert trustee hash node\n"); + return NwHashError; + } + retCode = AddTrusteeToDirectoryHash(volume, tname); + if (retCode) + { + RemoveTrusteeHash(volume, tname); + NWFSFree((void *)tname); + NWFSPrint("nwfs: could not insert trustee directory hash node\n"); + return NwHashError; + } + break; + + case RESTRICTION_NODE: + uname = (UHASH *) CreateHashNode(dos, DirNo); + if (!uname) + { + NWFSPrint("nwfs: could not alloc user quota hash DirNo-%d\n", (int)DirNo); + return NwHashError; + } + retCode = AddToUserQuotaHash(volume, uname); + if (retCode) + { + NWFSFree((void *)uname); + NWFSPrint("nwfs: could not insert user quota hash node\n"); + return NwHashError; + } + retCode = AddUserQuotaToDirectoryHash(volume, uname); + if (retCode) + { + RemoveUserQuotaHash(volume, uname); + NWFSFree((void *)uname); + NWFSPrint("nwfs: could not insert user quota directory hash node\n"); + return NwHashError; + } + break; + + case SUBALLOC_NODE: // this case is handled in NWDIR.C + case FREE_NODE: + break; + + case ROOT_NODE: + name = CreateHashNode(dos, DirNo); + if (!name) + { + NWFSPrint("nwfs: could not alloc root hash DirNo-%d\n", (int)DirNo); + return NwHashError; + } + retCode = AddToNameHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert root hash node\n"); + FreeHashNode(name); + return NwHashError; + } + retCode = AddToDirectoryHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert dir root hash node\n"); + RemoveNameHash(volume, name); + FreeHashNode(name); + return NwHashError; + } + if (name->NameSpace == DOS_NAME_SPACE) + { + retCode = AddToParentHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + RemoveDirectoryHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert parent root node\n"); + return NwHashError; + } + volume->DirectoryCount++; + } + break; + + default: + if (!dos->FileNameLength) + { + NWFSPrint("nwfs: invalid namespace directory record [%X]-%X\n", + (int)dos->PrimaryEntry, (unsigned int)DirNo); + return NwHashError; + } + + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: +#if (STRICT_NAMES) + retCode = NWValidDOSName(volume, + dos->FileName, + dos->FileNameLength, + dos->Subdirectory, + 0); + if (retCode) + { + NWFSPrint("nwfs: invalid DOS name dirno-%X [", + (unsigned int)DirNo); + for (i=0; i < dos->FileNameLength; i++) + NWFSPrint("%c", dos->FileName[i]); + NWFSPrint("]-(%d)\n", dos->FileNameLength); + + retCode = NWMangleDOSName(volume, dos->FileName, + dos->FileNameLength, dos, + dos->Subdirectory); + if (retCode) + return NwHashError; + } +#endif + // build an assignment list for any data streams + // detected for files other than directories in the dos + // namespace. skip hard links, as several directory + // entries may be linked to a single fat chain. + + if (!(dos->Flags & SUBDIRECTORY_FILE) && + !(dos->Flags & HARD_LINKED_FILE)) + { + retCode = BuildChainAssignment(volume, dos->FirstBlock, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0)); + if (retCode) + { + NWFSPrint("nwfs: (%d) suballoc not enabled on this volume\n", + (int) retCode); + return NwHashError; + } + } + + name = CreateHashNode(dos, DirNo); + if (!name) + { + NWFSPrint("nwfs: could not alloc name hash DirNo-%d\n", (int)DirNo); + return NwHashError; + } + + retCode = AddToNameHash(volume, name); + if (retCode) + { + FreeHashNode(name); + NWFSPrint("nwfs: could not insert name hash node [%s]\n", name->Name); + return NwHashError; + } + retCode = AddToDirectoryHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert dir hash node [%s]\n", name->Name); + return NwHashError; + } + + if ((dos->Flags & NW4_DELETED_FILE) || + (dos->Flags & NW3_DELETED_FILE)) + { + retCode = AddToMountHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + RemoveDirectoryHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert deleted hash node [%s]\n", name->Name); + return NwHashError; + } + break; + } + + // It is possible that during volume mount we might + // reference a parent entry in the directory file + // that has a higher DirNo than a child entry. Since + // we don't want to perform multiple passes through + // the diretory file during volume mount, we store this + // hash element on a temporary list. Following the + // first pass through the directory file, we traverse + // this list and attempt to resolve any orphaned + // hash records. + + dirHash = GetHashFromDirectoryNumber(volume, name->Parent); + if (!dirHash) + { + retCode = AddToMountHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + RemoveDirectoryHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert parent hash node [%s]\n", name->Name); + return NwHashError; + } + } + else + { + retCode = AddToParentHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + RemoveDirectoryHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert parent hash node [%s]\n", name->Name); + return NwHashError; + } + if (name->Flags & SUBDIRECTORY_FILE) + volume->DirectoryCount++; + } + + if ((!volume->DeletedDirNo) && + (!NWFSCompare(name->Name, "DELETED.SAV", 11))) + volume->DeletedDirNo = name->DirNo; + + break; + + case MAC_NAME_SPACE: +#if (STRICT_NAMES) + mac = (MACINTOSH *) dos; + retCode = NWValidMACName(volume, + mac->FileName, + mac->FileNameLength, + mac->Subdirectory, + 0); + if (retCode) + { + NWFSPrint("nwfs: invalid MAC name dirno-%X [", + (unsigned int)DirNo); + for (i=0; i < mac->FileNameLength; i++) + NWFSPrint("%c", mac->FileName[i]); + NWFSPrint("]\n"); + + retCode = NWMangleMACName(volume, mac->FileName, + mac->FileNameLength, mac, + mac->Subdirectory); + if (retCode) + return NwHashError; + } +#endif + // build an assignment list for any mac resource forks + // detected for files other than directories in the mac + // namespace. skip hard linked files since several + // directory entries may point to the same fat chain. + + if (!(dos->Flags & SUBDIRECTORY_FILE) && + !(dos->Flags & HARD_LINKED_FILE)) + { + retCode = BuildChainAssignment(volume, mac->ResourceFork, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0)); + if (retCode) + { + NWFSPrint("nwfs: suballoc not enabled on this volume\n"); + return NwHashError; + } + } + goto CreateHash; + + case UNIX_NAME_SPACE: +#if (STRICT_NAMES) + nfs = (NFS *) dos; + retCode = NWValidNFSName(volume, + nfs->FileName, + nfs->FileNameLength, + nfs->Subdirectory, + 0); + if (retCode) + { + NWFSPrint("nwfs: invalid UNIX name dirno-%X [", + (unsigned int)DirNo); + for (i=0; i < nfs->FileNameLength; i++) + NWFSPrint("%c", nfs->FileName[i]); + NWFSPrint("]\n"); + + retCode = NWMangleNFSName(volume, nfs->FileName, + nfs->FileNameLength, nfs, + nfs->Subdirectory); + if (retCode) + return NwHashError; + } + goto CreateHash; +#endif + + case LONG_NAME_SPACE: +#if (STRICT_NAMES) + longname = (LONGNAME *) dos; + retCode = NWValidLONGName(volume, + longname->FileName, + longname->FileNameLength, + longname->Subdirectory, + 0); + if (retCode) + { + NWFSPrint("nwfs: invalid LONG name dirno-%X [", + (unsigned int)DirNo); + for (i=0; i < longname->FileNameLength; i++) + NWFSPrint("%c", longname->FileName[i]); + NWFSPrint("]\n"); + + retCode = NWMangleLONGName(volume, longname->FileName, + longname->FileNameLength, + longname, + longname->Subdirectory); + if (retCode) + return NwHashError; + } + goto CreateHash; +#endif + + case NT_NAME_SPACE: +#if (STRICT_NAMES) + nt = (NTNAME *) dos; + retCode = NWValidLONGName(volume, + nt->FileName, + nt->FileNameLength, + nt->Subdirectory, + 0); + if (retCode) + { + NWFSPrint("nwfs: invalid NT name dirno-%X [", + (unsigned int)DirNo); + for (i=0; i < nt->FileNameLength; i++) + NWFSPrint("%c", nt->FileName[i]); + NWFSPrint("]\n"); + + retCode = NWMangleLONGName(volume, nt->FileName, + nt->FileNameLength, + (LONGNAME *)nt, + nt->Subdirectory); + if (retCode) + return NwHashError; + } +CreateHash:; + +#endif + name = CreateHashNode(dos, DirNo); + if (!name) + { + NWFSPrint("nwfs: could not alloc name hash DirNo-%d\n", (int)DirNo); + return NwHashError; + } + retCode = AddToNameHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert name hash node [%s]\n", name->Name); + FreeHashNode(name); + return NwHashError; + } + retCode = AddToDirectoryHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert dir hash node [%s]\n", name->Name); + RemoveNameHash(volume, name); + FreeHashNode(name); + return NwHashError; + } + break; + + case FTAM_NAME_SPACE: // We have not seen this namespace. + default: + break; + } + break; + } + return 0; + +} + +HASH *AllocHashDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo) +{ + register HASH *name = 0; + register ULONG retCode; + + // + // processor dependent max number of directories is machine + // dependent address maximum - 4 + // reserved dir numbers are as follows: + // + // 0 = root directory + // -1 = free dir block list + // -2 = deleted dir block list + // 1 to -3 = valid dir block list values + // + // Netware places limitations on the percentage + // of a volume that a directory file is allowed + // to occupy. + + // check for valid directory number range + if ((ULONG) DirNo > (ULONG) -4) + return (ULONG) 0; + + if (GetHashFromDirectoryNumber(volume, DirNo)) + { + NWFSPrint("nwfs: duplicate dir no detected (%d)\n", (int)DirNo); + return (ULONG) 0; + } + + switch (dos->Subdirectory) + { + case TRUSTEE_NODE: + case RESTRICTION_NODE: + case SUBALLOC_NODE: + case FREE_NODE: + return 0; + + case ROOT_NODE: + name = CreateHashNode(dos, DirNo); + if (!name) + { + NWFSPrint("nwfs: could not alloc name hash DirNo-%d\n", (int)DirNo); + return 0; + } + retCode = AddToNameHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert name hash node [%s]\n", name->Name); + FreeHashNode(name); + return 0; + } + retCode = AddToDirectoryHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert dir hash node [%s]\n", name->Name); + RemoveNameHash(volume, name); + FreeHashNode(name); + return 0; + } + + if (name->NameSpace == DOS_NAME_SPACE) + { + retCode = AddToParentHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + RemoveDirectoryHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert parent root node\n"); + return 0; + } + + // link into namespace chain + retCode = InsertNameSpaceElement(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert root namespace link node\n"); + RemoveParentHash(volume, name); + RemoveDirectoryHash(volume, name); + RemoveNameHash(volume, name); + FreeHashNode(name); + return 0; + } + volume->DirectoryCount++; + } + break; + + default: + if (!dos->FileNameLength) + { + NWFSPrint("nwfs: invalid namespace directory record [%X]-%X\n", + (int)dos->PrimaryEntry, (unsigned int)DirNo); + return 0; + } + + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: + name = CreateHashNode(dos, DirNo); + if (!name) + { + NWFSPrint("nwfs: could not alloc name hash DirNo-%d\n", (int)DirNo); + return 0; + } + retCode = AddToNameHash(volume, name); + if (retCode) + { + FreeHashNode(name); + NWFSPrint("nwfs: could not insert name hash node [%s]\n", name->Name); + return 0; + } + retCode = AddToDirectoryHash(volume, name); + if (retCode) + { + RemoveNameHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert dir hash node [%s]\n", name->Name); + return 0; + } + + if ((dos->Flags & NW4_DELETED_FILE) || + (dos->Flags & NW3_DELETED_FILE)) + name->Parent = DELETED_DIRECTORY; + + retCode = AddToParentHash(volume, name); + if (retCode) + { + RemoveDirectoryHash(volume, name); + RemoveNameHash(volume, name); + FreeHashNode(name); + NWFSPrint("nwfs: could not insert parent hash node [%s]\n", name->Name); + return 0; + } + + // link into namespace chain + retCode = InsertNameSpaceElement(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert dir name link node [%s]\n", name->Name); + RemoveParentHash(volume, name); + RemoveDirectoryHash(volume, name); + RemoveNameHash(volume, name); + FreeHashNode(name); + return 0; + } + + if (name->Flags & SUBDIRECTORY_FILE) + volume->DirectoryCount++; + break; + + case MAC_NAME_SPACE: + case UNIX_NAME_SPACE: + case LONG_NAME_SPACE: + case NT_NAME_SPACE: + name = CreateHashNode(dos, DirNo); + if (!name) + { + NWFSPrint("nwfs: could not alloc name hash DirNo-%d\n", (int)DirNo); + return 0; + } + retCode = AddToNameHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert name hash node [%s]\n", name->Name); + FreeHashNode(name); + return 0; + } + retCode = AddToDirectoryHash(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert dir hash node [%s]\n", name->Name); + RemoveNameHash(volume, name); + FreeHashNode(name); + return 0; + } + + // link into namespace chain + retCode = InsertNameSpaceElement(volume, name); + if (retCode) + { + NWFSPrint("nwfs: could not insert dir name link node [%s]\n", name->Name); + RemoveDirectoryHash(volume, name); + RemoveNameHash(volume, name); + FreeHashNode(name); + return 0; + } + break; + + case FTAM_NAME_SPACE: + default: + break; + } + break; + } + return name; + +} + +ULONG FreeHashDirectoryRecord(VOLUME *volume, HASH *hash) +{ + // set the hash element signature to 0 to prevent + // dir lookups during hash deletions. + hash->Signature = 0; + + if (hash->NameSpace == DOS_NAME_SPACE) + { + if (hash->Flags & SUBDIRECTORY_FILE) + { + if (volume->DirectoryCount) + volume->DirectoryCount--; + } + RemoveParentHash(volume, hash); + } + RemoveDirectoryHash(volume, hash); + RemoveNameHash(volume, hash); + FreeHashNode(hash); + + return 0; +} + +ULONG HashExtendedDirectoryRecord(VOLUME *volume, EXTENDED_DIR *dir, + ULONG Cluster, ULONG DirNo) +{ + register ULONG retCode; + register EXTENDED_DIR_HASH *ext; + + switch (dir->Signature) + { + case EXTENDED_DIR_STAMP: + case LONG_EXTENDED_DIR_STAMP: + case NT_EXTENDED_DIR_STAMP: + case NFS_EXTENDED_DIR_STAMP: + case MIGRATE_DIR_STAMP: + case TALLY_EXTENDED_DIR_STAMP: + case EXTENDED_ATTRIBUTE_DIR_STAMP: + ext = NWFSAlloc(sizeof(EXTENDED_DIR_HASH) + 1, EXT_HASH_TAG); + if (!ext) + { + NWFSPrint("nwfs: could not alloc extended hash DirNo-%d\n", (int)DirNo); + return -1; + } + NWFSSet(ext, 0, sizeof(EXTENDED_DIR_HASH)); + + ext->ExtDirNo = DirNo; + ext->Parent = dir->DirectoryNumber; + ext->Signature = dir->Signature; + ext->Length = dir->Length; + ext->NameSpace = dir->NameSpace; + ext->Flags = dir->Flags; + ext->ControlFlags = dir->ControlFlags; + + retCode = AddToExtHash(volume, ext); + if (retCode) + { + NWFSPrint("nwfs: could not add extended dir node\n"); + NWFSFree(ext); + return -1; + } + break; + + default: + break; + } + return 0; + +} + +// +// During initial reading of the directory file, it may have been +// possible that vrepair could have previoulsy had to reshuffle +// records due to block dir assignment errors. These means that some +// namespace records may not have been written in monatomically +// ascending order in the dir file. Since we have not completely +// cached all of the dir no assignments during initial mount, then +// it is possible that a record being linked into a namespace chain +// may point down rather than up with regard to the root DOS entry +// for a filename that has mulitple namespace entries. because of this, +// we are forced to link the namespaces after all of the directory +// records have been scanned into the dir number hash. If we attempt +// to force the namespace link before we have hashed all of the dir +// records, then we may not be able to link in all the records. +// +// during normal creates (after the dir file has been hashed) its +// a simple matter to link namespace records together, but during +// mount we are forced to provide a separate function that walks +// the entire directory file hash and links the records together. +// this is not a particularly elegant way to do accomplish this, +// however, it allows us to avoid making multiple passes through +// the directory file during volume mount. +// +// we always assume that when we break down and free namespace lists, +// we consume the list linkage and free the list as we traverse it. +// + +HASH *RemoveNameSpaceElement(VOLUME *volume, HASH *hash) +{ + register HASH *searchHash, *root; + + root = hash->nlroot; + if (!root) + { + NWFSPrint("nwfs: nlroot invalid in RemoveNameSpaceElement\n"); + return 0; + } + + // if this element is the root, then exit + if (hash == root) + return 0; + + NWLockNS(volume); + + // check and make certain this element is really linked + searchHash = root->nlnext; + while (searchHash) + { + if (searchHash == hash) + { + if (root->nlnext == hash) + { + root->nlnext = (void *) hash->nlnext; + if (root->nlnext) + root->nlnext->nlprior = NULL; + else + root->nlprior = NULL; + } + else + { + hash->nlprior->nlnext = hash->nlnext; + if (hash != root->nlprior) + hash->nlnext->nlprior = hash->nlprior; + else + root->nlprior = hash->nlprior; + } + NWUnlockNS(volume); + return hash; + } + searchHash = searchHash->nlnext; + } + NWUnlockNS(volume); + return 0; + +} + +ULONG InsertNameSpaceElement(VOLUME *volume, HASH *hash) +{ + register HASH *searchHash, *root; + + // check if this is a root entry, if so then exit + if (hash->DirNo == hash->Root) + { + // this element is root + hash->nlroot = hash; + hash->nlnext = hash->nlprior = 0; + return 0; + } + + root = GetHashFromDirectoryNumber(volume, hash->Root); + if (!root) + { + NWFSPrint("nwfs: root dirno error InsertNameSpaceElement [%X->%X]\n", + (unsigned int) hash->DirNo, + (unsigned int) hash->Root); + return NwHashError; + } + + // if we found ourself, then exit (this shouldn't ever happen) + if (hash == root) + { + NWFSPrint("nwfs: root hash was cyclic in InsertNameSpaceElement\n"); + + // this element is root + hash->nlroot = hash; + hash->nlnext = hash->nlprior = 0; + return NwHashError; + } + + // save the root hash entry for this element + hash->nlroot = root; + hash->Parent = root->Parent; + + // set the namespace record's parent to the root parent. deleted + // files may not have them set equal. + hash->Parent = root->Parent; + + NWLockNS(volume); + + // check and make certain we have not already linked this element + searchHash = root->nlnext; + while (searchHash) + { + if (searchHash == hash) + { + NWUnlockNS(volume); + return NwHashError; + } + searchHash = searchHash->nlnext; + } + + if (!root->nlnext) + { + root->nlnext = hash; + root->nlprior = hash; + hash->nlnext = hash->nlprior = 0; + } + else + { + root->nlprior->nlnext = hash; + hash->nlnext = 0; + hash->nlprior = root->nlprior; + root->nlprior = hash; + } + + NWUnlockNS(volume); + + return 0; + +} + +ULONG LinkVolumeNameSpaces(VOLUME *volume) +{ + register HASH_LIST *HashTable; + HASH *name, *nlname; + register ULONG i, r, NameSpace, count, retCode, NameList; + ULONG HashTraceCount; + HASH *HashTrace[MAX_NAMESPACES]; + BYTE FoundNameSpace[MAX_NAMESPACES]; + ULONG FoundNameSpaceDirNo[MAX_NAMESPACES]; + ULONG NameLinkTrace[MAX_NAMESPACES]; + ULONG NameLinkCount, j; + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Linking Volume Namespaces ***\n"); +#endif + + for (r=0; r < MAX_NAMESPACES; r++) + { + FoundNameSpace[r] = 0; + FoundNameSpaceDirNo[r] = 0; + } + + // first we validate the NameLink field for the root namespace (DOS) + // and verify the primary entry number of all linked records. if + // we detect a corrupted name link field, then we return an error + // and refuse to mount the volume. The user must run vrepair. + // This error indicates that the volume directory file hash been + // corrupted. + + NWLockNameHash(volume); + for (i=0; i < volume->NameSpaceCount; i++) + { + NameSpace = volume->NameSpaceID[i]; + if (NameSpace == DOS_NAME_SPACE) + { + if (volume->VolumeNameHash[NameSpace & 0xF]) + { + HashTable = (HASH_LIST *) volume->VolumeNameHash[NameSpace & 0xF]; + + for (count=0; + count < volume->VolumeNameHashLimit[NameSpace & 0xF]; + count++) + { + name = (HASH *) HashTable[count].head; + while (name) + { + HashTraceCount = NameLinkCount = 0; + NWFSSet(&HashTrace[0], 0, (sizeof(HASH *) * MAX_NAMESPACES)); + NWFSSet(&NameLinkTrace[0], 0, (sizeof(ULONG) * MAX_NAMESPACES)); + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + NWFSSet(&FoundNameSpaceDirNo[0], 0, (sizeof(ULONG) * MAX_NAMESPACES)); + + FoundNameSpace[name->NameSpace & 0xF] = TRUE; + FoundNameSpaceDirNo[name->NameSpace & 0xF] = name->DirNo; + HashTrace[HashTraceCount++] = name; + + NameList = name->NameLink; + while (NameList) + { + NameLinkTrace[NameLinkCount++] = NameList; + + // see if this name list field points to a valid + // directory record + nlname = GetHashFromDirectoryNumber(volume, NameList); + if (!nlname) + { + NWFSPrint("nwfs: record [%X] has invalid name list\n", + (unsigned int)NameList); + NWUnlockNameHash(volume); + return NwDirectoryCorrupt; + } + HashTrace[HashTraceCount++] = nlname; + + // see if this dir record primary entry points back to + // the root DOS entry. Netware tolerates this error + // in the directory, so we ignore the inconsistency + // and correct the hash in memory and in the directory. + + if (nlname->Root != name->DirNo) + { + NWFSPrint("nwfs: record [%X]-[%s] invalid primary entry [R-%X/D-%X]\n", + (unsigned int)NameList, + nlname->Name, + (unsigned int)nlname->Root, + (unsigned int)name->DirNo); + + for (j=0; j < NameLinkCount; j++) + { + if ((j + 1) >= NameLinkCount) + NWFSPrint("0x%08X\n", + (unsigned int)NameLinkTrace[j]); + else + NWFSPrint("0x%08X -> ", + (unsigned int)NameLinkTrace[j]); + } + + for (j=0; j < HashTraceCount; j++) + { + extern ULONG dumpRecord(BYTE *, ULONG); + extern ULONG dumpRecordBytes(BYTE *, ULONG); + + if (HashTrace[j]) + { + NWFSPrint("hash-%08X\n", + (unsigned int)HashTrace[j]); + dumpRecord((BYTE *)HashTrace[j], sizeof(HASH)); + dumpRecordBytes((BYTE *)HashTrace[j], sizeof(HASH)); + if (HashTrace[j]->Name) + dumpRecordBytes(HashTrace[j]->Name, + HashTrace[j]->NameLength); + } + } + nlname->Root = name->DirNo; + } + + // see if we have multiple entries in the name list + // that are the same name space + if (FoundNameSpace[nlname->NameSpace & 0xF]) + { + NWFSPrint("nwfs: multiple name space error [%X/%X] NS-(%d)\n", + (unsigned int)FoundNameSpaceDirNo[name->NameSpace & 0xF], + (unsigned int)nlname->DirNo, + (int)nlname->NameSpace); + + for (j=0; j < NameLinkCount; j++) + { + if ((j + 1) >= NameLinkCount) + NWFSPrint("0x%08X\n", + (unsigned int)NameLinkTrace[j]); + else + NWFSPrint("0x%08X ->", + (unsigned int)NameLinkTrace[j]); + } + + for (j=0; j < HashTraceCount; j++) + { + extern ULONG dumpRecord(BYTE *, ULONG); + extern ULONG dumpRecordBytes(BYTE *, ULONG); + + if (HashTrace[j]) + { + dumpRecord((BYTE *)HashTrace[j], sizeof(HASH)); + dumpRecordBytes((BYTE *)HashTrace[j], sizeof(HASH)); + if (HashTrace[j]->Name) + dumpRecordBytes(HashTrace[j]->Name, + HashTrace[j]->NameLength); + } + } + + NWUnlockNameHash(volume); + return NwDirectoryCorrupt; + } + + FoundNameSpace[nlname->NameSpace & 0xF] = TRUE; + FoundNameSpaceDirNo[nlname->NameSpace & 0xF] = nlname->DirNo; + + NameList = nlname->NameLink; + } + name = name->next; + } + } + break; + } + } + } + + // now we make a second pass through the namespaces and + // link the namespace records onto the root entry in the name + // hash. + + for (i=0; i < volume->NameSpaceCount; i++) + { + NameSpace = volume->NameSpaceID[i]; + if (volume->VolumeNameHash[NameSpace & 0xF]) + { + HashTable = (HASH_LIST *) volume->VolumeNameHash[NameSpace & 0xF]; + for (count=0; + count < volume->VolumeNameHashLimit[NameSpace & 0xF]; + count++) + { + name = (HASH *) HashTable[count].head; + while (name) + { + // if we fail to locate the root entry for this record, + // then flag the hash record as invalid. this will tell + // the search routines to ignore the record. We will remove + // the record later. + + retCode = InsertNameSpaceElement(volume, name); + if (retCode) + name->Root = (ULONG) -1; + + name = name->next; + } + } + } + } + NWUnlockNameHash(volume); + return 0; + +} + +ULONG ProcessOrphans(VOLUME *volume) +{ + register ULONG retCode; + register HASH *hash, *listHash, *searchHash; + + while (volume->HashMountHead) + { + hash = volume->HashMountHead; + volume->HashMountHead = hash->pnext; + + if (!volume->HashMountHead) + volume->HashMountTail = 0; + + if ((hash->Flags & NW4_DELETED_FILE) || + (hash->Flags & NW3_DELETED_FILE)) + hash->Parent = DELETED_DIRECTORY; + + retCode = AddToParentHash(volume, hash); + if (retCode) + { + // see if this hash record's parent is further down + // on the hash mount list. If so, insert this record at + // the end of the list, and process again after the parent + // has been added. + + searchHash = volume->HashMountHead; + while (searchHash) + { + if (searchHash->DirNo == hash->Parent) + { + retCode = AddToMountHash(volume, hash); + if (retCode) + break; + else + goto SkipRecord; + } + searchHash = searchHash->pnext; + } + + // if we detect an orphaned file, remove the hash and + // all associated namespace records for this entry. + + NWFSPrint("nwfs: orphaned file [%s] detected [%X/%X]\n", + hash->Name, (unsigned int)hash->DirNo, + (unsigned int)hash->Parent); + + listHash = hash; + while (listHash) + { + hash = listHash; + listHash = listHash->nlnext; + if (hash->NameSpace == DOS_NAME_SPACE) + { + // set the hash element signature to 0 to prevent + // dir lookups during hash deletions. + hash->Signature = 0; + + RemoveDirectoryHash(volume, hash); + RemoveNameHash(volume, hash); + FreeHashNode(hash); + } + else + FreeHashDirectoryRecord(volume, hash); + } + } + if (hash->Flags & SUBDIRECTORY_FILE) + volume->DirectoryCount++; + +SkipRecord:; + } + return 0; + +} + +void FreeVolumeNamespaces(VOLUME *volume) +{ + register HASH_LIST *HashTable; + register HASH *name, *list; + register THASH *tname, *tlist; + register UHASH *uname, *ulist; + register EXTENDED_DIR_HASH *ext, *extlist; + register ULONG i, NameSpace, count; + + // the directory and parent hash records cross reference to the + // name space, trustee, and user quota hashes + + NWLockDirectoryHash(volume); + if (volume->DirectoryNumberHash) + NWFSFree(volume->DirectoryNumberHash); + volume->DirectoryNumberHashLimit = 0; + volume->DirectoryNumberHash = 0; + NWUnlockDirectoryHash(volume); + + NWLockParentHash(volume); + if (volume->ParentHash) + NWFSFree(volume->ParentHash); + volume->ParentHashLimit = 0; + volume->ParentHash = 0; + NWUnlockParentHash(volume); + + NWLockExtHash(volume); + if (volume->ExtDirHash) + { + HashTable = (HASH_LIST *) volume->ExtDirHash; + for (count=0; count < volume->ExtDirHashLimit; count++) + { + extlist = (EXTENDED_DIR_HASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].tail = 0; + while (extlist) + { + ext = extlist; + extlist = extlist->next; + NWFSFree((void *)ext); + } + } + NWFSFree(volume->ExtDirHash); + } + volume->ExtDirHashLimit = 0; + volume->ExtDirHash = 0; + NWUnlockExtHash(volume); + + NWLockTrusteeHash(volume); + if (volume->TrusteeHash) + { + HashTable = (HASH_LIST *) volume->TrusteeHash; + for (count=0; count < volume->TrusteeHashLimit; count++) + { + tlist = (THASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].tail = 0; + while (tlist) + { + tname = tlist; + tlist = tlist->next; + NWFSFree((void *)tname); + } + } + NWFSFree(volume->TrusteeHash); + } + volume->TrusteeHashLimit = 0; + volume->TrusteeHash = 0; + NWUnlockTrusteeHash(volume); + + NWLockQuotaHash(volume); + if (volume->UserQuotaHash) + { + HashTable = (HASH_LIST *) volume->UserQuotaHash; + for (count=0; count < volume->UserQuotaHashLimit; count++) + { + ulist = (UHASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].tail = 0; + while (ulist) + { + uname = ulist; + ulist = ulist->next; + NWFSFree((void *)uname); + } + } + NWFSFree(volume->UserQuotaHash); + } + volume->UserQuotaHashLimit = 0; + volume->UserQuotaHash = 0; + NWUnlockQuotaHash(volume); + + NWLockNameHash(volume); + for (i=0; i < volume->NameSpaceCount; i++) + { + NameSpace = volume->NameSpaceID[i]; + + if (volume->VolumeNameHash[NameSpace & 0xF]) + { + HashTable = (HASH_LIST *) volume->VolumeNameHash[NameSpace & 0xF]; + for (count=0; + count < volume->VolumeNameHashLimit[NameSpace & 0xF]; + count++) + { + list = (HASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].tail = 0; + while (list) + { + name = list; + list = list->next; + FreeHashNode(name); + } + } + NWFSFree(volume->VolumeNameHash[NameSpace & 0xF]); + } + volume->VolumeNameHashLimit[NameSpace & 0xF] = 0; + volume->VolumeNameHash[NameSpace & 0xF] = 0; + } + NWUnlockNameHash(volume); + +} + +// +// +// + +ULONG AddToNameHash(VOLUME *volume, HASH *name) +{ + register ULONG Value; + register HASH_LIST *HashTable; + + Value = NWFSStringHash(name->Name, name->NameLength, + volume->VolumeNameHashLimit[name->NameSpace]); + if (Value == (ULONG) -1) + return -1; + + NWLockNameHash(volume); + + HashTable = (HASH_LIST *) volume->VolumeNameHash[name->NameSpace & 0xF]; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->next = name->prior = 0; + } + else + { + HashTable[Value].tail->next = name; + name->next = 0; + name->prior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockNameHash(volume); + return 0; + } + NWUnlockNameHash(volume); + return -1; +} + +ULONG RemoveNameHash(VOLUME *volume, HASH *name) +{ + register ULONG Value; + register HASH_LIST *HashTable; + + Value = NWFSStringHash(name->Name, name->NameLength, + volume->VolumeNameHashLimit[name->NameSpace]); + if (Value == (ULONG) -1) + return -1; + + NWLockNameHash(volume); + HashTable = (HASH_LIST *) volume->VolumeNameHash[name->NameSpace & 0xF]; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->next; + if (HashTable[Value].head) + HashTable[Value].head->prior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->prior->next = name->next; + if (name != HashTable[Value].tail) + name->next->prior = name->prior; + else + HashTable[Value].tail = name->prior; + } + NWUnlockNameHash(volume); + return 0; + } + NWUnlockNameHash(volume); + return -1; +} + +// +// +// + + +ULONG AddToDirectoryHash(VOLUME *volume, HASH *name) +{ + register ULONG Value; + register HASH_LIST *HashTable; + + NWLockDirectoryHash(volume); + Value = (name->DirNo & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (HASH_LIST *) volume->DirectoryNumberHash; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->dnext = name->dprior = 0; + } + else + { + HashTable[Value].tail->dnext = name; + name->dnext = 0; + name->dprior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockDirectoryHash(volume); + return 0; + } + NWUnlockDirectoryHash(volume); + return -1; +} + +ULONG RemoveDirectoryHash(VOLUME *volume, HASH *name) +{ + register ULONG Value; + register HASH_LIST *HashTable; + + NWLockDirectoryHash(volume); + Value = (name->DirNo & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (HASH_LIST *) volume->DirectoryNumberHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->dnext; + if (HashTable[Value].head) + HashTable[Value].head->dprior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->dprior->dnext = name->dnext; + if (name != HashTable[Value].tail) + name->dnext->dprior = name->dprior; + else + HashTable[Value].tail = name->dprior; + } + NWUnlockDirectoryHash(volume); + return 0; + } + NWUnlockDirectoryHash(volume); + return -1; +} + +ULONG AddTrusteeToDirectoryHash(VOLUME *volume, THASH *name) +{ + register ULONG Value; + register THASH_LIST *HashTable; + + NWLockDirectoryHash(volume); + Value = (name->DirNo & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (THASH_LIST *) volume->DirectoryNumberHash; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->dnext = name->dprior = 0; + } + else + { + HashTable[Value].tail->dnext = name; + name->dnext = 0; + name->dprior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockDirectoryHash(volume); + return 0; + } + NWUnlockDirectoryHash(volume); + return -1; +} + +ULONG RemoveTrusteeFromDirectoryHash(VOLUME *volume, THASH *name) +{ + register ULONG Value; + register THASH_LIST *HashTable; + + NWLockDirectoryHash(volume); + Value = (name->DirNo & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (THASH_LIST *) volume->DirectoryNumberHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->dnext; + if (HashTable[Value].head) + HashTable[Value].head->dprior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->dprior->dnext = name->dnext; + if (name != HashTable[Value].tail) + name->dnext->dprior = name->dprior; + else + HashTable[Value].tail = name->dprior; + } + NWUnlockDirectoryHash(volume); + return 0; + } + NWUnlockDirectoryHash(volume); + return -1; +} + +ULONG AddUserQuotaToDirectoryHash(VOLUME *volume, UHASH *name) +{ + register ULONG Value; + register UHASH_LIST *HashTable; + + NWLockDirectoryHash(volume); + Value = (name->DirNo & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (UHASH_LIST *) volume->DirectoryNumberHash; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->dnext = name->dprior = 0; + } + else + { + HashTable[Value].tail->dnext = name; + name->dnext = 0; + name->dprior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockDirectoryHash(volume); + return 0; + } + NWUnlockDirectoryHash(volume); + return -1; +} + +ULONG RemoveUserQuotaFromDirectoryHash(VOLUME *volume, UHASH *name) +{ + register ULONG Value; + register UHASH_LIST *HashTable; + + NWLockDirectoryHash(volume); + Value = (name->DirNo & (volume->DirectoryNumberHashLimit - 1)); + HashTable = (UHASH_LIST *) volume->DirectoryNumberHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->dnext; + if (HashTable[Value].head) + HashTable[Value].head->dprior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->dprior->dnext = name->dnext; + if (name != HashTable[Value].tail) + name->dnext->dprior = name->dprior; + else + HashTable[Value].tail = name->dprior; + } + NWUnlockDirectoryHash(volume); + return 0; + } + NWUnlockDirectoryHash(volume); + return -1; +} + +ULONG AddToMountHash(VOLUME *volume, HASH *name) +{ + if (name->Parent == (ULONG) -1) + return -1; + + if (name->NameSpace == DOS_NAME_SPACE) + { + NWLockParentHash(volume); + if (!volume->HashMountHead) + { + volume->HashMountHead = name; + volume->HashMountTail = name; + name->pnext = name->pprior = 0; + } + else + { + volume->HashMountTail->pnext = name; + name->pnext = 0; + name->pprior = volume->HashMountTail; + volume->HashMountTail = name; + } + NWUnlockParentHash(volume); + return 0; + } + return -1; +} + +ULONG RemoveMountHash(VOLUME *volume, HASH *name) +{ + if (name->Parent == (ULONG) -1) + return -1; + + if (name->NameSpace == DOS_NAME_SPACE) + { + NWLockParentHash(volume); + if (volume->HashMountHead == name) + { + volume->HashMountHead = name->pnext; + if (volume->HashMountHead) + volume->HashMountHead->pprior = NULL; + else + volume->HashMountTail = NULL; + } + else + { + name->pprior->pnext = name->pnext; + if (name != volume->HashMountTail) + name->pnext->pprior = name->pprior; + else + volume->HashMountTail = name->pprior; + } + NWUnlockParentHash(volume); + return 0; + } + return -1; +} + +ULONG AddToDelMountHash(VOLUME *volume, HASH *name) +{ + if (name->Parent == (ULONG) -1) + return -1; + + NWLockParentHash(volume); + if (!volume->DelHashMountHead) + { + volume->DelHashMountHead = name; + volume->DelHashMountTail = name; + name->pnext = name->pprior = 0; + } + else + { + volume->DelHashMountTail->pnext = name; + name->pnext = 0; + name->pprior = volume->DelHashMountTail; + volume->DelHashMountTail = name; + } + NWUnlockParentHash(volume); + return 0; +} + +ULONG RemoveDelMountHash(VOLUME *volume, HASH *name) +{ + if (name->Parent == (ULONG) -1) + return -1; + + NWLockParentHash(volume); + if (volume->DelHashMountHead == name) + { + volume->DelHashMountHead = name->pnext; + if (volume->DelHashMountHead) + volume->DelHashMountHead->pprior = NULL; + else + volume->DelHashMountTail = NULL; + } + else + { + name->pprior->pnext = name->pnext; + if (name != volume->DelHashMountTail) + name->pnext->pprior = name->pprior; + else + volume->DelHashMountTail = name->pprior; + } + NWUnlockParentHash(volume); + return 0; +} + +// +// +// + +ULONG AddToTrusteeHash(VOLUME *volume, THASH *name) +{ + register ULONG Value; + register THASH_LIST *HashTable; + + NWLockTrusteeHash(volume); + Value = (name->Parent & (volume->TrusteeHashLimit - 1)); + HashTable = (THASH_LIST *) volume->TrusteeHash; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->next = name->prior = 0; + } + else + { + HashTable[Value].tail->next = name; + name->next = 0; + name->prior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockTrusteeHash(volume); + return 0; + } + NWUnlockTrusteeHash(volume); + return -1; +} + +ULONG RemoveTrusteeHash(VOLUME *volume, THASH *name) +{ + register ULONG Value; + register THASH_LIST *HashTable; + + NWLockTrusteeHash(volume); + Value = (name->Parent & (volume->TrusteeHashLimit - 1)); + HashTable = (THASH_LIST *) volume->TrusteeHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->next; + if (HashTable[Value].head) + HashTable[Value].head->prior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->prior->next = name->next; + if (name != HashTable[Value].tail) + name->next->prior = name->prior; + else + HashTable[Value].tail = name->prior; + } + NWUnlockTrusteeHash(volume); + return 0; + } + NWUnlockTrusteeHash(volume); + return -1; +} + +// +// +// + +ULONG AddToUserQuotaHash(VOLUME *volume, UHASH *name) +{ + register ULONG Value; + register UHASH_LIST *HashTable; + + NWLockQuotaHash(volume); + Value = (name->Parent & (volume->UserQuotaHashLimit - 1)); + HashTable = (UHASH_LIST *) volume->UserQuotaHash; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->next = name->prior = 0; + } + else + { + HashTable[Value].tail->next = name; + name->next = 0; + name->prior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockQuotaHash(volume); + return 0; + } + NWUnlockQuotaHash(volume); + return -1; +} + +ULONG RemoveUserQuotaHash(VOLUME *volume, UHASH *name) +{ + register ULONG Value; + register UHASH_LIST *HashTable; + + NWLockQuotaHash(volume); + Value = (name->Parent & (volume->UserQuotaHashLimit - 1)); + HashTable = (UHASH_LIST *) volume->UserQuotaHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->next; + if (HashTable[Value].head) + HashTable[Value].head->prior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->prior->next = name->next; + if (name != HashTable[Value].tail) + name->next->prior = name->prior; + else + HashTable[Value].tail = name->prior; + } + NWUnlockQuotaHash(volume); + return 0; + } + NWUnlockQuotaHash(volume); + return -1; +} + +// +// +// + +ULONG AddToExtHash(VOLUME *volume, EXTENDED_DIR_HASH *name) +{ + register ULONG Value; + register EXT_HASH_LIST *HashTable; + + NWLockExtHash(volume); + + Value = (name->Parent & (volume->ExtDirHashLimit - 1)); + HashTable = (EXT_HASH_LIST *) volume->ExtDirHash; + if (HashTable) + { + if (!HashTable[Value].head) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->next = name->prior = 0; + } + else + { + HashTable[Value].tail->next = name; + name->next = 0; + name->prior = HashTable[Value].tail; + HashTable[Value].tail = name; + } + NWUnlockExtHash(volume); + return 0; + } + NWUnlockExtHash(volume); + return -1; +} + +ULONG RemoveExtHash(VOLUME *volume, EXTENDED_DIR_HASH *name) +{ + register ULONG Value; + register EXT_HASH_LIST *HashTable; + + NWLockExtHash(volume); + Value = (name->Parent & (volume->ExtDirHashLimit - 1)); + HashTable = (EXT_HASH_LIST *) volume->ExtDirHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->next; + if (HashTable[Value].head) + HashTable[Value].head->prior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->prior->next = name->next; + if (name != HashTable[Value].tail) + name->next->prior = name->prior; + else + HashTable[Value].tail = name->prior; + } + NWUnlockExtHash(volume); + return 0; + } + NWUnlockExtHash(volume); + return -1; +} + +// +// +// + +ULONG AddToParentHash(VOLUME *volume, HASH *name) +{ + register ULONG Value; + register HASH *dirHash; + register HASH_LIST *HashTable; + + if (name->Parent == (ULONG) -1) + return -1; + + if (name->NameSpace == DOS_NAME_SPACE) + { + NWLockParentHash(volume); + switch (name->Parent) + { + case DELETED_DIRECTORY: + if (volume->DeletedDirNo) + dirHash = GetHashFromDirectoryNumber(volume, + volume->DeletedDirNo); + else + dirHash = 0; + break; + + case ROOT_NODE: + dirHash = GetHashFromDirectoryNumber(volume, 0); + break; + + default: + dirHash = GetHashFromDirectoryNumber(volume, name->Parent); + if (!dirHash) + { + NWFSPrint("nwfs: orphaned file (%X) detected parent-%X (PH)\n", + (unsigned int)name->DirNo, + (unsigned int)name->Parent); + } + break; + } + + Value = (name->Parent & (volume->ParentHashLimit - 1)); + HashTable = (HASH_LIST *) volume->ParentHash; + if (HashTable) + { + HASH *old, *p; + + if (!HashTable[Value].tail) + { + HashTable[Value].head = name; + HashTable[Value].tail = name; + name->pnext = name->pprior = 0; + } + else + { + p = HashTable[Value].head; + old = NULL; + while (p) + { + if ((p->Parent != name->Parent) || (p->DirNo < name->DirNo)) + { + old = p; + p = p->pnext; + } + else + { + if (p->pprior) + { + p->pprior->pnext = name; + name->pnext = p; + name->pprior = p->pprior; + p->pprior = name; + goto parent_inserted; + } + name->pnext = p; + name->pprior = NULL; + p->pprior = name; + HashTable[Value].head = name; + goto parent_inserted; + } + } + old->pnext = name; + name->pnext = NULL; + name->pprior = old; + HashTable[Value].tail = name; + } + +parent_inserted:; + + if (dirHash) + dirHash->Blocks++; + + NWUnlockParentHash(volume); + return 0; + } + NWUnlockParentHash(volume); + } + return -1; +} + +ULONG RemoveParentHash(VOLUME *volume, HASH *name) +{ + register ULONG Value; + register HASH *dirHash; + register HASH_LIST *HashTable; + + if (name->Parent == (ULONG) -1) + return -1; + + if (name->NameSpace == DOS_NAME_SPACE) + { + NWLockParentHash(volume); + Value = (name->Parent & (volume->ParentHashLimit - 1)); + HashTable = (HASH_LIST *) volume->ParentHash; + if (HashTable) + { + if (HashTable[Value].head == name) + { + HashTable[Value].head = name->pnext; + if (HashTable[Value].head) + HashTable[Value].head->pprior = NULL; + else + HashTable[Value].tail = NULL; + } + else + { + name->pprior->pnext = name->pnext; + if (name != HashTable[Value].tail) + name->pnext->pprior = name->pprior; + else + HashTable[Value].tail = name->pprior; + } + + if (name->Parent == (ULONG)ROOT_NODE) + dirHash = GetHashFromDirectoryNumber(volume, 0); + else + if ((name->Parent == DELETED_DIRECTORY) && (volume->DeletedDirNo)) + dirHash = GetHashFromDirectoryNumber(volume, + volume->DeletedDirNo); + else + dirHash = GetHashFromDirectoryNumber(volume, name->Parent); + + if (dirHash) + dirHash->Blocks--; + + NWUnlockParentHash(volume); + return 0; + } + NWUnlockParentHash(volume); + } + return -1; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/inode.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/inode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/inode.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,615 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : INODE.C +* DESCRIP : NWFS VFS inode Module for Linux +* DATE : November 16, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +// +// NOTE: nwfs will only preserve unix style permissions if the NFS +// namespace has been installed on a netware volume. Otherwise, +// nwfs will either emulate fat based files systems if the DOS namespace +// or LONG namespace if the default. You can create device special files +// with fenris, however, the device information will not be valid unless +// on NFS namespace is installed on the volume. +// + + +int nwfs_notify_change(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + register ULONG retCode, DirNo, flags; + DOS stdos; + DOS *dos = &stdos; + NFS stnfs; + NFS *nfs = &stnfs; + +#if (VERBOSE) + NWFSPrint("notify change %s\n", dentry->d_name.name); +#endif + + if (inode == NULL) + { + NWFSPrint("nwfs: inode = NULL\n"); + return -EACCES; + } + + if (!hash) + { +#if (VERBOSE) + NWFSPrint("nwfs: NULL inode hash in notify_change\n"); +#endif + hash = get_directory_record(volume, inode->i_ino); + if (!hash) + { + NWFSPrint("nwfs: inode number (%d) not found notify_change\n", + (int)inode->i_ino); + return -EACCES; + } + + // save the hash pointer for this inode + inode->u.generic_ip = hash; + } + + if (hash->DirNo != inode->i_ino) + { + NWFSPrint("nwfs: inode and parent hash are inconsistent\n"); + return -EACCES; + } + + NWLockFileExclusive(hash); + + if (volume->NameSpaceDefault == UNIX_NAME_SPACE) + { + DirNo = get_namespace_dir_record(volume, (DOS *)nfs, + hash, UNIX_NAME_SPACE); + if (DirNo != (ULONG) -1) + { + if (attr->ia_valid & ATTR_UID) + { + inode->i_uid = attr->ia_uid; + nfs->uid = inode->i_uid; + } + + if (attr->ia_valid & ATTR_GID) + { + inode->i_gid = attr->ia_gid; + nfs->gid = inode->i_gid; + } + + if (attr->ia_valid & ATTR_MODE) + { + inode->i_mode = attr->ia_mode; + nfs->mode = inode->i_mode; + } + + // save the redev info + nfs->rdev = inode->i_rdev; + + retCode = WriteDirectoryRecord(volume, (DOS *)nfs, DirNo); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return -EIO; + } + } + } + + retCode = ReadDirectoryRecord(volume, dos, inode->i_ino); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) file read error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return -EIO; + } + + if (attr->ia_valid & ATTR_SIZE) + { + dos->FileSize = attr->ia_size; + inode->i_size = attr->ia_size; + } + +#if (HASH_FAT_CHAINS) + dos->FirstBlock = hash->FirstBlock; +#endif + + if (attr->ia_valid & ATTR_CTIME) + { + if (hash->Parent == DELETED_DIRECTORY) + dos->DeletedDateAndTime = NWFSSystemToNetwareTime(attr->ia_ctime); + else + dos->CreateDateAndTime = NWFSSystemToNetwareTime(attr->ia_ctime); + inode->i_ctime = attr->ia_ctime; + } + + if (attr->ia_valid & ATTR_MTIME) + { + dos->LastUpdatedDateAndTime = NWFSSystemToNetwareTime(attr->ia_mtime); + inode->i_mtime = attr->ia_mtime; + } + + if (attr->ia_valid & ATTR_ATIME) + { + dos->LastArchivedDateAndTime = NWFSSystemToNetwareTime(attr->ia_atime); + inode->i_atime = attr->ia_atime; + } + + if (attr->ia_valid & ATTR_ATTR_FLAG) + { + flags = attr->ia_attr_flags; + if (flags & ATTR_FLAG_SYNCRONOUS) + inode->i_flags |= MS_SYNCHRONOUS; + else + inode->i_flags &= ~MS_SYNCHRONOUS; + + if (flags & ATTR_FLAG_NOATIME) + inode->i_flags |= MS_NOATIME; + else + inode->i_flags &= ~MS_NOATIME; + + if (flags & ATTR_FLAG_APPEND) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + +#ifndef CONFIG_VSERVERCTX + if (flags & ATTR_FLAG_IMMUTABLE) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; +#else + if (flags & ATTR_FLAG_IMMUTABLE_FILE) + inode->i_flags |= S_IMMUTABLE_FILE; + else + inode->i_flags &= ~S_IMMUTABLE_FILE; +#endif /* CONFIG_VSERVERCTX */ + } + + retCode = WriteDirectoryRecord(volume, dos, inode->i_ino); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return -EIO; + } + + NWUnlockFile(hash); + + return 0; +} + +void nwfs_put_inode(struct inode *inode) +{ + +#if (VERBOSE) + NWFSPrint("put inode %X\n", (unsigned)(inode ? inode->i_ino : 0)); +#endif + + if (!inode) + return; + + if (!inode->u.generic_ip) + return; + +// inode->u.generic_ip = 0; + + if (inode->i_count.counter == 1) + inode->i_nlink = 0; + + return; +} + +void nwfs_read_inode(struct inode *inode) +{ + register HASH *hash; + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register ino_t ino = inode->i_ino; + register ULONG retCode; + register ULONG DirNo; + DOS stdos; + DOS *dos = &stdos; + NFS stnfs; + NFS *nfs = &stnfs; + extern struct address_space_operations nwfs_symlink_aops; + extern struct address_space_operations nwfs_aops; + +#if (VERBOSE) + NWFSPrint("read inode %X\n", (unsigned)(inode ? inode->i_ino : 0)); +#endif + + if (!inode) + return; + + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_size = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = 0; + inode->i_blocks = 0; + inode->i_blksize = 512; + + hash = get_directory_record(volume, inode->i_ino); + if (!hash) + { +#if (VERBOSE) + NWFSPrint("nwfs: inode number (%d) not found in directory\n", (int)ino); +#endif + return; + } + + // save the hash pointer for this inode + inode->u.generic_ip = hash; + + NWLockFile(hash); + + retCode = ReadDirectoryRecord(volume, dos, inode->i_ino); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) directory read error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return; + } + + if (hash->Parent == DELETED_DIRECTORY) + inode->i_ctime = + NWFSNetwareToSystemTime(dos->DeletedDateAndTime); + else + inode->i_ctime = + NWFSNetwareToSystemTime(dos->CreateDateAndTime); + + inode->i_mtime = + NWFSNetwareToSystemTime(dos->LastUpdatedDateAndTime); + inode->i_atime = + NWFSNetwareToSystemTime(dos->LastArchivedDateAndTime); + + // + // Root entry is inode number 0. We use the Netware directory numbers + // as the inode numbers and we fill in the numbers inside of this + // function. By default, if the volume does not host an NFS namespace + // we default to an MSDOS behavior relative to unix-style file + // permissions. If the LONG namespace is present, we support unix + // names, however, unix permissions are emulated as in the FAT + // filesystem. If the NFS namespace is present on the volume, then + // we support unix permissions and device files on a NetWare volume. + // + // The code below determines which namespace is present as the default, + // then assigns permissions accordingly. + // + + // fill in the inode for the root of the volume if we get an inode + // number of zero. + + if (!ino) + { + // if root, initialize the uid and gid volume fields + volume->uid = current->fsuid; + volume->gid = current->fsgid; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + + if (volume->VolumeFlags & READ_ONLY_VOLUME) + inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; + else + inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; + + switch (volume->NameSpaceDefault) + { + case UNIX_NAME_SPACE: + DirNo = get_namespace_dir_record(volume, (DOS *)nfs, + hash, UNIX_NAME_SPACE); + if (DirNo != (ULONG) -1) + { + // if nfs namespace has been initialized + if (nfs->mode) + { + inode->i_uid = nfs->uid; + inode->i_gid = nfs->gid; + inode->i_mode = nfs->mode | S_IFDIR; + inode->i_rdev = nfs->rdev; + break; + } + } + inode->i_uid = volume->uid; + inode->i_gid = volume->gid; + inode->i_mode |= S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; + break; + + case DOS_NAME_SPACE: + case MAC_NAME_SPACE: + case LONG_NAME_SPACE: + case NT_NAME_SPACE: + default: + inode->i_uid = volume->uid; + inode->i_gid = volume->gid; + inode->i_mode |= S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; + break; + } + + inode->i_op = &nwfs_dir_inode_operations; + inode->i_fop = &nwfs_dir_operations; + inode->i_nlink = 2 + hash->Blocks; + inode->i_size = hash->Blocks * sizeof(ROOT); + inode->i_blocks = hash->Blocks; + + NWUnlockFile(hash); + return; + } + + // we detected a directory + if ((hash->Flags & SUBDIRECTORY_FILE) || (hash->Parent == (ULONG) -1)) + { + switch (volume->NameSpaceDefault) + { + case UNIX_NAME_SPACE: + DirNo = get_namespace_dir_record(volume, (DOS *)nfs, + hash, UNIX_NAME_SPACE); + if (DirNo != (ULONG) -1) + { + // if nfs namespace has been initialized + if (nfs->mode) + { + inode->i_uid = nfs->uid; + inode->i_gid = nfs->gid; + inode->i_mode = nfs->mode | S_IFDIR; + inode->i_rdev = nfs->rdev; + break; + } + } + inode->i_uid = volume->uid; + inode->i_gid = volume->gid; + inode->i_mode |= S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; + break; + + case DOS_NAME_SPACE: + case MAC_NAME_SPACE: + case LONG_NAME_SPACE: + case NT_NAME_SPACE: + default: + inode->i_uid = volume->uid; + inode->i_gid = volume->gid; + inode->i_mode |= S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; + break; + } + if (S_ISLNK(inode->i_mode)) + { + inode->i_op = &nwfs_symlink_inode_operations; + inode->i_data.a_ops = &nwfs_symlink_aops; + } + else + { + inode->i_op = &nwfs_dir_inode_operations; + inode->i_fop = &nwfs_dir_operations; + } + inode->i_nlink = 2 + hash->Blocks; // dirs have 2 links + dirs + inode->i_size = hash->Blocks * sizeof(ROOT); + inode->i_blocks = hash->Blocks; + } + else + { + // we detected a file + switch (volume->NameSpaceDefault) + { + case UNIX_NAME_SPACE: + DirNo = get_namespace_dir_record(volume, (DOS *)nfs, + hash, UNIX_NAME_SPACE); + if (DirNo != (ULONG) -1) + { + // if nfs namespace has been initialized + if (nfs->mode) + { + inode->i_uid = nfs->uid; + inode->i_gid = nfs->gid; + inode->i_mode = nfs->mode; + inode->i_rdev = nfs->rdev; + + if (nfs->nlinks) + inode->i_nlink = nfs->nlinks; + else + inode->i_nlink = 1; + break; + } + } + inode->i_uid = volume->uid; + inode->i_gid = volume->gid; + inode->i_mode |= S_IRUGO | S_IXUGO | S_IWUSR | S_IFREG; + inode->i_nlink = 1; + break; + + case DOS_NAME_SPACE: + case MAC_NAME_SPACE: + case LONG_NAME_SPACE: + case NT_NAME_SPACE: + default: + inode->i_uid = volume->uid; + inode->i_gid = volume->gid; + inode->i_mode |= S_IRUGO | S_IXUGO | S_IWUSR | S_IFREG; + inode->i_nlink = 1; + break; + } + + if (S_ISLNK(inode->i_mode)) + { + inode->i_op = &nwfs_symlink_inode_operations; + inode->i_mapping->a_ops = &nwfs_symlink_aops; + } + else + { + inode->i_op = &nwfs_file_inode_operations; + inode->i_fop = &nwfs_file_operations; + inode->i_mapping->a_ops = &nwfs_aops; + } + inode->i_size = dos->FileSize; + inode->i_blocks = (dos->FileSize + 511) / 512; + } + + NWUnlockFile(hash); + return; + +} + +void nwfs_write_inode(struct inode *inode, int wait) +{ + register VOLUME *volume = (VOLUME *) inode->i_sb->u.generic_sbp; + register HASH *hash = (HASH *) inode->u.generic_ip; + register ULONG retCode, DirNo; + DOS stdos; + DOS *dos = &stdos; + NFS stnfs; + NFS *nfs = &stnfs; + +#if (VERBOSE) + NWFSPrint("write inode %X\n", (unsigned)(inode ? inode->i_ino : 0)); +#endif + + if (inode == NULL) + { + NWFSPrint("nwfs: inode = NULL\n"); + return; + } + + if (!hash) + { +#if (VERBOSE) + NWFSPrint("nwfs: NULL inode hash in write_inode\n"); +#endif + hash = get_directory_record(volume, inode->i_ino); + if (!hash) + { + NWFSPrint("nwfs: inode number (%d) not found write_inode\n", + (int)inode->i_ino); + return; + } + + // save the hash pointer for this inode + inode->u.generic_ip = hash; + } + + if (hash->DirNo != inode->i_ino) + { + NWFSPrint("nwfs: inode and parent hash are inconsistent\n"); + return; + } + + NWLockFileExclusive(hash); + + if (volume->NameSpaceDefault == UNIX_NAME_SPACE) + { + DirNo = get_namespace_dir_record(volume, (DOS *)nfs, + hash, UNIX_NAME_SPACE); + if (DirNo != (ULONG) -1) + { + nfs->uid = inode->i_uid; + nfs->gid = inode->i_gid; + nfs->mode = inode->i_mode; + nfs->rdev = inode->i_rdev; + + retCode = WriteDirectoryRecord(volume, (DOS *)nfs, DirNo); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return; + } + } + } + + retCode = ReadDirectoryRecord(volume, dos, inode->i_ino); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) file read error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return; + } + + dos->FileSize = inode->i_size; +#if (HASH_FAT_CHAINS) + dos->FirstBlock = hash->FirstBlock; +#endif + + if (hash->Parent == DELETED_DIRECTORY) + dos->DeletedDateAndTime = NWFSSystemToNetwareTime(inode->i_ctime); + else + dos->CreateDateAndTime = NWFSSystemToNetwareTime(inode->i_ctime); + dos->LastUpdatedDateAndTime = NWFSSystemToNetwareTime(inode->i_mtime); + dos->LastArchivedDateAndTime = NWFSSystemToNetwareTime(inode->i_atime); + + retCode = WriteDirectoryRecord(volume, dos, inode->i_ino); + if (retCode) + { + NWFSPrint("nwfs: inode number (%d) directory write error [%d]\n", + (int)inode->i_ino, (int)retCode); + NWUnlockFile(hash); + return; + } + + NWUnlockFile(hash); + + return; +} + +void nwfs_delete_inode(struct inode *inode) +{ +#if (VERBOSE) + NWFSPrint("delete inode %X\n", (unsigned)(inode ? inode->i_ino : 0)); +#endif + + clear_inode(inode); + return; +} + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/ioctl.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/ioctl.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/ioctl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/ioctl.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,91 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : IOCTL.C +* DESCRIP : NWFS VFS IOCTL Module for Linux +* DATE : December 6, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +int nwfs_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ +// DOS DOS_S; +// register DOS *dos = &DOS_S; + ULONG Attributes; + +#if (VERBOSE) + NWFSPrint("nwfs-ioctl\n"); +#endif + + switch (cmd) + { + case NWFS_GET_ATTRIBUTES: + if (NWFSCopyToUserSpace((void *)arg, (void *)&Attributes, 4)) + return -EFAULT; + return 0; + + case NWFS_SET_ATTRIBUTES: + if (NWFSCopyFromUserSpace((void *)&Attributes, (void *)arg, 4)) + return -EFAULT; + return 0; + + case NWFS_GET_TRUSTEES: + case NWFS_GET_QUOTA: + case NWFS_SET_TRUSTEES: + case NWFS_SET_QUOTA: + return 0; + + default: + return -EINVAL; + } +} + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/lru.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/lru.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/lru.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/lru.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,2130 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : LRU.C +* DESCRIP : NWFS LRU Module +* DATE : November 19, 1998 +* +* This is how NetWare does asynch I/O with an LRU. Somewhat different +* than what's in Linux today. This is a much more compact version +* than what is in NetWare, and a little slower since it's not +* written in hand-optimized IA32 assembly language. +* +***************************************************************************/ + +#include "globals.h" + +ULONG lru_active = 0; +ULONG lru_state = 0; +ULONG lru_signal = 0; +BYTE *LRUBlockHash = 0; +ULONG LRUBlockHashLimit = 0; +LRU *ListHead = 0; +LRU *ListTail = 0; +LRU *LRUFreeHead = 0; +LRU *LRUFreeTail = 0; +LRU *LRUDirtyHead = 0; +LRU *LRUDirtyTail = 0; +ULONG LRUDirtyBuffers = 0; +ULONG LRUBlocks = 0; +ULONG PERCENT_FACTOR = LRU_FACTOR; + +#if (LINUX_SLEEP) +atomic_t lock_counter = { 0 }; +atomic_t in_section; +ULONG section_owner = 0; + +#if (LINUX_SPIN && DO_ASYNCH_IO) +spinlock_t LRU_spinlock = SPIN_LOCK_UNLOCKED; +long LRU_flags = 0; +#else +NWFSInitSemaphore(LRUSemaphore); +#endif +NWFSInitSemaphore(LRUSyncSemaphore); +#endif + +extern ULONG insert_io(ULONG disk, ASYNCH_IO *io); +extern void RunAsynchIOQueue(ULONG disk); + +// mirror round robin counter +ULONG mirror_counter = 0; +BYTE *get_taddress(ULONG addr); + +void NWLockLRU(ULONG whence) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN && DO_ASYNCH_IO) + spin_lock_irqsave(&LRU_spinlock, LRU_flags); +#else + if (WaitOnSemaphore(&LRUSemaphore) == -EINTR) + NWFSPrint("lock lru was interupted addr-0x%X\n", (unsigned)whence); +#endif +#endif + +} + +void NWUnlockLRU(ULONG whence) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN && DO_ASYNCH_IO) + spin_unlock_irqrestore(&LRU_spinlock, LRU_flags); +#else + SignalSemaphore(&LRUSemaphore); +#endif +#endif + +} + +ULONG NWLockBuffer(LRU *lru) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&lru->Semaphore) == -EINTR) + { + NWFSPrint("lock buffer was interupted\n"); + return -1; + } +#endif + return 0; +} + +void NWUnlockBuffer(LRU *lru) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&lru->Semaphore); +#endif +} + +void ReleaseWaiters(LRU *lru) +{ + while (lru->Waiters) + { +#if (LINUX_SLEEP) + SignalSemaphore(&lru->Semaphore); +#endif + lru->Waiters--; + } +} + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +ULONG GetLRUTime(void) +{ + ULONG year, month, day, hour, minute, second; + + GetUnixTime(NWFSGetSystemTime(), + &second, &minute, &hour, &day, &month, &year); + return (ULONG)(second + (minute * 60)); +} + +#endif + +LRU *RemoveListHead(LRU *lru) +{ + if (ListHead == lru) + { + ListHead = (void *) lru->listnext; + if (ListHead) + ListHead->listprior = NULL; + else + ListTail = NULL; + } + else + { + lru->listprior->listnext = lru->listnext; + if (lru != ListTail) + lru->listnext->listprior = lru->listprior; + else + ListTail = lru->listprior; + } + lru->listnext = lru->listprior = 0; + return lru; + +} + +void InsertListHead(LRU *lru) +{ + if (!ListHead) + { + ListHead = lru; + ListTail = lru; + lru->listnext = lru->listprior = 0; + } + else + { + ListTail->listnext = lru; + lru->listnext = 0; + lru->listprior = ListTail; + ListTail = lru; + } + return; + +} + +// this is a very SLOW brute force ordering routine. We only use +// it when we are doing synchronous I/O (debug mode). + +LRU *IndexDirtyLRU(LRU *i) +{ + register int j; + ULONG count = 0, ccode; + LRU *old, *p; + nwvp_asynch_map map[8]; + + for (j=0; j < 8; j++) + { + i->lba[j] = 0; + i->disk[j] = 0; + } + + // This function returns a mirror map of all mirror + // group members, whether IN_SYNC or not. For the + // write case, we always attempt ot update all the + // mirrored members asynchronously. For the read case, + // we only allow reads from IN_SYNC mirror members. + + ccode = nwvp_vpartition_map_asynch_write(i->nwvp_handle, + i->block, + &count, + &map[0]); + if (!ccode && count) + { + i->mirror_count = (count % 8); + for (j=0; j < (int)(count % 8); j++) + { + i->lba[j] = map[j].sector_offset; + i->disk[j] = map[j].disk_id; + } + } + + if (!LRUDirtyTail) + { + i->dnext = i->dprior = NULL; + LRUDirtyTail = i; + return i; + } + p = LRUDirtyHead; + old = NULL; + while (p) + { + if ((p->disk < i->disk) && (p->lba[0] < i->lba[0])) + { + old = p; + p = p->dnext; + } + else + { + if (p->dprior) + { + p->dprior->dnext = i; + i->dnext = p; + i->dprior = p->dprior; + p->dprior = i; + return LRUDirtyHead; + } + i->dnext = p; + i->dprior = NULL; + p->dprior = i; + return i; + } + } + old->dnext = i; + i->dnext = NULL; + i->dprior = old; + LRUDirtyTail = i; + return LRUDirtyHead; +} + + +LRU *RemoveDirty(LRU *lru) +{ +#if (!SINGLE_DIRTY_LIST) + if (LRUDirtyHead == lru) + { + LRUDirtyHead = (void *) lru->dnext; + if (LRUDirtyHead) + LRUDirtyHead->dprior = NULL; + else + LRUDirtyTail = NULL; + } + else + { + lru->dprior->dnext = lru->dnext; + if (lru != LRUDirtyTail) + lru->dnext->dprior = lru->dprior; + else + LRUDirtyTail = lru->dprior; + } +#endif + + lru->dnext = lru->dprior = (LRU *)-3; + lru->state &= ~L_DIRTY; + lru->state |= L_UPTODATE; + lru->owner &= ~QUEUE_DIRTY; + if (LRUDirtyBuffers) + LRUDirtyBuffers--; + + return lru; +} + +#if (DO_ASYNCH_IO & !LINUX_UTIL) + +// the asynch io manager orders requests. so we don't need to do +// this here. + +void InsertDirty(LRU *lru) +{ + if (lru->owner & QUEUE_DIRTY) + { + NWFSPrint("dirty element was already on list\n"); + return; + } + +#if (!SINGLE_DIRTY_LIST) + if (!LRUDirtyHead) + { + LRUDirtyHead = lru; + LRUDirtyTail = lru; + lru->dnext = lru->dprior = 0; + } + else + { + LRUDirtyTail->dnext = lru; + lru->dnext = 0; + lru->dprior = LRUDirtyTail; + LRUDirtyTail = lru; + } +#endif + + lru->owner |= QUEUE_DIRTY; + lru->state |= L_DIRTY; + LRUDirtyBuffers++; + return; + +} + +#else + +void InsertDirty(LRU *lru) +{ + if (lru->owner & QUEUE_DIRTY) + { + NWFSPrint("dirty element was already on list\n"); + return; + } + +#if (!SINGLE_DIRTY_LIST) + LRUDirtyHead = IndexDirtyLRU(lru); +#endif + + lru->owner |= QUEUE_DIRTY; + lru->state |= L_DIRTY; + LRUDirtyBuffers++; + return; +} + +#endif + +LRU *RemoveLRU(LRU_HANDLE *lru_handle, LRU *lru) +{ + if (lru_handle->LRUListHead == lru) + { + lru_handle->LRUListHead = (void *) lru->next; + if (lru_handle->LRUListHead) + lru_handle->LRUListHead->prior = NULL; + else + lru_handle->LRUListTail = NULL; + } + else + { + lru->prior->next = lru->next; + if (lru != lru_handle->LRUListTail) + lru->next->prior = lru->prior; + else + lru_handle->LRUListTail = lru->prior; + } + + lru->next = lru->prior = 0; + lru->owner &= ~QUEUE_LRU; + if (lru_handle->LocalLRUBlocks) + lru_handle->LocalLRUBlocks--; + return lru; + +} + +void InsertLRU(LRU_HANDLE *lru_handle, LRU *lru) +{ + if (lru->owner & QUEUE_LRU) + { + NWFSPrint("LRU element was already on list\n"); + return; + } + + if (!lru_handle->LRUListHead) + { + lru_handle->LRUListHead = lru; + lru_handle->LRUListTail = lru; + lru->next = lru->prior = 0; + } + else + { + lru_handle->LRUListTail->next = lru; + lru->next = 0; + lru->prior = lru_handle->LRUListTail; + lru_handle->LRUListTail = lru; + } + lru->owner |= QUEUE_LRU; + lru_handle->LocalLRUBlocks++; + return; + +} + +void InsertLRUTop(LRU_HANDLE *lru_handle, LRU *lru) +{ + if (lru->owner & QUEUE_LRU) + { + NWFSPrint("LRU element was already on list\n"); + return; + } + + if (!lru_handle->LRUListHead) + { + lru_handle->LRUListHead = lru; + lru_handle->LRUListTail = lru; + lru->next = lru->prior = 0; + } + else + { + lru->next = lru_handle->LRUListHead; + lru->prior = 0; + lru_handle->LRUListHead->prior = lru; + lru_handle->LRUListHead = lru; + } + lru->owner |= QUEUE_LRU; + lru_handle->LocalLRUBlocks++; + return; + +} + +LRU *GetFreeLRU(void) +{ + register LRU *lru; + + if (LRUFreeHead) + { + lru = LRUFreeHead; + LRUFreeHead = (void *) lru->next; + if (LRUFreeHead) + LRUFreeHead->prior = NULL; + else + LRUFreeTail = NULL; + + lru->next = lru->prior = 0; + lru->owner &= ~QUEUE_FREE; + return lru; + } + return 0; + +} + +void PutFreeLRU(LRU *lru) +{ + if (lru->owner & QUEUE_FREE) + { + NWFSPrint("free element was already on list\n"); + return; + } + + if (!LRUFreeHead) + { + LRUFreeHead = lru; + LRUFreeTail = lru; + lru->next = lru->prior = 0; + } + else + { + LRUFreeTail->next = lru; + lru->next = 0; + lru->prior = LRUFreeTail; + LRUFreeTail = lru; + } + lru->owner |= QUEUE_FREE; + return; +} + +LRU *SearchHash(VOLUME *volume, ULONG block) +{ + register LRU *lru; + register ULONG hash; + register DATA_LRU_HASH_LIST *HashTable; + + hash = (block & (LRUBlockHashLimit - 1)); + HashTable = (DATA_LRU_HASH_LIST *) LRUBlockHash; + if (HashTable) + { + lru = HashTable[hash].head; + while (lru) + { + if ((lru->block == block) && (lru->volnum == volume->VolumeNumber)) + return lru; + lru = lru->hashNext; + } + } + return 0; +} + +ULONG AddToHash(LRU *lru) +{ + register ULONG hash; + register DATA_LRU_HASH_LIST *HashTable; + + hash = (lru->block & (LRUBlockHashLimit - 1)); + HashTable = (DATA_LRU_HASH_LIST *) LRUBlockHash; + if (HashTable) + { + if (lru->owner & QUEUE_HASH) + { + NWFSPrint("hash element was already on list\n"); + return -1; + } + + if (!HashTable[hash].head) + { + HashTable[hash].head = lru; + HashTable[hash].tail = lru; + lru->hashNext = lru->hashPrior = 0; + } + else + { + HashTable[hash].tail->hashNext = lru; + lru->hashNext = 0; + lru->hashPrior = HashTable[hash].tail; + HashTable[hash].tail = lru; + } + lru->owner |= QUEUE_HASH; + return 0; + } + return -1; +} + +ULONG RemoveHash(LRU *lru) +{ + register ULONG hash; + register DATA_LRU_HASH_LIST *HashTable; + + hash = (lru->block & (LRUBlockHashLimit - 1)); + HashTable = (DATA_LRU_HASH_LIST *) LRUBlockHash; + if (HashTable) + { + if (HashTable[hash].head == lru) + { + HashTable[hash].head = lru->hashNext; + if (HashTable[hash].head) + HashTable[hash].head->hashPrior = NULL; + else + HashTable[hash].tail = NULL; + } + else + { + lru->hashPrior->hashNext = lru->hashNext; + if (lru != HashTable[hash].tail) + lru->hashNext->hashPrior = lru->hashPrior; + else + HashTable[hash].tail = lru->hashPrior; + } + + lru->hashNext = lru->hashPrior = 0; + lru->owner &= ~QUEUE_HASH; + return 0; + } + return -1; +} + +void FreeLRUElement(LRU *lru) +{ + if (lru) + { + if (lru->buffer) + { +#if (LINUX_20 | LINUX_22) + kfree(lru->buffer); + + LRU_BUFFER_TRACKING.count -= IO_BLOCK_SIZE; + LRU_BUFFER_TRACKING.units--; + MemoryInUse -= IO_BLOCK_SIZE; + +#elif (LINUX_24) + __free_page(lru->page); + + LRU_BUFFER_TRACKING.count -= IO_BLOCK_SIZE; + LRU_BUFFER_TRACKING.units--; + MemoryInUse -= IO_BLOCK_SIZE; + +#else + NWFSFree(lru->buffer); +#endif + } + NWFSFree(lru); + if (LRUBlocks) + LRUBlocks--; + } + return; +} + +LRU *AllocateLRUElement(VOLUME *volume, ULONG block, ULONG *ccode) +{ + register LRU *lru; + + if (ccode) + *ccode = 0; + + lru = NWFSAlloc(sizeof(LRU), LRU_TAG); + if (!lru) + return 0; + + NWFSSet(lru, 0, sizeof(LRU)); + + lru->state = L_FREE; + lru->block = -1; + lru->volnum = (ULONG) -1; + +#if (LINUX_SLEEP) + AllocateSemaphore(&lru->Semaphore, 0); // this is a waiters queue +#endif + + // if we are a linux driver, then the buffer must be page aligned + // or the lower layers may get DMA timeouts (drivers in Linux are + // optimized for 512-byte aligned memory). + +#if (LINUX_20 | LINUX_22) + + lru->buffer = kmalloc(IO_BLOCK_SIZE, GFP_ATOMIC); + if (!lru->buffer) + { + NWFSFree(lru); + return 0; + } + + LRU_BUFFER_TRACKING.count += IO_BLOCK_SIZE; + LRU_BUFFER_TRACKING.units++; + MemoryInUse += IO_BLOCK_SIZE; + +#elif (LINUX_24) + lru->page = alloc_page(GFP_ATOMIC); + if (!lru->page) + { + NWFSFree(lru); + return 0; + } + lru->buffer = (BYTE *)page_address(lru->page); + + LRU_BUFFER_TRACKING.count += IO_BLOCK_SIZE; + LRU_BUFFER_TRACKING.units++; + MemoryInUse += IO_BLOCK_SIZE; + +#else + lru->buffer = NWFSIOAlloc(IO_BLOCK_SIZE, LRU_BUFFER_TAG); + if (!lru->buffer) + { + NWFSFree(lru); + return 0; + } +#endif + + NWFSSet(lru->buffer, 0, IO_BLOCK_SIZE); + LRUBlocks++; + InsertListHead(lru); + return lru; +} + +ULONG InitializeLRU(LRU_HANDLE *lru_handle, BYTE *name, ULONG mode, + ULONG max, ULONG min, ULONG age) +{ + NWFSSet(lru_handle, 0, sizeof(LRU_HANDLE)); + lru_handle->LRUName = name; + lru_handle->LRUMode = mode; + + if (!LRUBlockHash) + { + LRUBlockHash = NWFSCacheAlloc(BLOCK_LRU_HASH_SIZE, LRU_HASH_TAG); + if (!LRUBlockHash) + return -1; + + LRUBlockHashLimit = NUMBER_OF_LRU_HASH_ENTRIES; + NWFSSet(LRUBlockHash, 0, BLOCK_LRU_HASH_SIZE); + } + + lru_handle->MinimumLRUBlocks = min; + lru_handle->MaximumLRUBlocks = max; + lru_handle->LocalLRUBlocks = 0; + lru_handle->AGING_INTERVAL = age; + + return 0; +} + +ULONG FreeLRU(void) +{ + register ULONG ccode; + register LRU *lru, *list; + + NWLockLRU((ULONG)FreeLRU); + lru_active = TRUE; + list = ListHead; + ListHead = ListTail = 0; + while (list) + { + lru = list; + list = list->listnext; + +#if (LINUX_20 || LINUX_22 || LINUX_24) + if (lru->state & L_FLUSHING) + { + NWUnlockLRU((ULONG)FreeLRU); + + while (lru->state & L_FLUSHING) + schedule(); + + NWLockLRU((ULONG)FreeLRU); + } +#endif + + if ((lru->state & L_DIRTY) && + (lru->nwvp_handle) && + (lru->state & L_DATAVALID)) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + NWUnlockLRU((ULONG)FreeLRU); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, lru->block, 1, lru->buffer); + + NWLockLRU((ULONG)FreeLRU); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + +#if (VERBOSE) + if (ccode) + NWFSPrint("nwfs: I/O Error (close) block-%d volume-%d\n", + (int)lru->block, (int)lru->volnum); +#endif + if (!(lru->state & L_MODIFIED)) + { + NWFSPrint("lru was modified -- free lru\n"); + RemoveDirty(lru); + } + } + FreeLRUElement(lru); + } + + list = LRUFreeHead; + LRUFreeHead = LRUFreeTail = 0; + while (list) + { + lru = list; + list = list->next; + FreeLRUElement(lru); + } + lru_active = FALSE; + NWUnlockLRU((ULONG)FreeLRU); + + return 0; +} + +ULONG retry_write_aio(ASYNCH_IO *io) +{ + register ULONG ccode; + register LRU *lru = (LRU *) io->call_back_parameter; + + // if we had a write failure for any of the mirrored asynch + // writes, then we retry the write operation synchronously with + // retry logic to attempt to recover lost sectors (hotfixing). + // nwvp_() function calls perform hotfixing and mirror failover + // operations. + + NWFSPrint("write retry\n"); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, lru->block, 1, lru->buffer); + + NWLockLRU((ULONG)retry_write_aio); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + // if no I/O error and the buffer was not dirtied while I/O was + // pending, then remove from the dirty list. + if (!ccode) + { + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + lru->io_signature = 0; + NWUnlockLRU((ULONG)retry_write_aio); + + return 0; +} + +ULONG release_write_aio(ASYNCH_IO *io) +{ + register LRU *lru = (LRU *) io->call_back_parameter; + + NWLockLRU((ULONG)release_write_aio); + if (io->ccode) + lru->aio_ccode = io->ccode; + + // count the number of aoi's completed. signal when the + // last mirror member has returned completed. + + lru->mirrors_completed++; + if (lru->mirror_count == lru->mirrors_completed) + { + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + if (!lru->aio_ccode) + { + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + else + { + // post this write for retry and failover operations + io->call_back_routine = retry_write_aio; + io->flags = ASIO_SLEEP_CALLBACK; + NWUnlockLRU((ULONG)release_write_aio); + return 1; + } + lru->io_signature = 0; + } + NWUnlockLRU((ULONG)release_write_aio); + return 0; +} + +ULONG FlushLRU(void) +{ +#if (DO_ASYNCH_IO & !LINUX_UTIL) + + register ULONG i; + register LRU *lru, *list; + BYTE disks[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + register int j; + ULONG count = 0, ccode; + nwvp_asynch_map map[8]; + + NWLockLRU((ULONG)FlushLRU); + lru_active = TRUE; + +#if (SINGLE_DIRTY_LIST) + list = ListHead; + while (list) + { + lru = list; + list = list->listnext; +#else + list = LRUDirtyHead; + while (list) + { + lru = list; + list = list->dnext; + + if (lru->dnext == (LRU *)-3) + NWFSPrint("FlushLRU -- lru->dnext was already off the list\n"); +#endif + + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle) && + (!lru->lock_count) && + (!(lru->state & L_FLUSHING))) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + // this flag is cleared when we dirty a buffer + + if (lru->io_signature == ASIO_SUBMIT_IO) + { + NWFSPrint("io already scheduled (f)\n"); + continue; + } + + lru->io_signature = ASIO_SUBMIT_IO; + for (j=0; j < 8; j++) + { + lru->lba[j] = 0; + lru->disk[j] = 0; + } + + // This function returns a mirror map of all mirror + // group members, whether IN_SYNC or not. For the + // write case, we always attempt ot update all the + // mirrored members asynchronously. For the read case, + // we only allow reads from IN_SYNC mirror members. + + ccode = nwvp_vpartition_map_asynch_write(lru->nwvp_handle, + lru->block, + &count, + &map[0]); + if (!ccode && count) + { + lru->mirror_count = (count % 8); + for (j=0; j < (int)(count % 8); j++) + { + lru->lba[j] = map[j].sector_offset; + lru->disk[j] = map[j].disk_id; + } + } + else + { + NWFSPrint("map_asynch_write failed volume-%d block-%d\n", + (int)lru->volnum, (int)lru->block); + continue; + } + + // The block bad bits are always identical across mirrors for + // every member of a mirror group. if during Hotfixing, data + // could not be completely recovered for a read I/O error + // from other mirrors or from cache, we artifically hotfix + // all mirrored partitions and record any unrecoverable sectors + // in a bad bit block in the device hotfix data area. + // The first time a read is attempted from a sector region + // that was unrecoverable from a previous read hotfix, then + // we know that some portion of the data is now missing and + // we return a hard I/O error to the user for this block region. + // Writing to a read hotfixed region clears the bad bit + // table for a particular hotfixed block. If a block has + // bad bits, we must transact the mirrored write for this + // single case synchronously in order to clear the bad bit + // tables for all the mirrored partitions and update the + // hotfix tables. + + // if there are bad bits for this block, we must update the hotfix + // tables on any active mirrors. + + // if the bad bits have changed, write the new bits + if (lru->bad_bits != map[0].bad_bits) + { + NWUnlockLRU((ULONG)FlushLRU); + + ccode = nwvp_vpartition_bad_bit_update(lru->nwvp_handle, + lru->block, + lru->bad_bits); + if (ccode) + NWFSPrint("nwfs: could not update bad bits vol-%d block-%d\n", + (int)lru->volnum, (int)lru->block); + + NWLockLRU((ULONG)FlushLRU); + } + + lru->aio_ccode = 0; + lru->mirrors_completed = 0; + for (i=0; i < lru->mirror_count; i++) + { + NWFSSet(&lru->io[i], 0, sizeof(ASYNCH_IO)); + lru->io[i].command = ASYNCH_WRITE; + lru->io[i].disk = lru->disk[i]; + lru->io[i].flags = ASIO_INTR_CALLBACK; + lru->io[i].sector_offset = lru->lba[i]; + lru->io[i].sector_count = 8; + lru->io[i].buffer = lru->buffer; + lru->io[i].call_back_routine = release_write_aio; + lru->io[i].call_back_parameter = (ULONG)lru; + + // the file system is not allowed to ever write sector + // zero at this layer. + if (lru->io[i].sector_offset == 0) + { + NWFSPrint("nwfs: mirroring map is corrupted block-%d vol-%d. Aborting I/O\n", + (int)lru->block, (int)lru->volnum); + continue; + } + insert_io(lru->disk[i], &lru->io[i]); + disks[(lru->disk[i] % 8)] = TRUE; + } + } + } + lru_active = FALSE; + NWUnlockLRU((ULONG)FlushLRU); + + // signal disk processes for any queues we gave work to. + for (i=0; i < 8; i++) + { + if (disks[i]) + RunAsynchIOQueue(i); + } + return 0; + +#else + + register ULONG ccode; + register LRU *lru, *list; + + NWLockLRU((ULONG)FlushLRU); + lru_active = TRUE; + +#if (SINGLE_DIRTY_LIST) + list = ListHead; + while (list) + { + lru = list; + list = list->listnext; +#else + list = LRUDirtyHead; + while (list) + { + lru = list; + list = list->dnext; + + if (lru->dnext == (LRU *)-3) + NWFSPrint("FlushLRU -- lru->dnext was already off the list\n"); +#endif + + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle) && + (!lru->lock_count) && + (!(lru->state & L_FLUSHING))) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + NWUnlockLRU((ULONG)FlushLRU); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, lru->block, 1, lru->buffer); + + NWLockLRU((ULONG)FlushLRU); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + if (!ccode) + { + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + } + } + lru_active = FALSE; + NWUnlockLRU((ULONG)FlushLRU); + return 0; + +#endif +} + +ULONG FlushEligibleLRU(void) +{ +#if (DO_ASYNCH_IO & !LINUX_UTIL) + + register ULONG i; + register LRU *lru, *list; + BYTE disks[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + register int j; + ULONG count = 0, ccode; + nwvp_asynch_map map[8]; + + NWLockLRU((ULONG)FlushEligibleLRU); + lru_active = TRUE; + +#if (SINGLE_DIRTY_LIST) + list = ListHead; + while (list) + { + lru = list; + list = list->listnext; +#else + list = LRUDirtyHead; + while (list) + { + lru = list; + list = list->dnext; + + if (lru->dnext == (LRU *)-3) + NWFSPrint("FlushEligLRU -- lru->dnext was already off the list\n"); +#endif + +#if (LINUX_20 | LINUX_22 | LINUX_24) + if ((lru_state != NWFS_FLUSH_ALL) && + (lru->timestamp + lru->AGING_INTERVAL) > GetLRUTime()) + continue; +#endif + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle) && + (!lru->lock_count) && + (!(lru->state & L_FLUSHING))) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + + NWUnlockLRU((ULONG)FlushEligibleLRU); + + if (lru->io_signature == ASIO_SUBMIT_IO) + { + NWFSPrint("io already scheduled (fe)\n"); + NWLockLRU((ULONG)FlushEligibleLRU); + continue; + } + + for (j=0; j < 8; j++) + { + lru->lba[j] = 0; + lru->disk[j] = 0; + } + + // This function returns a mirror map of all mirror + // group members, whether IN_SYNC or not. For the + // write case, we always attempt ot update all the + // mirrored members asynchronously. For the read case, + // we only allow reads from IN_SYNC mirror members. + + ccode = nwvp_vpartition_map_asynch_write(lru->nwvp_handle, + lru->block, + &count, + &map[0]); + + if (!ccode && count) + { + lru->mirror_count = (count % 8); + for (j=0; j < (int)(count % 8); j++) + { + lru->lba[j] = map[j].sector_offset; + lru->disk[j] = map[j].disk_id; + } + } + else + { + NWFSPrint("map_asynch_write failed volume-%d block-%d\n", + (int)lru->volnum, (int)lru->block); + NWLockLRU((ULONG)FlushEligibleLRU); + continue; + } + + + // The block bad bits are always identical across mirrors for + // every member of a mirror group. if during Hotfixing, data + // could not be completely recovered for a read I/O error + // from other mirrors or from cache, we artifically hotfix + // all mirrored partitions and record any unrecoverable sectors + // in a bad bit block in the device hotfix data area. + // The first time a read is attempted from a sector region + // that was unrecoverable from a previous read hotfix, then + // we know that some portion of the data is now missing and + // we return a hard I/O error to the user for this block region. + // Writing to a read hotfixed region clears the bad bit + // table for a particular hotfixed block. If a block has + // bad bits, we must transact the mirrored write for this + // single case synchronously in order to clear the bad bit + // tables for all the mirrored partitions and update the + // hotfix tables. + + // if there are bad bits for this block, we must update the hotfix + // tables on any active mirrors. + + // if the bad bits have changed, write the new bits + if (lru->bad_bits != map[0].bad_bits) + { +// NWUnlockLRU((ULONG)FlushLRU); + + ccode = nwvp_vpartition_bad_bit_update(lru->nwvp_handle, + lru->block, + lru->bad_bits); + if (ccode) + NWFSPrint("nwfs: could not update bad bits vol-%d block-%d\n", + (int)lru->volnum, (int)lru->block); + +// NWLockLRU((ULONG)FlushLRU); + } + + lru->aio_ccode = 0; + lru->mirrors_completed = 0; + for (i=0; i < lru->mirror_count; i++) + { + NWFSSet(&lru->io[i], 0, sizeof(ASYNCH_IO)); + lru->io[i].command = ASYNCH_WRITE; + lru->io[i].disk = lru->disk[i]; + lru->io[i].flags = ASIO_INTR_CALLBACK; + lru->io[i].sector_offset = lru->lba[i]; + lru->io[i].sector_count = 8; + lru->io[i].buffer = lru->buffer; + lru->io[i].call_back_routine = release_write_aio; + lru->io[i].call_back_parameter = (ULONG)lru; + + // the file system is not allowed to ever write sector + // zero at this layer. + if (lru->io[i].sector_offset == 0) + { + NWFSPrint("nwfs: mirroring map is corrupted block-%d vol-%d. Aborting I/O\n", + (int)lru->block, (int)lru->volnum); + NWLockLRU((ULONG)FlushEligibleLRU); + continue; + } + + insert_io(lru->disk[i], &lru->io[i]); + disks[(lru->disk[i] % 8)] = TRUE; + + NWLockLRU((ULONG)FlushEligibleLRU); + } + } + } + lru_state = 0; + lru_active = FALSE; + NWUnlockLRU((ULONG)FlushEligibleLRU); + + // signal disk processes for any queues we gave work to. + for (i=0; i < 8; i++) + { + if (disks[i]) + RunAsynchIOQueue(i); + } + return 0; + +#else + + register ULONG ccode; + register LRU *lru, *list; + + NWLockLRU((ULONG)FlushEligibleLRU); + lru_active = TRUE; + +#if (SINGLE_DIRTY_LIST) + list = ListHead; + while (list) + { + lru = list; + list = list->listnext; +#else + list = LRUDirtyHead; + while (list) + { + lru = list; + list = list->dnext; + + if (lru->dnext == (LRU *)-3) + NWFSPrint("FlushEligLRU -- lru->dnext was already off the list\n"); +#endif + +#if (LINUX_20 | LINUX_22 | LINUX_24) + if ((lru_state != NWFS_FLUSH_ALL) && + (lru->timestamp + lru_handle->AGING_INTERVAL) > GetLRUTime()) + continue; +#endif + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle) && + (!lru->lock_count) && + (!(lru->state & L_FLUSHING))) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + NWUnlockLRU((ULONG)FlushEligibleLRU); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, lru->block, 1, lru->buffer); + + if (ccode) + NWFSPrint("write error in flush LRU\n"); + + NWLockLRU((ULONG)FlushEligibleLRU); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + if (!ccode) + { + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + } + } + lru_state = 0; + lru_active = FALSE; + NWUnlockLRU((ULONG)FlushEligibleLRU); + return 0; + +#endif +} + +ULONG SyncVolumeLRU(VOLUME *volume) +{ + register ULONG ccode; + register LRU *lru, *list; + + NWLockLRU((ULONG)FlushVolumeLRU); + lru_active = TRUE; + list = ListHead; + while (list) + { + lru = list; + list = list->listnext; + + if (lru->volnum == volume->VolumeNumber) + { +#if (LINUX_20 || LINUX_22 || LINUX_24) + if (lru->state & L_FLUSHING) + { + NWUnlockLRU((ULONG)SyncVolumeLRU); + + while (lru->state & L_FLUSHING) + schedule(); + + NWLockLRU((ULONG)FlushVolumeLRU); + } +#endif + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle)) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + NWUnlockLRU((ULONG)SyncVolumeLRU); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, lru->block, 1, lru->buffer); + + if (ccode) + NWFSPrint("write error in sync volume LRU\n"); + + NWLockLRU((ULONG)FlushVolumeLRU); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + } + } + lru_active = FALSE; + NWUnlockLRU((ULONG)SyncVolumeLRU); + return 0; +} + +ULONG FlushVolumeLRU(VOLUME *volume) +{ + register ULONG ccode; + register LRU *lru, *list; + + NWLockLRU((ULONG)FlushVolumeLRU); + lru_active = TRUE; + list = ListHead; + while (list) + { + lru = list; + list = list->listnext; + + if (lru->volnum == volume->VolumeNumber) + { +#if (LINUX_20 || LINUX_22 || LINUX_24) + if (lru->state & L_FLUSHING) + { + NWUnlockLRU((ULONG)FlushVolumeLRU); + + while (lru->state & L_FLUSHING) + schedule(); + + NWLockLRU((ULONG)FlushVolumeLRU); + } +#endif + + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle)) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + NWUnlockLRU((ULONG)FlushVolumeLRU); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, lru->block, 1, lru->buffer); + + if (ccode) + NWFSPrint("write error in flush volume LRU\n"); + + NWLockLRU((ULONG)FlushVolumeLRU); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + RemoveLRU(lru->lru_handle, lru); + RemoveHash(lru); + + RemoveListHead(lru); + lru->state = L_FREE; + lru->volnum = (ULONG) -1; + PutFreeLRU(lru); + } + } + lru_active = FALSE; + NWUnlockLRU((ULONG)FlushVolumeLRU); + return 0; +} + +// +// blocking read functions +// + +#if (DO_ASYNCH_IO) +ULONG release_read_aio(ASYNCH_IO *io) +{ +#if (LINUX_SLEEP) + SignalSemaphore((struct semaphore *)io->call_back_parameter); +#endif + return 0; +} +#endif + +LRU *GetAvailableLRU(LRU_HANDLE *lru_handle, VOLUME *volume, ULONG block) +{ + register LRU *lru = 0; + + if ((lru_handle->LocalLRUBlocks < lru_handle->MaximumLRUBlocks) && + (LRUBlocks < MAX_LRU_BLOCKS)) + { + ULONG ccode = 0; + + if (LRUFreeHead) + { + lru = GetFreeLRU(); + if (lru) + { + InsertListHead(lru); + lru->lru_handle = lru_handle; + lru->AGING_INTERVAL = lru_handle->AGING_INTERVAL; + return lru; + } + } + + lru = AllocateLRUElement(volume, block, &ccode); + if (ccode) + return 0; + + if (lru) + { + lru->lru_handle = lru_handle; + lru->AGING_INTERVAL = lru_handle->AGING_INTERVAL; + return lru; + } + } + + if (lru_handle->LRUListHead) + { + lru = lru_handle->LRUListTail; + while ((lru) && + ((lru->state & (L_DIRTY | L_LOADING | L_FLUSHING)) || + (lru->lock_count))) + lru = lru->prior; + + if (lru) + { + RemoveLRU(lru->lru_handle, lru); + RemoveHash(lru); + } + } + return lru; +} + +LRU *FillBlock(LRU_HANDLE *lru_handle, VOLUME *volume, ULONG block, + ULONG fill, ULONG ccount, + ULONG *mirror) +{ + register ULONG retCode; +#if (DO_ASYNCH_IO & !LINUX_UTIL) + register ULONG mirror_index; +#endif + register LRU *lru = 0; + + lru = GetAvailableLRU(lru_handle, volume, block); + if (!lru) + return 0; + + if (lru->io_signature == ASIO_SUBMIT_IO) + { + NWFSPrint("io already scheduled (f)\n"); + RemoveListHead(lru); + lru->state = L_FREE; + lru->volnum = (ULONG) -1; + PutFreeLRU(lru); + return 0; + } + + lru->io_signature = ASIO_SUBMIT_IO; + lru->aio_ccode = 0; + + lru->state = L_LOADING; + lru->block = block; + lru->nwvp_handle = volume->nwvp_handle; + lru->volnum = volume->VolumeNumber; + + AddToHash(lru); + lru->lru_handle = lru_handle; + lru->AGING_INTERVAL = lru_handle->AGING_INTERVAL; + InsertLRUTop(lru->lru_handle, lru); + + if (fill) + { +#if (DO_ASYNCH_IO & !LINUX_UTIL) +#if (LINUX_SLEEP) + NWFSInitSemaphore(semaphore); +#endif + register int j; + ULONG count = 0, map_ccode; + nwvp_asynch_map map[8]; + + // remap the lru mirroring information since during recovery, it + // may have changed. + + lru->bad_bits = 0; + for (j=0; j < 8; j++) + { + lru->lba[j] = 0; + lru->disk[j] = 0; + } + + map_ccode = nwvp_vpartition_map_asynch_read(lru->nwvp_handle, + lru->block, + &count, &map[0]); + if (!map_ccode && count) + { + lru->mirror_count = (count % 8); + for (j=0; j < (int)(count % 8); j++) + { + lru->lba[j] = map[j].sector_offset; + lru->disk[j] = map[j].disk_id; + } + } + + NWFSSet(&lru->io[0], 0, sizeof(ASYNCH_IO)); + lru->io[0].command = ASYNCH_READ; + + // Pick a random mirror member to read from that is IN_SYNC. + // nwvp_vpartition_map_asynch_read() will only return a list + // of IN_SYNC mirrors to read from, as opposed to + // nwvp_vpartition_map_asynch_write() which will return all + // present mirror group members with an active device. + + // We typically don't want to interleave 4K reads for a + // complete cluster across mirrors because a cluster is + // almost always a contiguous run of sectors. We allow + // the LRU reader to pass a mirror context pointer + // where we can record the last mirror index and use + // it for subsequent calls to fill any blocks that may + // all reside within the same cluster. + + if (mirror) + { + if (*mirror < count) + mirror_index = *mirror; + else + { + mirror_index = mirror_counter % lru->mirror_count; + *mirror = mirror_index; + } + } + else + mirror_index = mirror_counter % lru->mirror_count; + mirror_counter++; + + lru->io[0].disk = lru->disk[mirror_index]; + lru->io[0].flags = ASIO_INTR_CALLBACK; + lru->io[0].sector_offset = lru->lba[mirror_index]; + lru->io[0].sector_count = 8; + lru->io[0].buffer = lru->buffer; + lru->io[0].call_back_routine = release_read_aio; + lru->io[0].call_back_parameter = (ULONG)&semaphore; + + lru->bad_bits = map[mirror_index].bad_bits; + + insert_io(lru->io[0].disk, &lru->io[0]); + + NWUnlockLRU((ULONG)FillBlock); + + RunAsynchIOQueue(lru->io[0].disk); + +#if (LINUX_SLEEP) + WaitOnSemaphore(&semaphore); +#endif + // if we get an I/O error on the async read, retry the operation + // synchronously to perform hotfixing or mirrored failover. + + retCode = lru->io[0].ccode; + if (retCode) + retCode = nwvp_vpartition_block_read(lru->nwvp_handle, lru->block, 1, lru->buffer); + + NWLockLRU((ULONG)FillBlock); +#else + NWUnlockLRU((ULONG)FillBlock); + + retCode = nwvp_vpartition_block_read(lru->nwvp_handle, lru->block, 1, lru->buffer); + + NWLockLRU((ULONG)FillBlock); +#endif + if (retCode) + { + RemoveLRU(lru->lru_handle, lru); + RemoveHash(lru); + + RemoveListHead(lru); + lru->state = L_FREE; + lru->volnum = (ULONG) -1; + PutFreeLRU(lru); + + lru->io_signature = 0; + + ReleaseWaiters(lru); + return 0; + } + } + lru->state &= ~L_LOADING; + lru->state |= (L_DATAVALID | L_UPTODATE); + + lru->io_signature = 0; + + ReleaseWaiters(lru); + return lru; + +} + +// +// Asynch Read Functions +// + +ULONG retry_asynch_read_ahead(ASYNCH_IO *io) +{ + register ULONG ccode; + register LRU *lru = (LRU *) io->call_back_parameter; + + // if we get an I/O error on the async read, retry the operation + // synchronously to perform hotfixing or mirrored failover. + + ccode = nwvp_vpartition_block_read(lru->nwvp_handle, lru->block, + 1, lru->buffer); + + NWLockLRU((ULONG)retry_asynch_read_ahead); + if (ccode) + { + RemoveLRU(lru->lru_handle, lru); + RemoveHash(lru); + + RemoveListHead(lru); + lru->state = L_FREE; + lru->volnum = (ULONG) -1; + PutFreeLRU(lru); + + ReleaseWaiters(lru); + lru->io_signature = 0; + + NWUnlockLRU((ULONG)retry_asynch_read_ahead); + return 0; + } + lru->state &= ~L_LOADING; + lru->state |= (L_DATAVALID | L_UPTODATE); + ReleaseWaiters(lru); + lru->io_signature = 0; + + NWUnlockLRU((ULONG)retry_asynch_read_ahead); + return 0; + +} + +ULONG release_asynch_read_ahead(ASYNCH_IO *io) +{ + register ULONG ccode; + register LRU *lru = (LRU *) io->call_back_parameter; + + NWLockLRU((ULONG)release_asynch_read_ahead); + ccode = io->ccode; + if (ccode) + { + io->call_back_routine = retry_asynch_read_ahead; + io->flags = ASIO_SLEEP_CALLBACK; + NWUnlockLRU((ULONG)release_asynch_read_ahead); + return 1; + } + lru->state &= ~L_LOADING; + lru->state |= (L_DATAVALID | L_UPTODATE); + ReleaseWaiters(lru); + lru->io_signature = 0; + + NWUnlockLRU((ULONG)release_asynch_read_ahead); + return 0; + +} + +LRU *FillBlockAsynch(LRU_HANDLE *lru_handle, VOLUME *volume, ULONG block, + ULONG ccount, BYTE *disks, + ULONG *mirror) +{ + register ULONG mirror_index; + register LRU *lru = 0; + register int j; + ULONG count = 0, map_ccode; + nwvp_asynch_map map[8]; + + lru = GetAvailableLRU(lru_handle, volume, block); + if (!lru) + return 0; + + if (lru->io_signature == ASIO_SUBMIT_IO) + { + NWFSPrint("io already scheduled (f)\n"); + RemoveListHead(lru); + lru->state = L_FREE; + lru->volnum = (ULONG) -1; + PutFreeLRU(lru); + return 0; + } + + lru->io_signature = ASIO_SUBMIT_IO; + lru->aio_ccode = 0; + + lru->state = L_LOADING; + lru->block = block; + lru->nwvp_handle = volume->nwvp_handle; + lru->volnum = volume->VolumeNumber; + + AddToHash(lru); + lru->lru_handle = lru_handle; + lru->AGING_INTERVAL = lru_handle->AGING_INTERVAL; + InsertLRUTop(lru->lru_handle, lru); + + lru->bad_bits = 0; + for (j=0; j < 8; j++) + { + lru->lba[j] = 0; + lru->disk[j] = 0; + } + + map_ccode = nwvp_vpartition_map_asynch_read(lru->nwvp_handle, + lru->block, + &count, &map[0]); + if (!map_ccode && count) + { + lru->mirror_count = (count % 8); + for (j=0; j < (int)(count % 8); j++) + { + lru->lba[j] = map[j].sector_offset; + lru->disk[j] = map[j].disk_id; + } + } + + NWFSSet(&lru->io[0], 0, sizeof(ASYNCH_IO)); + lru->io[0].command = ASYNCH_READ; + + // We typically don't want to interleave 4K reads for a + // complete cluster across mirrors because a cluster is + // almost always a contiguous run of sectors. We allow + // the LRU reader to pass a mirror context pointer + // where we can record the last mirror index and use + // it for subsequent calls to fill any blocks that may + // all reside within the same cluster. + + if (mirror) + { + if (*mirror < count) + mirror_index = *mirror; + else + { + mirror_index = mirror_counter % lru->mirror_count; + *mirror = mirror_index; + } + } + else + mirror_index = mirror_counter % lru->mirror_count; + mirror_counter++; + + lru->io[0].disk = lru->disk[mirror_index]; + lru->io[0].flags = ASIO_INTR_CALLBACK; + lru->io[0].sector_offset = lru->lba[mirror_index]; + lru->io[0].sector_count = 8; + lru->io[0].buffer = lru->buffer; + lru->io[0].call_back_routine = release_asynch_read_ahead; + lru->io[0].call_back_parameter = (ULONG)lru; + + lru->bad_bits = map[mirror_index].bad_bits; + + insert_io(lru->io[0].disk, &lru->io[0]); + mirror_counter++; + + disks[(lru->io[0].disk % 8)] = TRUE; + + return lru; +} + +ULONG ReleaseLRU(LRU_HANDLE *lru_handle, LRU *lru) +{ + NWLockLRU((ULONG)ReleaseLRU); + + lru->lock_count--; + RemoveLRU(lru->lru_handle, lru); + if (lru->lru_handle == lru_handle) + InsertLRUTop(lru->lru_handle, lru); + else + InsertLRU(lru->lru_handle, lru); + + NWUnlockLRU((ULONG)ReleaseLRU); + return 0; +} + +ULONG ReleaseDirtyLRU(LRU_HANDLE *lru_handle, LRU *lru) +{ + NWLockLRU((ULONG)ReleaseDirtyLRU); + + lru->state &= ~L_UPTODATE; + lru->state |= L_MODIFIED; + lru->lock_count--; + +#if (LINUX_20 | LINUX_22 | LINUX_24) + lru->timestamp = GetLRUTime(); +#endif + if (!(lru->state & L_DIRTY)) + InsertDirty(lru); + + RemoveLRU(lru->lru_handle, lru); + if (lru->lru_handle == lru_handle) + InsertLRUTop(lru->lru_handle, lru); + else + InsertLRU(lru->lru_handle, lru); + + NWUnlockLRU((ULONG)ReleaseDirtyLRU); + return 0; +} + +ULONG SyncLRUBlocks(VOLUME *volume, ULONG block, ULONG blocks) +{ + register ULONG ccode, retCode = 0; + register ULONG i; + register LRU *lru; + + if (!blocks) + return -1; + + NWLockLRU((ULONG)SyncLRUBlocks); + for (i = 0; i < blocks; i++) + { + lru = SearchHash(volume, block + i); + if (lru) + { + if ((lru->state & L_DIRTY) && + (lru->state & L_DATAVALID) && + (lru->nwvp_handle) && + (!(lru->state & L_FLUSHING))) + { + lru->state |= L_FLUSHING; + lru->state &= ~L_MODIFIED; + NWUnlockLRU((ULONG)SyncLRUBlocks); + + ccode = nwvp_vpartition_block_write(lru->nwvp_handle, + lru->block, 1, lru->buffer); + + NWLockLRU((ULONG)SyncLRUBlocks); + lru->state &= ~L_FLUSHING; + lru->timestamp = 0; + + + if (!ccode) + { + if (!(lru->state & L_MODIFIED)) + RemoveDirty(lru); + } + else + retCode = ccode; + } + } + } + NWUnlockLRU((ULONG)SyncLRUBlocks); + return retCode; + +} + +#if (READ_AHEAD_ON) + +ULONG PerformBlockReadAhead(LRU_HANDLE *lru_handle, VOLUME *volume, + ULONG block, ULONG blockReadAhead, ULONG ccount, + ULONG *mirror) +{ + register ULONG i; + register LRU *lru; +#if (DO_ASYNCH_IO && ASYNCH_READ_AHEAD && !LINUX_UTIL) + BYTE disks[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#endif + + if (!blockReadAhead) + return -1; + + NWLockLRU((ULONG)PerformBlockReadAhead); + for (i = 0; i < blockReadAhead; i++) + { + lru = SearchHash(volume, block + i); + if (!lru) +#if (DO_ASYNCH_IO && ASYNCH_READ_AHEAD && !LINUX_UTIL) + FillBlockAsynch(lru_handle, volume, block + i, ccount, disks, + mirror); +#else + FillBlock(lru_handle, volume, block + i, 1, ccount, mirror); +#endif + } + NWUnlockLRU((ULONG)PerformBlockReadAhead); + +#if (DO_ASYNCH_IO && ASYNCH_READ_AHEAD && !LINUX_UTIL) + for (i=0; i < 8; i++) + { + if (disks[i]) + RunAsynchIOQueue(i); + } +#endif + + return 0; + +} + +#endif + +LRU *ReadLRU(LRU_HANDLE *lru_handle, VOLUME *volume, ULONG block, + ULONG fill, ULONG ccount, ULONG readAhead, + ULONG *mirror) +{ + register LRU *lru; + + // validate the priority of this request and adjust it to something + // reasonable if we are passed an out of range value. + // don't allow blocks to recycle more than three times prior to + // being evicted from the LRU. + + if (!ccount || (ccount > 3)) + ccount = 1; + +#if (READ_AHEAD_ON) + // perform read ahead if we were asked to fill any blocks. + if (fill && readAhead) + PerformBlockReadAhead(lru_handle, volume, block + 1, readAhead - 1, + ccount, mirror); +#endif + +repeat:; + NWLockLRU((ULONG)ReadLRU); + + lru = SearchHash(volume, block); + if (lru) + { + if (lru->state & L_LOADING) + goto WaitOnBuffer; + + // this indicates an I/O error + if (!(lru->state & L_DATAVALID)) + { + NWFSPrint("I/O error in Read LRU\n"); + NWUnlockLRU((ULONG)ReadLRU); + return 0; + } + + lru->lock_count++; + NWUnlockLRU((ULONG)ReadLRU); + return lru; + } + +#if (LINUX_20 | LINUX_22 | LINUX_24) + if ((LRUDirtyBuffers * PERCENT_FACTOR) >= LRUBlocks) + { + if (!lru_signal) + { + if (!lru_active) + { + lru_signal = TRUE; + NWFSFlush(); + } + } + } +#endif + + // this call is blocking. + lru = FillBlock(lru_handle, volume, block, fill, + ccount, mirror); + if (lru) + { + lru->lock_count++; + NWUnlockLRU((ULONG)ReadLRU); + return lru; + } + + NWUnlockLRU((ULONG)ReadLRU); + +#if (LINUX_20 | LINUX_22 | LINUX_24) + lru_state = NWFS_FLUSH_ALL; + if (!lru_signal) + { + if (!lru_active) + { + lru_signal = TRUE; + lru_state = NWFS_FLUSH_ALL; + NWFSFlush(); + } + } + + schedule(); + goto repeat; + +#else + FlushLRU(); + goto repeat; +#endif + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +WaitOnBuffer:; + lru->Waiters++; + NWUnlockLRU((ULONG)ReadLRU); + + NWLockBuffer(lru); + if (!(lru->state & L_DATAVALID) || + (lru->block != block) || + (lru->volnum != volume->VolumeNumber)) + return 0; + + goto repeat; + +#endif + +} + +void DisplayLRUInfo(LRU_HANDLE *lru_handle) +{ + register LRU *lru; + + lru_handle->dirty = 0; + lru_handle->loading = 0; + lru_handle->flushing = 0; + lru_handle->locked = 0; + lru_handle->valid = 0; + lru_handle->uptodate = 0; + lru_handle->total = 0; + lru_handle->free = 0; + + lru = ListHead; + while (lru) + { + if (lru->lru_handle == lru_handle) + { + lru_handle->total++; + + if (lru->state & L_FREE) + lru_handle->free++; + + if (lru->state & L_DIRTY) + lru_handle->dirty++; + + if (lru->state & L_DATAVALID) + lru_handle->valid++; + + if (lru->state & L_UPTODATE) + lru_handle->uptodate++; + + if (lru->state & L_FLUSHING) + lru_handle->flushing++; + + if (lru->state & L_LOADING) + lru_handle->loading++; + + if (lru->lock_count) + lru_handle->locked++; + } + lru = lru->listnext; + } + + NWFSPrint("%-10s drt-%d vld-%d utod-%d flsh-%d ld-%d lk-%d free-%d t-%d/%d\n", + lru_handle->LRUName, + (int)lru_handle->dirty, + (int)lru_handle->valid, + (int)lru_handle->uptodate, + (int)lru_handle->flushing, + (int)lru_handle->loading, + (int)lru_handle->locked, + (int)lru_handle->free, + (int)lru_handle->total, + (int)lru_handle->LocalLRUBlocks); + + return; +} + +BYTE *get_taddress(ULONG addr) +{ + if (addr == (ULONG)FreeLRU) + return "FreeLRU"; + else + if (addr == (ULONG)FlushLRU) + return "FlushLRU"; + else + if (addr == (ULONG)FlushEligibleLRU) + return "FlushEligibleLRU"; + else + if (addr == (ULONG)release_write_aio) + return "release_write_aio"; + else + if (addr == (ULONG)retry_write_aio) + return "retry_write_aio"; + else + if (addr == (ULONG)FlushVolumeLRU) + return "FlushVolumeLRU"; + else + if (addr == (ULONG)GetAvailableLRU) + return "GetAvailableLRU"; + else + if (addr == (ULONG)FillBlock) + return "FillBlock"; + else + if (addr == (ULONG)retry_asynch_read_ahead) + return "retry_asynch_read_ahead"; + else + if (addr == (ULONG)release_asynch_read_ahead) + return "release_asynch_read_ahead"; + else + if (addr == (ULONG)ReleaseLRU) + return "ReleaseLRU"; + else + if (addr == (ULONG)ReleaseDirtyLRU) + return "ReleaseDirtyLRU"; + else + if (addr == (ULONG)SyncLRUBlocks) + return "SyncLRUBlocks"; + else + if (addr == (ULONG)PerformBlockReadAhead) + return "PerformBlockReadAhead"; + else + if (addr == (ULONG)ReadLRU) + return "ReadLRU"; + else + return "unknown"; + +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/mmap.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/mmap.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/mmap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/mmap.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,473 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : MMAP.C +* DESCRIP : NWFS VFS Memory Mapping Module for Linux +* DATE : December 6, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +extern ULONG insert_io(ULONG disk, ASYNCH_IO *io); +extern void RunAsynchIOQueue(ULONG disk); +extern ULONG nwfs_to_linux_error(ULONG NwfsError); + +// this function returns the volume logical block number from the +// logical file block number. + +ULONG NWFileMapBlock(VOLUME *volume, HASH *hash, ULONG Offset, + ULONG *boffset) +{ + register ULONG Length, vBlock; + register long FATChain, index, voffset; + register ULONG StartIndex, StartOffset, rc; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + SUBALLOC_MAP map; +#if (!HASH_FAT_CHAINS) + register ULONG ccode; + register MACINTOSH *mac; + DOS dos; +#endif + + // if a subdirectory or bad bsize then return error + if (!hash || (hash->Flags & SUBDIRECTORY_FILE)) + return (ULONG) -1; + + if (boffset) + *boffset = 0; + +#if (HASH_FAT_CHAINS) + FATChain = hash->FirstBlock; + Length = hash->FileSize; +#else + ccode = ReadDirectoryRecord(volume, &dos, hash->DirNo); + if (ccode) + return -1; + + FATChain = dos.FirstBlock; + Length = dos.FileSize; +#endif + + StartIndex = Offset / volume->ClusterSize; + StartOffset = Offset % volume->ClusterSize; + + // we always start with an index of zero + index = 0; + if (FATChain & 0x80000000) + { + // check for EOF + if (FATChain == (ULONG) -1) + return (ULONG) -1; + + // index must be null here + if (StartIndex) + return (ULONG) -1; + + rc = MapSuballocNode(volume, &map, FATChain); + if (rc) + return (ULONG) -1; + + if (StartOffset >= map.Size) + return (ULONG) -1; + + if (StartOffset >= map.clusterSize[0]) + { + if (map.Count == 1) + return (ULONG) -1; + + voffset = StartOffset - map.clusterSize[0]; + vBlock = (map.clusterNumber[1] * volume->BlocksPerCluster) + + ((map.clusterOffset[1] + voffset) / IO_BLOCK_SIZE); + if (boffset) + *boffset = ((map.clusterOffset[1] + voffset) % IO_BLOCK_SIZE); + return vBlock; + } + else + { + vBlock = (map.clusterNumber[0] * volume->BlocksPerCluster) + + ((map.clusterOffset[0] + StartOffset) / IO_BLOCK_SIZE); + if (boffset) + *boffset = ((map.clusterOffset[0] + StartOffset) % IO_BLOCK_SIZE); + return vBlock; + } + } + + FAT = GetFatEntry(volume, FATChain, &FAT_S); + if (FAT) + index = FAT->FATIndex; + + while (FAT && FAT->FATCluster) + { + // we detected a hole in the file + if (StartIndex < index) + { + // return 0 if we detect a hole in the file. + vBlock = 0; + return vBlock; + } + + // we found our cluster in the chain + if (StartIndex == index) + { + vBlock = (FATChain * volume->BlocksPerCluster) + + (StartOffset / IO_BLOCK_SIZE); + if (boffset) + *boffset = (StartOffset % IO_BLOCK_SIZE); + return vBlock; + } + + // bump to the next cluster + FATChain = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF marker + if (FATChain & 0x80000000) + { + // end of file + if (FATChain == (ULONG) -1) + return (ULONG) -1; + + // check for valid index + if ((index + 1) == StartIndex) + { + rc = MapSuballocNode(volume, &map, FATChain); + if (rc) + return (ULONG) -1; + + if (StartOffset >= map.Size) + return (ULONG) -1; + + if (StartOffset >= map.clusterSize[0]) + { + if (map.Count == 1) + return (ULONG) -1; + + voffset = StartOffset - map.clusterSize[0]; + vBlock = (map.clusterNumber[1] * volume->BlocksPerCluster) + + ((map.clusterOffset[1] + voffset) / IO_BLOCK_SIZE); + if (boffset) + *boffset = ((map.clusterOffset[1] + voffset) % + IO_BLOCK_SIZE); + return vBlock; + } + else + { + vBlock = (map.clusterNumber[0] * volume->BlocksPerCluster) + + ((map.clusterOffset[0] + StartOffset) / IO_BLOCK_SIZE); + if (boffset) + *boffset = ((map.clusterOffset[0] + StartOffset) % + IO_BLOCK_SIZE); + return vBlock; + } + } + return (ULONG) -1; + } + + // get next fat table entry and index + FAT = GetFatEntry(volume, FATChain, &FAT_S); + if (FAT) + index = FAT->FATIndex; + } + return (ULONG) -1; + +} + + +ULONG nwfs_map_extents(VOLUME *volume, HASH *hash, ULONG block, + ULONG bsize, ULONG *device, ULONG extend, + ULONG *retCode, ASYNCH_IO *io, + struct inode *inode, ULONG *vblock, + ULONG *voffset, nwvp_asynch_map *map, + ULONG *count) +{ + register ULONG ccode, disk, vBlock, vMap, mirror_index; + ULONG boffset = 0; + DOS dos; + + if (vblock) + *vblock = 0; + + if (voffset) + *voffset = 0; + + if (device) + *device = 0; + + if (retCode) + *retCode = 0; + + if (extend) + { + ccode = ReadDirectoryRecord(volume, &dos, hash->DirNo); + if (ccode) + return 0; + + // NWWriteFile() supports an extend mode that will extend the + // meta-data for a file if we pass a NULL address for the data + // buffer argument without writing any data to the extended + // area. + + ccode = NWWriteFile(volume, + &dos.FirstBlock, + dos.Flags, + block * bsize, + NULL, + (1 << PAGE_CACHE_SHIFT), + 0, + 0, + retCode, + KERNEL_ADDRESS_SPACE, + ((volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0), + dos.FileAttributes); + + if (ccode != (1 << PAGE_CACHE_SHIFT)) + return 0; + + if (retCode && *retCode) + return 0; + +#if (HASH_FAT_CHAINS) + hash->FirstBlock = dos.FirstBlock; +#endif + + // since we extended the file, flag as modified to force + // suballocation during file close. + hash->State |= NWFS_MODIFIED; + + ccode = WriteDirectoryRecord(volume, &dos, hash->DirNo); + if (ccode) + return 0; + } + + if (map && count) + { + vBlock = NWFileMapBlock(volume, hash, block * bsize, &boffset); + if (!vBlock || (vBlock == (ULONG) -1)) + { +#if (VERBOSE) + NWFSPrint("[%s] no map vBlock-%d block-%d\n", hash->Name, + (int)vBlock, (int)block); +#endif + return 0; + } + + ccode = nwvp_vpartition_map_asynch_write(volume->nwvp_handle, + vBlock, count, map); + if (!ccode && *count) + { + extern ULONG mirror_counter; + + // select a random mirror to read from + mirror_index = mirror_counter % *count; + mirror_counter++; + + disk = map[mirror_index].disk_id; + if (SystemDisk[disk]) + { + *device = (ULONG)SystemDisk[disk]->PhysicalDiskHandle; + + vMap = (map[mirror_index].sector_offset / (bsize / 512)) + + (boffset / bsize); + + if (vblock) + *vblock = vBlock; + + if (voffset) + *voffset = boffset; + +#if (VERBOSE) + NWFSPrint("[%s] block/size-%d/%d vblock-%d vMap-%08X boff=%d ext-%d\n", + hash->Name, + (int)block, + (int)bsize, + (int)vBlock, + (unsigned)vMap, + (int)boffset, + (int)extend); +#endif + return vMap; + } + } + } + return 0; +} + +int nwfs_get_block(struct inode *inode, long block, + struct buffer_head *bh_result, int create) +{ + register VOLUME *volume = inode->i_sb->u.generic_sbp; + register HASH *hash = inode->u.generic_ip; + register ULONG lba, totalBlocks; + ULONG device = 0, retCode = 0, count = 0; + nwvp_asynch_map map[8]; + + create = TRUE; + +#if (VERBOSE) + NWFSPrint("get_block block-%d create-%d [%s]\n", (int)block, + (int)create, hash->Name); +#endif + + if (!hash) + return -EBADF; + + if (!volume) + return -EBADF; + + if (!inode->i_sb->s_blocksize || + (inode->i_sb->s_blocksize > volume->BlockSize)) + return -EBADF; + + totalBlocks = (volume->VolumeClusters * volume->BlocksPerCluster); + totalBlocks = totalBlocks * (IO_BLOCK_SIZE / inode->i_sb->s_blocksize); + if ((block < 0) || (block > totalBlocks)) + { + NWFSPrint("nwfs: mmap exceeded volume size block-%d total-%d\n", + (int)block, (int)totalBlocks); + return -EIO; + } + + NWLockFileExclusive(hash); + + // if someone passes in a NULL bh_result buffer, and create is set + // TRUE, then we just want to extend the file without redundantly + // calling nwfs_map_extents() several times. + + lba = nwfs_map_extents(volume, hash, block, inode->i_sb->s_blocksize, + (bh_result ? &device : NULL), + (bh_result ? 0 : create), + &retCode, 0, inode, 0, 0, + (bh_result ? &map[0] : NULL), + (bh_result ? &count : NULL)); + if (retCode) + { + NWUnlockFile(hash); + return nwfs_to_linux_error(retCode); + } + + if (!bh_result) + { + NWUnlockFile(hash); + return 0; + } + + if (lba && device) + { + bh_result->b_dev = device; + bh_result->b_blocknr = lba; + bh_result->b_state |= (1UL << BH_Mapped); + if (create) + bh_result->b_state |= (1UL << BH_New); + NWUnlockFile(hash); + return 0; + } + + if (!create) + { + NWUnlockFile(hash); + return 0; + } + + lba = nwfs_map_extents(volume, hash, block, inode->i_sb->s_blocksize, + &device, create, &retCode, 0, inode, 0, 0, + &map[0], &count); + if (retCode) + { + NWUnlockFile(hash); + return nwfs_to_linux_error(retCode); + } + + if (lba && device) + { + bh_result->b_dev = device; + bh_result->b_blocknr = lba; + bh_result->b_state |= (1UL << BH_Mapped); + bh_result->b_state |= (1UL << BH_New); + NWUnlockFile(hash); + return 0; + } + + NWUnlockFile(hash); + return -EIO; +} + +int nwfs_readpage(struct file *file, struct page *page) +{ + return (block_read_full_page(page, nwfs_get_block)); +} + +int nwfs_bmap(struct address_space *mapping, long block) +{ + return (generic_block_bmap(mapping, block, nwfs_get_block)); +} + +int nwfs_writepage(struct page *page) +{ + return (block_write_full_page(page, nwfs_get_block)); +} + +int nwfs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + return (block_prepare_write(page, from, to, nwfs_get_block)); +} + +int nwfs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + return (generic_commit_write(file, page, from, to)); +} + +struct address_space_operations nwfs_aops = +{ + readpage: nwfs_readpage, + writepage: nwfs_writepage, + prepare_write: nwfs_prepare_write, + commit_write: nwfs_commit_write, + bmap: nwfs_bmap, +}; + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwcreate.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwcreate.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwcreate.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwcreate.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,4220 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWCREATE.C +* DESCRIP : NWFS Directory Creation and Deletion Routines +* DATE : February 12, 1999 +* +* +***************************************************************************/ + +#include "globals.h" + +// +// GENERAL: NetWare seems to allow just about anything in a name, even DOS +// names, if you believe the output from the NameSpace modules. This would +// make sense, since NetWare clients and not the server actually provide +// the UNICODE support for remote clients. NetWare names, even DOS names, +// have the ability to use just about all of the 0-256 range for special +// code page character sets, etc. in terms of what values actually end up +// inside of a directory record. There is a filter through the file system +// APIs for "behaved" and "unique" DOS names to get created during install, +// or with NLM based programs(???) (calling an NLM an "application" is +// technically incorrect, they are "kernel extensions"). Internally, the +// NetWare file system appears to allow pretty broad freedom with name entry +// values. This means that direct Unicode/NetWare CodePage conversions +// are possible, and in fact, the Windows NT NWFS works this way. Netware +// UNICODE support has trouble with UNICODE characters when converting +// between a Windows NT UNICODE name and a NetWare name in some cases. +// +// Netware also handles internationalization via the client, and not +// the server, and it's interesting to note that even French and +// German versions of Netware still host the english names on the +// server itself. It's the Netware client and not the server that +// actually performs much of the magic with language enabling. The +// obvious disadvantage here is that on linux, Netware volumes created +// with international versions of Netware may revert back to their +// english names when mounted under linux. The Novell KK (Novell +// Japan) version of Netware for the Japanese and Far Eastern markets +// does have some subtle differences to plain Netware, and our current +// NWFS code base is not enabled for DBCS Novell KK Netware file +// system support. +// +// This implementation filters naming requests through a Linux template +// via either the DOS, LONG, or UNIX namespaces. The MAC namespace +// information is maintained during create and directory namespace +// modifications. +// +// In order to create NetWare compatible MAC names, and to avoid +// data loss by rendering a file's name incomprehensible or non-unique, we +// attempt to remain compatibile with NetWare by limiting the name to 31 +// instead of 32 characters (seems to be a NetWare specific bug we should +// reproduce ???). +// + +BYTE DOSValidCharBitmap[] = +{ + 0x00, 0x00, 0x00, 0x00, + 0x52, 0x63, 0xFF, 0x03, + 0xFF, 0xFF, 0xFF, 0x87, + 0xFF, 0xFF, 0xFF, 0xE8, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00 +}; + +BYTE DOSSkipCharBitmap[] = +{ + 0x00, 0x00, 0x00, 0x00, + 0x05, 0x40, 0x00, 0xD4, + 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +BYTE DOSReplaceCharBitmap[] = +{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +// These characters are allowed in a LONG file name but not a DOS File Name +// (Netware 5.x, IntraNetWare (4.x) does not seem to care) +// =(x3D) %(x25) #(x23) +(x2B) +// '(x27) [(x5B) ](x5D) ;(x3B) +// ,(x2C) "(x22) (x20) + +BYTE LONGValidCharBitmap[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0x7B, 0xFF, 0x2F, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00 +}; + +BYTE NFSValidCharBitmap[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0x7B, 0xFF, 0x2F, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00 +}; + +// this is probably ok for the MAC name table since all the bytes +// are filtered through the conversion tables below +BYTE MACValidCharBitmap[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0x7B, 0xFF, 0x2F, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00 +}; + +BYTE DOSToMACConvertTable[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x82, 0x9F, 0x8E, 0x89, 0x8A, 0x88, 0x8C, 0x8D, + 0x90, 0x91, 0x8F, 0x95, 0x94, 0x93, 0x80, 0x81, + 0x83, 0xBE, 0xAE, 0x99, 0x9A, 0x98, 0x9E, 0x9D, + 0xD8, 0x85, 0x86, 0xA2, 0xA3, 0xB4, 0xCC, 0xC4, + + 0x87, 0x92, 0x97, 0x9C, 0x96, 0x84, 0xBB, 0xBC, + 0xC0, 0x8B, 0xC2, 0x9B, 0xA0, 0xC1, 0xC7, 0xC8, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xCD, 0xD7, + 0xCE, 0xCF, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0xA4, 0xA7, 0xA6, 0xB9, 0xB7, 0xA8, 0xB5, 0xA9, + 0xAA, 0xAB, 0xBD, 0xB6, 0xB0, 0xBF, 0xCB, 0xAD, + + 0xAF, 0xB1, 0xB3, 0xB2, 0xB8, 0xBA, 0xD6, 0xC5, + 0xA1, 0xA5, 0xE1, 0xC3, 0xAC, 0xC6, 0xC9, 0xCA, + 0 +}; + +BYTE MACToDOSConvertTable[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x8E, 0x8F, 0x80, 0x90, 0xA5, 0x99, 0x9A, 0xA0, + 0x85, 0x83, 0x84, 0xA9, 0x86, 0x87, 0x82, 0x8A, + 0x88, 0x89, 0xA1, 0x8D, 0x8C, 0x8B, 0xA4, 0xA2, + 0x95, 0x93, 0x94, 0xAB, 0xA3, 0x97, 0x96, 0x81, + + 0xAC, 0xF8, 0x9B, 0x9C, 0xE0, 0xF9, 0xE2, 0xE1, + 0xE5, 0xE7, 0xE8, 0xE9, 0xFC, 0xEF, 0x92, 0xF0, + 0xEC, 0xF1, 0xF3, 0xF2, 0x9D, 0xE6, 0xEB, 0xE4, + 0xF4, 0xE3, 0xF5, 0xA6, 0xA7, 0xEA, 0x91, 0xED, + 0xA8, 0xAD, 0xAA, 0xFB, 0x9F, 0xF7, 0xFD, 0xAE, + + 0xAF, 0xFE, 0xFF, 0xEE, 0x9E, 0xB6, 0xB8, 0xB9, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xF6, 0xB7, + 0x98, 0xC1, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xFA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0 +}; + +BYTE DOSUpperCaseTable[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + + 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0 +}; + +BYTE DOSLowerCaseTable[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0 +}; + +// MS-DOS device reserved file names NetWare appears to check for +// and disallows in any namespace implementation. It should be noted +// that one of these names (PIPE) will actually generate a file +// system mount error under Netware if you allow folks to create +// it. The other names may cause client software to malfunction +// if we allow them to exist. + +BYTE *ReservedNames[]= +{ + "NETQ ", "PIPE ", "CLOCK$ ", "CON ", + "PRN ", "NUL ", "AUX ", "LPT1 ", + "LPT2 ", "LPT3 ", "LPT4 ", "LPT5 ", + "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ", + "COM1 ", "COM2 ", "COM3 ", "COM4 ", + "COM5 ", "COM6 ", "COM7 ", "COM8 ", + "COM9 ", 0 +}; + +extern ULONG FreeHashDirectoryRecord(VOLUME *volume, HASH *hash); + +ULONG TestCharacter(BYTE *p, BYTE c) +{ + return (ULONG) (((p[c >> 3]) >> (c & 7)) & 1); +} + +// +// these functions determine whether a given name is valid or not +// for a given namespace. Some of the logic in the DOS function was +// adopted from the linux fat file system, though we were forced +// to make some changes to correct problems in the fat file system +// with collapsed names. +// + +ULONG NWValidDOSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag) +{ + register BYTE **Reserved; + register ULONG retCode, i, RemainingLength, Space = 0; + register HASH *hash; + BYTE DOSName[MAX_DOS_NAME]; + + NWFSSet(DOSName, ' ', MAX_DOS_NAME); + + if (NameLength > MAX_DOS_NAME) + { + return NwBadName; + } + + // MSDOS file names cannot begin with a '.' + if (DOSName[0] == '.') + { + return NwBadName; + } + + // create case insensitive string + for (i=0; (i < MAX_DOS_NAME) && (i < NameLength); i++) + DOSName[i] = DOSUpperCaseTable[(BYTE)Name[i]]; + + // check the first 8 characters for any invalid characters. + // If any are found, reject the name. also check the + // character after the first 8 and see if it's a '.' entry. + + for (RemainingLength = NameLength, i = 0; + (i < NameLength) && (i < 8); + i++, RemainingLength--) + { + if (DOSName[i] == '.') + break; + + retCode = TestCharacter(DOSValidCharBitmap, DOSName[i]); + if (!retCode) + { + return NwBadName; + } + + Space = (DOSName[i] == ' '); + } + + // if there was a space in the name, reject it. + if (Space) + { + return NwBadName; + } + + // if we have additional characters, then see if the next character is + // a dot. + + if (RemainingLength && DOSName[i] != '.') + { + return NwBadName; + } + + // if we found the dot, then process the file extension + if (RemainingLength && DOSName[i] == '.') + { + // if there are too many possible extension characters, error + if (RemainingLength > 4) + { + return NwBadName; + } + + // skip past first '.' character + i++; + RemainingLength--; + + while ((RemainingLength > 0) && (i < MAX_DOS_NAME) && + (i < NameLength)) + { + // only one '.' entry is allowed. reject the name if we + // detect a subsequent '.' within the extension. + + if (DOSName[i] == '.') + { + return NwBadName; + } + + retCode = TestCharacter(DOSValidCharBitmap, DOSName[i]); + if (!retCode) + { + return NwBadName; + } + + Space = (DOSName[i] == ' '); + + i++; + RemainingLength--; + } + // if we encountered a space or we still have characters left, + // then report error. + if (Space) + { + return NwBadName; + } + if (RemainingLength) + { + return NwBadName; + } + } + + // see if the name conflicts with any special or reserved + // DOS or Netware names. if so, disallow the name. + + for (Reserved = ReservedNames; *Reserved; Reserved++) + if (!strncmp(Name, *Reserved, 8)) + { + return NwBadName; + } + + // see if the name exists in the specified namespace + if (searchFlag) + { + hash = GetHashFromName(volume, DOSName, NameLength, DOS_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + } + return 0; +} + +ULONG NWValidMACName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag) +{ + register ULONG i, len, retCode; + register HASH *hash; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + for (len=i=0; (i < NameLength) && (i < MAX_MAC_NAME); i++) + { + retCode = TestCharacter(MACValidCharBitmap, Name[i]); + if (!retCode) + return NwBadName; + } + + // see if the name exists in the specified namespace + if (searchFlag) + { + hash = GetHashFromName(volume, Name, NameLength, MAC_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + } + return 0; +} + +ULONG NWValidNFSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag) +{ + register ULONG i, len, retCode; + register HASH *hash; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + for (len=i=0; (i < NameLength) && (i < MAX_NFS_NAME); i++) + { + retCode = TestCharacter(NFSValidCharBitmap, Name[i]); + if (!retCode) + return NwBadName; + } + + // see if the name exists in the specified namespace + if (searchFlag) + { + hash = GetHashFromName(volume, Name, NameLength, UNIX_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + } + return 0; +} + +ULONG NWValidLONGName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag) +{ + register ULONG i, len, retCode; + register HASH *hash; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + for (len=i=0; (i < NameLength) && (i < MAX_LONG_NAME); i++) + { + retCode = TestCharacter(LONGValidCharBitmap, Name[i]); + if (!retCode) + return NwBadName; + } + + // see if the name exists in the specified namespace + if (searchFlag) + { + hash = GetHashFromName(volume, Name, NameLength, LONG_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + } + return 0; +} + +// +// these functions copy and/or transform names as required. This code +// method was adapted from the VFAT file system. + +#define MSDOS_NAME 11 + +// OpFlag = 0 search all name hashes for name collisions +// OpFlag = 1 do not search any hashes for name collisions + +ULONG NWCreateUniqueName(VOLUME *volume, ULONG Parent, + BYTE *Name, ULONG NameLength, + BYTE *MangledName, BYTE *MangledNameLength, + ULONG OpFlag) +{ + register HASH *hash; + register BYTE *ip, *p; + register BYTE *ExtensionStart, *NameEnd, *NameStart; + register ULONG Size, ExtensionLength, BaseLength, i, value; + BYTE FileBase[8], FileExtension[3], Buffer[8]; + + if (!MangledNameLength) + return NwInvalidParameter; + + NWFSSet(FileBase, ' ', 8); + NWFSSet(FileExtension, ' ', 3); + + Size = 0; + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + ExtensionStart = NameEnd = &Name[NameLength]; + while (--ExtensionStart >= Name) + { + if (*ExtensionStart == '.') + { + if (ExtensionStart == (NameEnd - 1)) + { + Size = NameLength; + ExtensionStart = NULL; + } + break; + } + } + + // if we could not find a '.' entry, assume no extension + if (ExtensionStart == (Name - 1)) + { + Size = NameLength; + ExtensionStart = NULL; + } + else + if (ExtensionStart) + { + // we found a '.' entry somewhere in the name + NameStart = &Name[0]; + + // begin from start of name to location of '.' entry + // and skip invalid characters until we find the first + // valid character for a DOS name. + while (NameStart < ExtensionStart) + { + if (!TestCharacter(DOSSkipCharBitmap, *NameStart)) + break; + + if (TestCharacter(DOSValidCharBitmap, *NameStart)) + break; + + NameStart++; + } + + // if we found a valid character and we have not + // reached the '.' entry, then calculate the size + // of the base filename, and bump the extension + // start pointer to the first character after + // the '.' entry. + + if (NameStart != ExtensionStart) + { + Size = ExtensionStart - Name; + ExtensionStart++; + } + else + { + Size = NameLength; + ExtensionStart = NULL; + } + } + + for (BaseLength = i = 0, p = FileBase, ip = Name; + (i < Size) && (BaseLength < 8); + i++) + { + if (*ip & 0x80) + { + *p++ = '_'; + BaseLength++; + continue; + } + + if (!TestCharacter(DOSSkipCharBitmap, *ip) && + TestCharacter(DOSValidCharBitmap, *ip)) + { + *p = *ip; + + if (TestCharacter(DOSReplaceCharBitmap, *p)) + *p='_'; + + p++; + BaseLength++; + } + ip++; + } + + if (BaseLength == 0) + return NwBadName; + + ExtensionLength = 0; + if (ExtensionStart) + { + for (p = FileExtension, ip = ExtensionStart; + (ExtensionLength < 3) && (ip < NameEnd); + ip++) + { + if (*ip & 0x80) + { + *p++ = '_'; + ExtensionLength++; + continue; + } + + if (!TestCharacter(DOSSkipCharBitmap, *ip) && + TestCharacter(DOSValidCharBitmap, *ip)) + { + *p = *ip; + + if (TestCharacter(DOSReplaceCharBitmap, *p)) + *p='_'; + + ExtensionLength++; + p++; + } + } + } + + if (BaseLength > 8) + BaseLength = 8; + + if (ExtensionLength > 3) + ExtensionLength = 3; + + // attempt to randomize a DOS name even more so if it exceeded + // the legal filename size for MSDOS. The fat file system + // implementation does not try to randomize file names and + // during some copy operations, two or more files can be lost + // and collapsed into a single file because the fat implementation + // will convert them to identical names during create (cp isn't + // very smart, and if a filename has been created, if a new name + // hashes to the same mangled name, we will overwrite an existing + // file rather than create a new one.). We have implemented a + // different method from the fat file system that adds the + // bytes for a name together, and creates the name from a hash + // value. + + // check if the name is longer than default DOS filename length. + if (Size > 8) + { + // if so, we are going to calculate a hash of the source name + // and use the hash value to create the unique name. This will + // attempt to guarantee uniqueness of the names and prevent + // similar names like "trampoline.S" and "trampoline32.S from + // mangling to an identical name (TRAMPOLI.S). The fat file + // system actually allows this, and will collapse several files + // into a single file during name mangling operations if you + // perform recursive copies of the linux tree onto a fat + // partition. + + if (BaseLength > 5) + BaseLength = 5; + + NWFSSet(MangledName, ' ', 12); + NWFSCopy(MangledName, FileBase, BaseLength); + MangledName[BaseLength] = '~'; + + // calculate horner hash value from the original name + value = NWFSStringHash(Name, NameLength, 255); + for (i = value; i < 255; i++) + { + sprintf(Buffer, "%02X", (unsigned int) i); + NWFSCopy(&MangledName[BaseLength + 1], Buffer, 2); + + if (ExtensionLength) + { + MangledName[BaseLength + 3] = '.'; + NWFSCopy(&MangledName[BaseLength + 4], FileExtension, ExtensionLength); + } + *MangledNameLength = (BYTE)(BaseLength + ExtensionLength + 3 + (ExtensionLength > 0)); + + // if we were not asked to search the hashes, then just transform + // the name to it's first instanciation, then exit the function. + if (OpFlag) + return 0; + + hash = GetHashFromName(volume, MangledName, (*MangledNameLength), + DOS_NAME_SPACE, Parent); + +#if (VERBOSE) + NWFSPrint("(1a) BaseLength-%d ExtensionLength-%d [%12s]-%d hash-%X\n", + (int)BaseLength, (int)ExtensionLength, MangledName, + (int)*MangledNameLength, + (unsigned int)hash); +#endif + + if (!hash) + return 0; + } + } + else + { + NWFSSet(MangledName, ' ', 12); + NWFSCopy(MangledName, FileBase, BaseLength); + if (ExtensionLength) + { + MangledName[BaseLength] = '.'; + NWFSCopy(&MangledName[BaseLength + 1], FileExtension, ExtensionLength); + } + *MangledNameLength = (BYTE)(BaseLength + ExtensionLength + (ExtensionLength > 0)); + + // if we were not asked to search the hashes, then just transform + // the name to it's first instanciation, then exit the function. + if (OpFlag) + return 0; + + hash = GetHashFromName(volume, MangledName, (*MangledNameLength), + DOS_NAME_SPACE, Parent); +#if (VERBOSE) + NWFSPrint("(1b) BaseLength-%d ExtensionLength-%d [%12s]-%d hash-%X\n", + (int)BaseLength, (int)ExtensionLength, MangledName, + (int)*MangledNameLength, + (unsigned int)hash); +#endif + + if (!hash) + return 0; + } + + if (BaseLength > 6) + BaseLength = 6; + + NWFSSet(MangledName, ' ', 12); + NWFSCopy(MangledName, FileBase, BaseLength); + MangledName[BaseLength] = '~'; + + for (i = 1; i < 10; i++) + { + MangledName[BaseLength + 1] = (BYTE)(i + '0'); + + if (ExtensionLength) + { + MangledName[BaseLength + 2] = '.'; + NWFSCopy(&MangledName[BaseLength + 3], FileExtension, ExtensionLength); + } + *MangledNameLength = (BYTE)(BaseLength + ExtensionLength + 2 + (ExtensionLength > 0)); + + hash = GetHashFromName(volume, MangledName, (*MangledNameLength), + DOS_NAME_SPACE, Parent); + +#if (VERBOSE) + NWFSPrint("(2) BaseLength-%d ExtensionLength-%d [%12s]-%d hash-%X\n", + (int)BaseLength, (int)ExtensionLength, MangledName, + (int)*MangledNameLength, + (unsigned int)hash); +#endif + + if (!hash) + return 0; + } + +#if (LINUX_20 | LINUX_22 | LINUX_24) + i = jiffies & 0xffff; + Size = (jiffies >> 16) & 0x7; +#endif + + if (BaseLength > 2) + BaseLength = 2; + + NWFSSet(MangledName, ' ', 12); + NWFSCopy(MangledName, FileBase, BaseLength); + + MangledName[BaseLength + 4] = '~'; + MangledName[BaseLength + 5] = (BYTE)('1' + Size); + + while (1) + { + // This code was adapted from the VFAT file system for creating + // random names. although the method being used in VFAT works + // well enough, it is not the actual method used in Windows NT + // and Windows 98 to do this. In Microsoft implementations + // of fat, random short names are actually derived from a file's + // checksum value, and not the system clock, as is being done + // here. + + sprintf(Buffer, "%04X", (unsigned int) i); + NWFSCopy(&MangledName[BaseLength], Buffer, 4); + + if (ExtensionLength) + { + MangledName[BaseLength + 6] = '.'; + NWFSCopy(&MangledName[BaseLength + 7], FileExtension, ExtensionLength); + } + *MangledNameLength = (BYTE)(BaseLength + ExtensionLength + 6 + (ExtensionLength > 0)); + + hash = GetHashFromName(volume, MangledName, *MangledNameLength, + DOS_NAME_SPACE, Parent); + +#if (VERBOSE) + NWFSPrint("(3) BaseLength-%d ExtensionLength-%d [%12s]-%d hash-%X\n", + (int)BaseLength, (int)ExtensionLength, MangledName, + (int)*MangledNameLength, + (unsigned int)hash); +#endif + + if (!hash) + break; + + i -= 11; + } + return 0; +} + +ULONG NWMangleDOSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + DOS *dos, ULONG Parent) +{ + register ULONG i, retCode; + BYTE DOSName[256]; + BYTE OutputName[256]; + BYTE OutputLength = 0; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // create case insensitive string + for (i=0; i < NameLength; i++) + DOSName[i] = DOSUpperCaseTable[(BYTE)Name[i]]; + + // if we are passed a valid dos name that's also unique, return ok + if (NameLength <= MAX_DOS_NAME) + { + retCode = NWValidDOSName(volume, DOSName, NameLength, Parent, 1); + if (!retCode) + { + if (NameLength > MAX_DOS_NAME) + return NwBadName; + + dos->FileNameLength = (BYTE) NameLength; + NWFSCopy(dos->FileName, DOSName, NameLength); + + return retCode; + } + + if (volume->NameSpaceDefault == DOS_NAME_SPACE) + { + if (retCode == NwFileExists) + return retCode; + } + } + + retCode = NWCreateUniqueName(volume, Parent, DOSName, NameLength, + OutputName, &OutputLength, 0); + if (retCode) + return retCode; + + if (OutputLength > MAX_DOS_NAME) + return NwBadName; + + dos->FileNameLength = (BYTE) OutputLength; + NWFSCopy(dos->FileName, OutputName, OutputLength); + + return 0; + +} + +ULONG NWMangleMACName(VOLUME *volume, BYTE *Name, ULONG NameLength, + MACINTOSH *mac, ULONG Parent) +{ + register ULONG i, Length, retCode; + register HASH *hash; + BYTE CName[MAX_MAC_NAME]; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // save local copy just in case our name source and target + // are the same. + for (i=0; i < NameLength && i < MAX_MAC_NAME; i++) + CName[i] = Name[i]; + + for (Length=i=0; (i < NameLength) && (i < MAX_MAC_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(MACValidCharBitmap, CName[i]); + if (retCode) + mac->FileName[Length++] = DOSToMACConvertTable[(BYTE)CName[i]]; + } + mac->FileNameLength = (BYTE) Length; + + // see if the name exists in the specified namespace + hash = GetHashFromName(volume, mac->FileName, mac->FileNameLength, + MAC_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + + return 0; +} + +ULONG NWMangleNFSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + NFS *nfs, ULONG Parent) +{ + register ULONG i, Length, retCode; + register HASH *hash; + BYTE CName[MAX_NFS_NAME]; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // save local copy just in case our name source and target + // are the same. + for (i=0; i < NameLength && i < MAX_NFS_NAME; i++) + CName[i] = Name[i]; + + for (Length=i=0; (i < NameLength) && (i < MAX_NFS_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(NFSValidCharBitmap, CName[i]); + if (retCode) + nfs->FileName[Length++] = CName[i]; + } + nfs->FileNameLength = (BYTE) Length; + nfs->TotalFileNameLength = (BYTE) Length; + + // see if the name exists in the specified namespace + hash = GetHashFromName(volume, nfs->FileName, nfs->TotalFileNameLength, + UNIX_NAME_SPACE, Parent); + if (hash) + { + // try a lowercase variant if the first name already exists + for (Length=i=0; (i < NameLength) && (i < MAX_NFS_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(NFSValidCharBitmap, CName[i]); + if (retCode) + nfs->FileName[Length++] = DOSLowerCaseTable[(BYTE)CName[i]]; + } + nfs->FileNameLength = (BYTE) Length; + nfs->TotalFileNameLength = (BYTE) Length; + + // see if the name exists in the specified namespace + hash = GetHashFromName(volume, nfs->FileName, nfs->TotalFileNameLength, + UNIX_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + } + return 0; +} + +ULONG NWMangleLONGName(VOLUME *volume, BYTE *Name, ULONG NameLength, + LONGNAME *longname, ULONG Parent) +{ + register ULONG i, Length, retCode; + register HASH *hash; + BYTE CName[MAX_LONG_NAME]; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // save local copy just in case our name source and target + // are the same. + for (i=0; i < NameLength && i < MAX_LONG_NAME; i++) + CName[i] = Name[i]; + + for (Length=i=0; (i < NameLength) && (i < MAX_LONG_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(LONGValidCharBitmap, CName[i]); + if (retCode) + longname->FileName[Length++] = CName[i]; + } + longname->FileNameLength = (BYTE) Length; + longname->LengthData = (BYTE) Length; + + // see if the name exists in the specified namespace + + hash = GetHashFromName(volume, longname->FileName, + longname->FileNameLength, + LONG_NAME_SPACE, Parent); + if (hash) + { + return NwFileExists; + } + + return 0; +} + +ULONG NWCreateMACName(VOLUME *volume, BYTE *Name, ULONG NameLength, + MACINTOSH *mac, ULONG Parent) +{ + register ULONG i, Length, retCode; + BYTE CName[MAX_MAC_NAME]; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // save local copy just in case our name source and target + // are the same. + for (i=0; i < NameLength && i < MAX_MAC_NAME; i++) + CName[i] = Name[i]; + + for (Length=i=0; (i < NameLength) && (i < MAX_MAC_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(MACValidCharBitmap, CName[i]); + if (retCode) + mac->FileName[Length++] = DOSToMACConvertTable[(BYTE)CName[i]]; + } + mac->FileNameLength = (BYTE) Length; + + return 0; +} + +ULONG NWCreateNFSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + NFS *nfs, ULONG Parent) +{ + register ULONG i, Length, retCode; + BYTE CName[MAX_NFS_NAME]; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // save local copy just in case our name source and target + // are the same. + for (i=0; i < NameLength && i < MAX_NFS_NAME; i++) + CName[i] = Name[i]; + + for (Length=i=0; (i < NameLength) && (i < MAX_NFS_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(NFSValidCharBitmap, CName[i]); + if (retCode) + { + if ((volume->NameSpaceDefault == UNIX_NAME_SPACE) || + (volume->NameSpaceDefault == LONG_NAME_SPACE)) + nfs->FileName[Length++] = CName[i]; + else + nfs->FileName[Length++] = DOSLowerCaseTable[(BYTE)CName[i]]; + } + } + nfs->FileNameLength = (BYTE) Length; + nfs->TotalFileNameLength = (BYTE) Length; + + return 0; +} + +ULONG NWCreateLONGName(VOLUME *volume, BYTE *Name, ULONG NameLength, + LONGNAME *longname, ULONG Parent) +{ + register ULONG i, Length, retCode; + BYTE CName[MAX_LONG_NAME]; + + if (NameLength > 255) + return NwBadName; + + if (!NameLength) + return NwBadName; + + // a trailing space is not allowed + if (NameLength && (Name[NameLength - 1] == ' ')) + return NwBadName; + + // save local copy just in case our name source and target + // are the same. + for (i=0; i < NameLength && i < MAX_LONG_NAME; i++) + CName[i] = Name[i]; + + for (Length=i=0; (i < NameLength) && (i < MAX_LONG_NAME); i++) + { + // copy the character into file name + retCode = TestCharacter(LONGValidCharBitmap, CName[i]); + if (retCode) + longname->FileName[Length++] = CName[i]; + } + longname->FileNameLength = (BYTE) Length; + longname->LengthData = (BYTE) Length; + + return 0; +} + +ULONG FreeHashRecords(VOLUME *volume, HASH **Entries, ULONG Count) +{ + register ULONG i, retCode = 0; + + // free hash entries up to count + for (i=0; i < Count; i++) + { + retCode = FreeHashDirectoryRecord(volume, Entries[i]); + // if we fail try to free the remaining records and report the error + if (retCode) + NWFSPrint("nwfs: could not release hash record in create\n"); + } + return retCode; +} + +ULONG FreeDirectoryRecords(VOLUME *volume, ULONG *Entries, ULONG Parent, + ULONG Count) +{ + register ULONG i, retCode = 0; + DOS dosst; + register DOS *dos = &dosst; + + // free directory entries up to count + for (i=0; i < Count; i++) + { + retCode = FreeDirectoryRecord(volume, dos, Entries[i], Parent); + // if we fail try to free the remaining records and report the error + if (retCode) + NWFSPrint("nwfs: could not release dir record in free\n"); + } + return retCode; +} + +ULONG CreateDirectoryRecords(VOLUME *volume, ULONG *Entries, ULONG Parent, + ULONG *NumRec) +{ + register ULONG i, retCode; + + // allocate directory entries for total namespaces + for (i=0; i < volume->NameSpaceCount; i++) + { + Entries[i] = AllocateDirectoryRecord(volume, Parent); + if (Entries[i] == (ULONG) -1) + { + retCode = FreeDirectoryRecords(volume, Entries, Parent, i); + if (retCode) + { + NWFSPrint("nwfs: could not release dir record in create\n"); + return retCode; + } + return NwInsufficientResources; + } + // count the total records created + if (NumRec) + (*NumRec)++; + } + return 0; +} + +ULONG NWCreateDirectoryEntry(VOLUME *volume, BYTE *Name, ULONG Len, + ULONG Attributes, ULONG Parent, ULONG Flag, + ULONG Uid, ULONG Gid, ULONG RDev, ULONG Mode, + ULONG *retDirNo, ULONG DataStream, + ULONG DataStreamSize, ULONG DataFork, + ULONG DataForkSize, const char *SymbolicPath, + ULONG SymbolicPathLength) +{ + register ULONG RootDirNo, retCode, retries; + register BYTE *Buffer; + register DOS *dos; + register SUB_DIRECTORY *subdir; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + register ULONG i, NWFlags = 0; + register ULONG HashNumber = 0, RootNS = (ULONG) -1; + register VOLUME_WORKSPACE *wk; + + ULONG RecordNumber = 0; + DOS *WorkSpace[MAX_NAMESPACES]; + HASH *HashEntries[MAX_NAMESPACES]; + ULONG Entries[MAX_NAMESPACES]; + + // depending on which flag value was passed into this function, + // OR in the correct designator for the file type. NetWare already + // supports most types of files, so support for Unix style gid/uid + // designators as well as device handles are already supported. + + switch (Flag) + { + case NW_SUBDIRECTORY_FILE: + // we are not permitted to hard link to directories + if (Flag & NW_HARD_LINKED_FILE) + return NwNotPermitted; + NWFlags |= SUBDIRECTORY_FILE; + break; + + case NW_SYMBOLIC_FILE: + // we can only create unix special files if the nfs namespace is present + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + return NwNotPermitted; + + if (!SymbolicPathLength || !SymbolicPath) + return NwInvalidParameter; + + NWFlags |= SYMBOLIC_LINKED_FILE; + break; + + case NW_HARD_LINKED_FILE: + // we can only create unix special files if the nfs namespace is present + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + return NwNotPermitted; + NWFlags |= HARD_LINKED_FILE; + break; + + case NW_NAMED_FILE: + NWFlags |= NAMED_FILE; + break; + + case NW_DEVICE_FILE: + // we can only create unix special files if the nfs namespace is present + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + return NwNotPermitted; + NWFlags |= NAMED_FILE; + break; + + default: + return NwInvalidParameter; + + } + + // see if name conforms to default namespace conventions + switch (volume->NameSpaceDefault) + { + case DOS_NAME_SPACE: + case MAC_NAME_SPACE: + break; + + case UNIX_NAME_SPACE: + retCode = NWValidNFSName(volume, Name, Len, Parent, 1); + if (retCode) + return retCode; + break; + + case LONG_NAME_SPACE: + case NT_NAME_SPACE: + retCode = NWValidLONGName(volume, Name, Len, Parent, 1); + if (retCode) + return retCode; + break; + + // if we get here, then return error + default: + return NwBadName; + + } + + // get enough memory for directory workspace + + wk = AllocateNSWorkspace(volume); + if (!wk) + { + NWFSPrint("nwfs: alloc failed in NWCreate\n"); + return NwInsufficientResources; + } + Buffer = (BYTE *)&wk->Buffer[0]; + + // initialize directory workspace array + NWFSSet(Buffer, 0, sizeof(ROOT) * volume->NameSpaceCount); + for (i=0; i < volume->NameSpaceCount; i++) + WorkSpace[i] = (DOS *) &Buffer[i * sizeof(ROOT)]; + + // we create all of the name space directory entries in memory prior to + // attemping to write them to disk or add them to in-memory hash. + + for (i=0; i < volume->NameSpaceCount; i++) + { + switch (volume->NameSpaceID[i]) + { + case DOS_NAME_SPACE: + if (NWFlags & SUBDIRECTORY_FILE) + { + subdir = (SUB_DIRECTORY *) WorkSpace[i]; + retCode = NWMangleDOSName(volume, Name, Len, (DOS *)subdir, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + + subdir->Flags |= SUBDIRECTORY_FILE; + subdir->FileAttributes |= (SUBDIRECTORY | Attributes); + + if (volume->NameSpaceDefault == DOS_NAME_SPACE) + subdir->Flags |= PRIMARY_NAMESPACE; + subdir->Subdirectory = Parent; + subdir->NameSpace = DOS_NAME_SPACE; + subdir->CreateDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + subdir->OwnerID = SUPERVISOR; + subdir->LastModifiedDateAndTime = subdir->CreateDateAndTime; + subdir->PrimaryEntry = 0; + subdir->NameList = 0; + + // if we create a new subdirectory, then make certain + // we have enough free directory space to assign a + // free block to this directory. + + retCode = PreAllocateFreeDirectoryRecords(volume); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + } + else + { + dos = (DOS *) WorkSpace[i]; + retCode = NWMangleDOSName(volume, Name, Len, dos, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + + dos->FileAttributes |= Attributes; + dos->Flags |= (NAMED_FILE | NWFlags); + if (volume->NameSpaceDefault == DOS_NAME_SPACE) + dos->Flags |= PRIMARY_NAMESPACE; + dos->Subdirectory = Parent; + dos->NameSpace = DOS_NAME_SPACE; + dos->CreateDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + dos->OwnerID = SUPERVISOR; + dos->LastUpdatedDateAndTime = dos->CreateDateAndTime; + dos->PrimaryEntry = 0; + dos->NameList = 0; + dos->LastUpdatedID = SUPERVISOR; + dos->FileSize = DataStreamSize; + dos->FirstBlock = DataStream; + } + + // record the root namespace index + RootNS = i; + + break; + + case MAC_NAME_SPACE: + mac = (MACINTOSH *) WorkSpace[i]; + retCode = NWMangleMACName(volume, Name, Len, mac, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + if (NWFlags & SUBDIRECTORY_FILE) + mac->Flags |= SUBDIRECTORY_FILE; + else + mac->Flags |= (NWFlags | NAMED_FILE); + if (volume->NameSpaceDefault == MAC_NAME_SPACE) + mac->Flags |= PRIMARY_NAMESPACE; + mac->NameSpace = MAC_NAME_SPACE; + mac->Subdirectory = Parent; + mac->NameList = 0; + mac->PrimaryEntry = 0; + mac->ResourceForkSize = DataForkSize; + mac->ResourceFork = DataFork; + break; + + case UNIX_NAME_SPACE: + nfs = (NFS *) WorkSpace[i]; + retCode = NWMangleNFSName(volume, Name, Len, nfs, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + if (NWFlags & SUBDIRECTORY_FILE) + { + nfs->nlinks = 2; + nfs->Flags |= SUBDIRECTORY_FILE; + } + else + { + nfs->nlinks = 1; + nfs->Flags |= (NWFlags | NAMED_FILE); + } + if (volume->NameSpaceDefault == UNIX_NAME_SPACE) + nfs->Flags |= PRIMARY_NAMESPACE; + + if (NWFlags & SYMBOLIC_LINKED_FILE) + nfs->LinkedFlag = NFS_SYMBOLIC_LINK; + else + nfs->LinkedFlag = 0; + + nfs->NameSpace = UNIX_NAME_SPACE; + nfs->Subdirectory = Parent; + nfs->FileNameLength = (nfs->TotalFileNameLength <= MAX_NFS_NAME) + ? nfs->TotalFileNameLength : MAX_NFS_NAME; + nfs->gid = Gid; + nfs->uid = Uid; + nfs->mode = Mode; + nfs->rdev = RDev; + nfs->NameList = 0; + nfs->PrimaryEntry = 0; + break; + + case LONG_NAME_SPACE: + longname = (LONGNAME *) WorkSpace[i]; + retCode = NWMangleLONGName(volume, Name, Len, longname, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + if (NWFlags & SUBDIRECTORY_FILE) + longname->Flags |= SUBDIRECTORY_FILE; + else + longname->Flags |= (NWFlags | NAMED_FILE); + if (volume->NameSpaceDefault == LONG_NAME_SPACE) + longname->Flags |= PRIMARY_NAMESPACE; + longname->NameSpace = LONG_NAME_SPACE; + longname->Subdirectory = Parent; + longname->NameList = 0; + longname->PrimaryEntry = 0; + break; + + case NT_NAME_SPACE: + nt = (NTNAME *) WorkSpace[i]; + retCode = NWMangleLONGName(volume, Name, Len, (LONGNAME *)nt, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + if (NWFlags & SUBDIRECTORY_FILE) + nt->Flags |= SUBDIRECTORY_FILE; + else + nt->Flags |= (NWFlags | NAMED_FILE); + if (volume->NameSpaceDefault == NT_NAME_SPACE) + nt->Flags |= PRIMARY_NAMESPACE; + nt->NameSpace = NT_NAME_SPACE; + nt->Subdirectory = Parent; + nt->NameList = 0; + nt->PrimaryEntry = 0; + break; + + default: + // this case is a fatal error. we should never have + // an allocated record without a valid namespace + // to match up with it. + + FreeNSWorkspace(volume, wk); + return NwVolumeCorrupt; + } + } + + if (RootNS == (ULONG) -1) + { + NWFSPrint("nwfs: could not determine root namespace NWCreate\n"); + FreeNSWorkspace(volume, wk); + return NwDirectoryCorrupt; + } + + // allocate directory records necessary to create the file or directory + retCode = CreateDirectoryRecords(volume, Entries, Parent, &RecordNumber); + if (retCode) + { +#if (VERBOSE) + NWFSPrint("nwfs: dir entry alloc failed in NWCreate\n"); +#endif + FreeNSWorkspace(volume, wk); + return NwVolumeFull; + } + + // verify that the number of allocated directory records is equal + // to the number of namespaces for the volume. if not, return error. + if (RecordNumber != volume->NameSpaceCount) + { + NWFSPrint("nwfs: allocated dir records != namespaces in NWCreate\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWCreate\n"); + + FreeNSWorkspace(volume, wk); + return NwVolumeCorrupt; + } + + // link allocated directory records together into a single namespace + // chain + for (RootDirNo = Entries[RootNS], i=0; + RecordNumber && (i < (RecordNumber - 1)); i++) + { + // store the DirNo for next record into NameList + dos = (DOS *) WorkSpace[i]; + dos->NameList = Entries[i + 1]; + dos->PrimaryEntry = RootDirNo; + } + // null terminate last dir namespace record + dos = (DOS *) WorkSpace[i]; + dos->NameList = 0; + dos->PrimaryEntry = RootDirNo; + + // write and hash the initialized directory records + for (i=0; i < RecordNumber; i++) + { + HashEntries[i] = AllocHashDirectoryRecord(volume, + (DOS *)WorkSpace[i], + Entries[i]); + if (!HashEntries[i]) + { + retCode = FreeHashRecords(volume, HashEntries, HashNumber); + if (retCode) + NWFSPrint("nwfs: could not release hash record in NWCreate)\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWCreate\n"); + + FreeNSWorkspace(volume, wk); + return NwInsufficientResources; + } + // count the number of name hash elements we create + + HashNumber++; + + retCode = WriteDirectoryRecord(volume, + (DOS *)WorkSpace[i], + Entries[i]); + if (retCode) + { + retCode = FreeHashRecords(volume, HashEntries, HashNumber); + if (retCode) + NWFSPrint("nwfs: could not release hash record in NWCreate)\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWCreate\n"); + + FreeNSWorkspace(volume, wk); + return NwDiskIoError; + } + } + + if (NWFlags & SYMBOLIC_LINKED_FILE) + { + register ULONG bytesWritten; + ULONG writeRetCode; + + NWLockFileExclusive(HashEntries[0]); + + bytesWritten = NWWriteFile(volume, + &WorkSpace[RootNS]->FirstBlock, + WorkSpace[RootNS]->Flags, + 0, (BYTE *)SymbolicPath, SymbolicPathLength, + 0, 0, &writeRetCode, KERNEL_ADDRESS_SPACE, + (volume->VolumeFlags & SUB_ALLOCATION_ON) ? 1 : 0, + WorkSpace[RootNS]->FileAttributes); + + if (bytesWritten != SymbolicPathLength) + { + NWUnlockFile(HashEntries[0]); + + retCode = FreeHashRecords(volume, HashEntries, HashNumber); + if (retCode) + NWFSPrint("nwfs: could not release hash record in NWCreate)\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWCreate\n"); + + FreeNSWorkspace(volume, wk); + return writeRetCode; + } + + // update NetWare directory entry with modified date and time + WorkSpace[RootNS]->FileSize = bytesWritten; + WorkSpace[RootNS]->LastUpdatedDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + + // force suballocation of this symbolic link file + TruncateClusterChain(volume, + &WorkSpace[RootNS]->FirstBlock, + 0, + 0, + WorkSpace[RootNS]->FileSize, + TRUE, + WorkSpace[RootNS]->FileAttributes); + +#if (HASH_FAT_CHAINS) + // update the hash first block and file size fields + HashEntries[0]->FirstBlock = WorkSpace[RootNS]->FirstBlock, + HashEntries[0]->FileSize = WorkSpace[RootNS]->FileSize; + HashEntries[0]->FileAttributes = WorkSpace[RootNS]->FileAttributes; +#endif + + NWUnlockFile(HashEntries[0]); + + // write the dos record to the directory file. + writeRetCode = WriteDirectoryRecord(volume, WorkSpace[RootNS], Entries[RootNS]); + if (writeRetCode) + { + retCode = FreeHashRecords(volume, HashEntries, HashNumber); + if (retCode) + NWFSPrint("nwfs: could not release hash record in NWCreate)\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWCreate\n"); + + FreeNSWorkspace(volume, wk); + return writeRetCode; + } + } + + // free the workspace + FreeNSWorkspace(volume, wk); + + // if the count of empty subdirectories on this volume is greater + // than the current free directory blocks, then preallocate + // free space in the directory file until the count of empty + // directories is greater than or equal to the number of + // free directory blocks in the directory file. Netware treats + // this as a fatal error if any empty subdirectories exist for + // which there is no corresponding free directory block. We + // don't treat this as a fatal error, and will attempt to + // pre-allocate free records until a reasonable limit + // is reached. + + if (volume->FreeDirectoryBlockCount < volume->FreeDirectoryCount) + { + retries = 0; + while (volume->FreeDirectoryBlockCount < volume->FreeDirectoryCount) + { + retCode = PreAllocateEmptyDirectorySpace(volume); + if (retCode) + break; + + if (retries++ > 5) // if we get stuck in a loop here, then exit + { + NWFSPrint("nwfs: exceeded maximum pre-allocated records (create)\n"); + break; + } + } + } + + if (retDirNo) + *retDirNo = RootDirNo; + + return 0; + +} + +// this function only removes the directory entries for a particular +// file or directory. data streams are not removed. + +ULONG NWDeleteDirectoryEntry(VOLUME *volume, DOS *dos, HASH *hash) +{ + register ULONG retCode, Parent, DirNo, TrusteeDirNo; + register HASH *searchHash, *listHash; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + register TRUSTEE *trustee; + register SUB_DIRECTORY *subdir; + + // the DOS namespace must always be the first record on the name list + if (hash->NameSpace != DOS_NAME_SPACE) + return NwHashCorrupt; + + Parent = hash->Parent; + listHash = hash; + while (listHash) + { + searchHash = listHash; + listHash = listHash->nlnext; + + switch (searchHash->NameSpace) + { + case DOS_NAME_SPACE: + if (searchHash->Flags & SUBDIRECTORY_FILE) + { + // check if directory still has files in it + if (searchHash->Blocks) + { + // don't delete directories unless they are empty + return NwNotEmpty; + } + } + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + if (searchHash->Flags & SUBDIRECTORY_FILE) + { + // free any trustee records for this entry + subdir = (SUB_DIRECTORY *) dos; + TrusteeDirNo = subdir->NextTrusteeEntry; + while (TrusteeDirNo) + { + retCode = ReadDirectoryRecord(volume, dos, TrusteeDirNo); + if (retCode) + { + NWFSPrint("nwfs: error reading trustee record\n"); + return retCode; + } + + trustee = (TRUSTEE *) dos; + TrusteeDirNo = trustee->NextTrusteeEntry; + + retCode = FreeDirectoryRecord(volume, dos, TrusteeDirNo, + Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing trustee record\n"); + return retCode; + } + } + } + else + { + // free any trustee records for this entry + TrusteeDirNo = dos->NextTrusteeEntry; + while (TrusteeDirNo) + { + retCode = ReadDirectoryRecord(volume, dos, TrusteeDirNo); + if (retCode) + { + NWFSPrint("nwfs: error reading trustee record\n"); + return retCode; + } + + trustee = (TRUSTEE *) dos; + TrusteeDirNo = trustee->NextTrusteeEntry; + + retCode = FreeDirectoryRecord(volume, dos, TrusteeDirNo, + Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing trustee record\n"); + return retCode; + } + } + } + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case MAC_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + mac = (MACINTOSH *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case UNIX_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + nfs = (NFS *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case LONG_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + longname = (LONGNAME *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case NT_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + nt = (NTNAME *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + default: + NWFSPrint("nwfs: unknown directory record format\n"); + break; + } + } + return 0; +} + +ULONG NWDeleteHashChain(VOLUME *volume, HASH *hash) +{ + register HASH *searchHash, *listHash; + + // the DOS namespace must always be the first record on the name list + if (hash->NameSpace != DOS_NAME_SPACE) + return NwHashCorrupt; + + listHash = hash; + while (listHash) + { + searchHash = listHash; + listHash = listHash->nlnext; + FreeHashDirectoryRecord(volume, searchHash); + } + return 0; +} + +// this function removes the directory entries and all datastreams +// associated with these directory entries. + +ULONG NWDeleteDirectoryEntryAndData(VOLUME *volume, DOS *dos, HASH *hash) +{ + register ULONG retCode, Parent, DirNo, TrusteeDirNo, Attributes = 0; + register HASH *searchHash, *listHash; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + register TRUSTEE *trustee; + register SUB_DIRECTORY * subdir; + + // the DOS namespace must always be the first record on the name list + if (hash->NameSpace != DOS_NAME_SPACE) + return NwHashCorrupt; + + Parent = hash->Parent; + listHash = hash; + while (listHash) + { + searchHash = listHash; + listHash = listHash->nlnext; + + switch (searchHash->NameSpace) + { + case DOS_NAME_SPACE: + Attributes = dos->FileAttributes; + if (searchHash->Flags & SUBDIRECTORY_FILE) + { + // check if directory still has files in it + if (searchHash->Blocks) + { + // don't delete directories unless they are empty + return NwNotEmpty; + } + } + else + { + // free the primary data stream for this file + if (dos->FirstBlock && (dos->FirstBlock != (ULONG) -1)) + { + retCode = TruncateClusterChain(volume, + &dos->FirstBlock, + 0, + 0, + 0, + (volume->VolumeFlags & SUB_ALLOCATION_ON) + ? 1 : 0, Attributes); + if (retCode) + { + NWFSPrint("nwfs: error in truncate cluster chain\n"); + return retCode; + } + } + dos->FileSize = 0; + } + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + if (searchHash->Flags & SUBDIRECTORY_FILE) + { + // free any trustee records for this entry + subdir = (SUB_DIRECTORY *) dos; + TrusteeDirNo = subdir->NextTrusteeEntry; + while (TrusteeDirNo) + { + retCode = ReadDirectoryRecord(volume, dos, TrusteeDirNo); + if (retCode) + { + NWFSPrint("nwfs: error reading trustee record\n"); + return retCode; + } + + trustee = (TRUSTEE *) dos; + TrusteeDirNo = trustee->NextTrusteeEntry; + + retCode = FreeDirectoryRecord(volume, dos, TrusteeDirNo, + Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing trustee record\n"); + return retCode; + } + } + } + else + { + // free any trustee records for this entry + TrusteeDirNo = dos->NextTrusteeEntry; + while (TrusteeDirNo) + { + retCode = ReadDirectoryRecord(volume, dos, TrusteeDirNo); + if (retCode) + { + NWFSPrint("nwfs: error reading trustee record\n"); + return retCode; + } + + trustee = (TRUSTEE *) dos; + TrusteeDirNo = trustee->NextTrusteeEntry; + + retCode = FreeDirectoryRecord(volume, dos, TrusteeDirNo, + Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing trustee record\n"); + return retCode; + } + } + } + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case MAC_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + + mac = (MACINTOSH *) dos; + // free the mac resource fat chain for this file + + if (mac->ResourceFork && (mac->ResourceFork != (ULONG) -1)) + { + retCode = TruncateClusterChain(volume, &mac->ResourceFork, 0, 0, + 0, (volume->VolumeFlags & SUB_ALLOCATION_ON) + ? 1 : 0, Attributes); + if (retCode) + { + NWFSPrint("nwfs: error in truncate cluster chain\n"); + return retCode; + } + } + mac->ResourceForkSize = 0; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case UNIX_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + nfs = (NFS *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case LONG_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + longname = (LONGNAME *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + case NT_NAME_SPACE: + retCode = ReadDirectoryRecord(volume, dos, searchHash->DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory read\n"); + return retCode; + } + nt = (NTNAME *) dos; + + // save the directory number for this hash + DirNo = searchHash->DirNo; + + // free the hash first so its instance handle gets + // invalidated before clearing the directory entry. + FreeHashDirectoryRecord(volume, searchHash); + + // now clear the directory record and mark it free in + // the dir block free lists + retCode = FreeDirectoryRecord(volume, dos, DirNo, Parent); + if (retCode) + { + NWFSPrint("nwfs: error freeing directory record\n"); + return retCode; + } + break; + + default: + NWFSPrint("nwfs: unknown directory record format\n"); + break; + } + } + return 0; + +} + +ULONG NWShadowDirectoryEntry(VOLUME *volume, DOS *dos, HASH *hash) +{ + return 0; +} + +// we create an entirely new file entry during renames, even if +// we are not moving a file to another directory. We do it this +// way so that in the event we get interrupted during the operation +// we will not lose the file. + +ULONG NWRenameEntry(VOLUME *volume, DOS *oldDir, HASH *hash, + BYTE *Name, ULONG Len, ULONG Parent) +{ + register ULONG retCode, i, RootNS = (ULONG) -1, oldDirNo; + register ULONG DirCount, RootDirNo, HashNumber = 0; + register HASH *searchHash, *listHash; + register DOS *dos; + register SUB_DIRECTORY *subdir; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + register BYTE *Buffer; + register VOLUME_WORKSPACE *wk; + + ULONG RecordNumber = 0; + DOS *WorkSpace[MAX_NAMESPACES]; + HASH *HashEntries[MAX_NAMESPACES]; + ULONG Entries[MAX_NAMESPACES]; + ULONG PrevDirEntries[MAX_NAMESPACES]; + + // the DOS namespace must always be the first record on the name list + if (hash->NameSpace != DOS_NAME_SPACE) + return NwHashCorrupt; + + oldDirNo = hash->DirNo; + + // if we are moving a subdirectory with files, then report error. + // if the directory is empty, or we are renaming it, then allow + // the operation. + + if ((hash->Flags & SUBDIRECTORY_FILE) && (hash->Parent != Parent)) + { + // check if directory still has files in it + if (hash->Blocks) + { + // don't move directories unless they are empty + return NwNotEmpty; + } + } + + // see if name conforms to default namespace conventions + switch (volume->NameSpaceDefault) + { + case DOS_NAME_SPACE: + retCode = NWValidDOSName(volume, Name, Len, Parent, 1); + if (retCode) + return retCode; + break; + + case MAC_NAME_SPACE: + retCode = NWValidMACName(volume, Name, Len, Parent, 1); + if (retCode) + return retCode; + break; + + case UNIX_NAME_SPACE: + retCode = NWValidNFSName(volume, Name, Len, Parent, 1); + if (retCode) + return retCode; + break; + + case LONG_NAME_SPACE: + case NT_NAME_SPACE: + retCode = NWValidLONGName(volume, Name, Len, Parent, 1); + if (retCode) + return retCode; + break; + + // if we get here, then return error + default: + return NwBadName; + + } + + // get enough memory for directory workspace + wk = AllocateNSWorkspace(volume); + if (!wk) + { + NWFSPrint("nwfs: alloc failed in NWRename\n"); + return NwInsufficientResources; + } + Buffer = (BYTE *)&wk->Buffer[0]; + + // initialize directory workspace array + NWFSSet(Buffer, 0, sizeof(ROOT) * volume->NameSpaceCount); + for (i=0; i < volume->NameSpaceCount; i++) + WorkSpace[i] = (DOS *) &Buffer[i * sizeof(ROOT)]; + + // read the current directory entries into the workspace. + DirCount = 0; + listHash = hash; + while (listHash) + { + searchHash = listHash; + listHash = listHash->nlnext; + + PrevDirEntries[DirCount] = searchHash->DirNo; + retCode = ReadDirectoryRecord(volume, WorkSpace[DirCount], + searchHash->DirNo); + if (retCode) + return retCode; + + DirCount++; + } + + for (i=0; i < DirCount; i++) + { + dos = (DOS *) WorkSpace[i]; + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: + if (dos->Flags & SUBDIRECTORY_FILE) + { + subdir = (SUB_DIRECTORY *) dos; + retCode = NWMangleDOSName(volume, Name, Len, (DOS *)subdir, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + subdir->Subdirectory = Parent; + if (Parent == (ULONG) -2) // going to a deleted block + { + } + subdir->CreateDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + subdir->OwnerID = SUPERVISOR; + subdir->LastModifiedDateAndTime = subdir->CreateDateAndTime; + } + else + { + retCode = NWMangleDOSName(volume, Name, Len, dos, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + dos->Subdirectory = Parent; + if (Parent == (ULONG) -2) // going to a deleted block + { + } + dos->CreateDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + dos->LastUpdatedDateAndTime = dos->CreateDateAndTime; + dos->LastUpdatedID = SUPERVISOR; + } + // record the root namespace index + RootNS = i; + break; + + case MAC_NAME_SPACE: + mac = (MACINTOSH *) dos; + retCode = NWMangleMACName(volume, Name, Len, mac, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + mac->Subdirectory = Parent; + break; + + case UNIX_NAME_SPACE: + nfs = (NFS *) dos; + retCode = NWMangleNFSName(volume, Name, Len, nfs, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + nfs->Subdirectory = Parent; + nfs->FileNameLength = (nfs->TotalFileNameLength <= MAX_NFS_NAME) + ? nfs->TotalFileNameLength : MAX_NFS_NAME; + break; + + case LONG_NAME_SPACE: + longname = (LONGNAME *) dos; + retCode = NWMangleLONGName(volume, Name, Len, longname, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + longname->Subdirectory = Parent; + break; + + case NT_NAME_SPACE: + nt = (NTNAME *) dos; + retCode = NWMangleLONGName(volume, Name, Len, (LONGNAME *)nt, Parent); + if (retCode) + { + FreeNSWorkspace(volume, wk); + return retCode; + } + nt->Subdirectory = Parent; + break; + + default: + // this case is a fatal error. we should never have + // an allocated record without a valid namespace + // to match up with it. + + FreeNSWorkspace(volume, wk); + return NwVolumeCorrupt; + } + } + + // now we check if we are renaming a directory rather than moving + // one. We allow it in this implementation so long as they are empty. + // since Netware always maintains child links to parents, but no + // parent links to children, if you move a directory with files + // you will orphan all the files. The overhead involved in + // deleting and reassigning the children for a particular directory + // to the correctly assigned dir blocks is considerable to support + // this, and has a great deal of overhead (you must read and write + // each directory record and change it's parent link.) + + if ((hash->Flags & SUBDIRECTORY_FILE) && (hash->Parent == Parent)) + { + register HASH *searchHash; + BYTE *Name[MAX_NAMESPACES]; + ULONG Length[MAX_NAMESPACES]; + + // save the previous name links, and clear the name field + // we also remove the name from the name hashes + + for (searchHash = hash, i = 0; (searchHash) && (i < DirCount); i++) + { + RemoveNameHash(volume, searchHash); + Name[i] = searchHash->Name; + Length[i] = searchHash->NameLength; + searchHash->Name = 0; + searchHash->NameLength = 0; + searchHash = searchHash->nlnext; + } + + for (searchHash = hash, i = 0; (searchHash) && (i < DirCount); i++) + { + searchHash->Name = CreateNameField((DOS *)WorkSpace[i], searchHash); + if (!searchHash->Name) + { + for (searchHash = hash, i = 0; (searchHash) && (i < DirCount); i++) + { + if (searchHash->Name) + { + RemoveNameHash(volume, searchHash); + NWFSFree(searchHash->Name); + } + searchHash->Name = Name[i]; + searchHash->NameLength = (WORD) Length[i]; + AddToNameHash(volume, searchHash); + searchHash = searchHash->nlnext; + } + FreeNSWorkspace(volume, wk); + return NwInsufficientResources; + } + AddToNameHash(volume, searchHash); + searchHash = searchHash->nlnext; + } + + // write the modified directory records to disk + for (HashNumber = i = 0; i < DirCount; i++) + { + retCode = WriteDirectoryRecord(volume, + (DOS *)WorkSpace[i], + PrevDirEntries[i]); + if (retCode) + { + for (searchHash = hash, i = 0; (searchHash) && (i < DirCount); i++) + { + if (searchHash->Name) + { + RemoveNameHash(volume, searchHash); + NWFSFree(searchHash->Name); + } + searchHash->Name = Name[i]; + searchHash->NameLength = (WORD) Length[i]; + AddToNameHash(volume, searchHash); + searchHash = searchHash->nlnext; + } + FreeNSWorkspace(volume, wk); + return NwDiskIoError; + } + } + + // free the workspace + FreeNSWorkspace(volume, wk); + + // free the old hash name fields + for (i = 0; i < DirCount; i++) + { + if (Name[i]) + NWFSFree(Name[i]); + } + return 0; + } + + if (RootNS == (ULONG) -1) + { + NWFSPrint("nwfs: could not determine root namespace NWRename\n"); + FreeNSWorkspace(volume, wk); + return NwDirectoryCorrupt; + } + + // allocate directory records necessary to create the file or directory + retCode = CreateDirectoryRecords(volume, Entries, Parent, &RecordNumber); + if (retCode) + { + NWFSPrint("nwfs: dir entry alloc failed in NWRename\n"); + FreeNSWorkspace(volume, wk); + return NwInsufficientResources; + } + + // verify that the number of allocated directory records is equal + // to the number of namespaces for the volume. if not, return error. + if (RecordNumber != DirCount) + { + NWFSPrint("nwfs: allocated dir records != directory count in NWRename\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWRename\n"); + + FreeNSWorkspace(volume, wk); + return NwVolumeCorrupt; + } + + // link allocated directory records together into a single namespace + // chain + for (RootDirNo = Entries[RootNS], i=0; + RecordNumber && (i < (RecordNumber - 1)); i++) + { + // store the DirNo for next record into NameList + dos = (DOS *) WorkSpace[i]; + dos->NameList = Entries[i + 1]; + dos->PrimaryEntry = RootDirNo; + } + // null terminate last dir namespace record + dos = (DOS *) WorkSpace[i]; + dos->NameList = 0; + dos->PrimaryEntry = RootDirNo; + + // write and hash the initialized directory records + for (i=0; i < RecordNumber; i++) + { + HashEntries[i] = AllocHashDirectoryRecord(volume, + (DOS *)WorkSpace[i], + Entries[i]); + if (!HashEntries[i]) + { + retCode = FreeHashRecords(volume, HashEntries, HashNumber); + if (retCode) + NWFSPrint("nwfs: could not release hash record in NWRename)\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWRename\n"); + + FreeNSWorkspace(volume, wk); + return NwInsufficientResources; + } + // count the number of name hash elements we create + + HashNumber++; + + retCode = WriteDirectoryRecord(volume, + (DOS *)WorkSpace[i], + Entries[i]); + if (retCode) + { + retCode = FreeHashRecords(volume, HashEntries, HashNumber); + if (retCode) + NWFSPrint("nwfs: could not release hash record in NWRename)\n"); + + retCode = FreeDirectoryRecords(volume, Entries, Parent, RecordNumber); + if (retCode) + NWFSPrint("nwfs: could not release dir record in NWRename\n"); + + FreeNSWorkspace(volume, wk); + return NwDiskIoError; + } + } + + // free the workspace + FreeNSWorkspace(volume, wk); + + retCode = ReadDirectoryRecord(volume, oldDir, oldDirNo); + if (retCode) + return retCode; + + retCode = NWDeleteDirectoryEntry(volume, oldDir, hash); + + return retCode; + +} + +// +// +// + +ULONG UtilInitializeDirAssignHash(VOLUME *volume); +ULONG UtilCreateDirAssignEntry(VOLUME *volume, ULONG Parent, ULONG BlockNo, + DOS *dos); +ULONG UtilFreeDirAssignHash(VOLUME *volume); +ULONG UtilAddToDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock); +ULONG UtilRemoveDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock); +ULONG UtilAllocateDirectoryRecord(VOLUME *volume, ULONG Parent); +ULONG UtilFreeDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo, + ULONG Parent); + +ULONG UtilInitializeDirAssignHash(VOLUME *volume) +{ + volume->DirAssignBlocks = 0; + volume->DirAssignHash = NWFSCacheAlloc(ASSIGN_BLOCK_HASH_SIZE, + ASSN_BLOCKHASH_TAG); + + if (!volume->DirAssignHash) + return -1; + + volume->DirAssignHashLimit = NUMBER_OF_ASSIGN_BLOCK_ENTRIES; + NWFSSet(volume->DirAssignHash, 0, ASSIGN_BLOCK_HASH_SIZE); + + return 0; +} + +ULONG UtilCreateDirAssignEntry(VOLUME *volume, ULONG Parent, ULONG BlockNo, + DOS *dos) +{ + register ULONG DirsPerBlock; + register DIR_ASSIGN_HASH *hash; + register ULONG retCode, i; + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + + hash = NWFSAlloc(sizeof(DIR_ASSIGN_HASH) + + (DirsPerBlock / 8), ASSN_BLOCK_TAG); + if (hash) + { + NWFSSet(hash, 0, sizeof(DIR_ASSIGN_HASH) + (DirsPerBlock / 8)); + + hash->DirOwner = Parent; + hash->BlockNo = BlockNo; + + // create directory record free list for this block + + for (i=0; i < DirsPerBlock; i++) + { + if (dos[i].Subdirectory == (ULONG) -1) + hash->FreeList[i >> 3] &= ~(1 << (i & 7)); + else + hash->FreeList[i >> 3] |= (1 << (i & 7)); + } + + retCode = UtilAddToDirAssignHash(volume, hash); + if (retCode) + { + NWFSFree(hash); + return -1; + } + return 0; + } + return -1; + +} + +ULONG UtilFreeDirAssignHash(VOLUME *volume) +{ + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list, *hash; + register ULONG count; + + if (volume->DirAssignHash) + { + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + for (count=0; count < volume->DirAssignHashLimit; count++) + { + list = (DIR_ASSIGN_HASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].head = 0; + while (list) + { + hash = list; + list = list->next; + NWFSFree(hash); + } + } + } + + if (volume->DirAssignHash) + NWFSFree(volume->DirAssignHash); + volume->DirAssignHashLimit = 0; + volume->DirAssignHash = 0; + + return 0; + +} + +ULONG UtilAddToDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock) +{ + register ULONG hash; + register DIR_ASSIGN_HASH_LIST *HashTable; + + hash = (dblock->DirOwner & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (HashTable) + { + if (!HashTable[hash].head) + { + HashTable[hash].head = dblock; + HashTable[hash].tail = dblock; + dblock->next = dblock->prior = 0; + } + else + { + HashTable[hash].tail->next = dblock; + dblock->next = 0; + dblock->prior = HashTable[hash].tail; + HashTable[hash].tail = dblock; + } + return 0; + } + return -1; +} + +ULONG UtilRemoveDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock) +{ + register ULONG hash; + register DIR_ASSIGN_HASH_LIST *HashTable; + + hash = (dblock->DirOwner & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (HashTable) + { + if (HashTable[hash].head == dblock) + { + HashTable[hash].head = dblock->next; + if (HashTable[hash].head) + HashTable[hash].head->prior = NULL; + else + HashTable[hash].tail = NULL; + } + else + { + dblock->prior->next = dblock->next; + if (dblock != HashTable[hash].tail) + dblock->next->prior = dblock->prior; + else + HashTable[hash].tail = dblock->prior; + } + return 0; + } + return -1; +} + +ULONG UtilAllocateDirectoryRecord(VOLUME *volume, ULONG Parent) +{ + register ULONG hash, i, DirsPerBlock, DirNo, DirsPerCluster; + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list; + register VOLUME_WORKSPACE *WorkSpace; + register BYTE *cBuffer; + register ULONG cbytes, retCode, block, BlockNo; + register DOS *dos; + register ULONG dirFileSize, dirBlocks; + ULONG retRCode; + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + + hash = (Parent & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + return -1; + + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == Parent) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list, set it + // then return the allocated DirNo + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + list->FreeList[i >> 3] |= (1 << (i & 7)); + DirNo = ((DirsPerBlock * list->BlockNo) + i); + return DirNo; + } + } + } + list = list->next; + } + + // if we got here, then we could not locate an assigned directory + // block with available entries. at this point, we scan the free + // list hash (-1) and search free directory blocks for available + // entries. if we find a free block, then we assign this + // dir block as owned by the specified parent. + + hash = ((ULONG)FREE_NODE & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + return -1; + + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == FREE_NODE) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list, set it + // then return the allocated DirNo + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + // set directory entry as allocated + list->FreeList[i >> 3] |= (1 << (i & 7)); + + // re-hash block assign record to reflect + // new parent + UtilRemoveDirAssignHash(volume, list); + list->DirOwner = Parent; + UtilAddToDirAssignHash(volume, list); + + // calculate and return directory number + DirNo = ((DirsPerBlock * list->BlockNo) + i); + return DirNo; + } + } + } + list = list->next; + } + + // if we got here, then the directory is completely full, and we need + // to extend the directory by allocating another cluster for both the + // primary and mirror copies of the directory. + + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + return -1; + cBuffer = &WorkSpace->Buffer[0]; + + // initialize new cluster and fill with free directory + // entries + NWFSSet(cBuffer, 0, volume->ClusterSize); + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + for (i=0; i < DirsPerCluster; i++) + { + dos = (DOS *) &cBuffer[i * sizeof(ROOT)]; + dos->Subdirectory = FREE_NODE; + } + + // get directory file size + dirFileSize = GetChainSize(volume, volume->FirstDirectory); + dirBlocks = (dirFileSize + (volume->BlockSize - 1)) / volume->BlockSize; + + // write free cluster to the end of the primary directory chain + cbytes = NWWriteFile(volume, + &volume->FirstDirectory, + 0, + dirBlocks * volume->BlockSize, + cBuffer, + volume->ClusterSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->ClusterSize) + { + NWFSPrint("nwfs: error extending primary directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // write free cluster to the end of the mirror directory chain + cbytes = NWWriteFile(volume, + &volume->SecondDirectory, + 0, + dirBlocks * volume->BlockSize, + cBuffer, + volume->ClusterSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->ClusterSize) + { + NWFSPrint("nwfs: error extending mirror directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + BlockNo = dirBlocks; + for (block=0; block < volume->BlocksPerCluster; block++, BlockNo++) + { + dos = (DOS *) &cBuffer[block * volume->BlockSize]; + retCode = UtilCreateDirAssignEntry(volume, FREE_NODE, BlockNo, dos); + if (retCode) + { + NWFSPrint("nwfs: could not allocate dir block Assign element during extend\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + } + + // free the workspace + FreeWorkspace(volume, WorkSpace); + + // now try to scan the free list hash (-1) and search free + // directory blocks for available entries. if we find a free + // block (we'd better, we just created one above), then we mark + // this dir block as owned by the specified parent. we should + // never get here unless we successfully extended the directory file. + + hash = ((ULONG)FREE_NODE & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + return -1; + + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == FREE_NODE) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list, set it + // then return the allocated DirNo + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + // set directory entry as allocated + list->FreeList[i >> 3] |= (1 << (i & 7)); + + // re-hash block assign record to reflect + // new parent + UtilRemoveDirAssignHash(volume, list); + list->DirOwner = Parent; + UtilAddToDirAssignHash(volume, list); + + // calculate and return directory number + DirNo = ((DirsPerBlock * list->BlockNo) + i); + return DirNo; + } + } + } + list = list->next; + } + return -1; + +} + +ULONG UtilFreeDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo, + ULONG Parent) +{ + register ULONG hash, i, count, SubdirNo; + register ULONG DirsPerBlock, DirsPerCluster; + register ULONG DirIndex, DirBlockNo; + register ULONG retCode; + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list; + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + DirBlockNo = DirNo / DirsPerBlock; + DirIndex = DirNo % DirsPerBlock; + + hash = ((ULONG)Parent & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + return NwHashCorrupt; + + SubdirNo = dos->Subdirectory; + NWFSSet(dos, 0, sizeof(ROOT)); + dos->Subdirectory = FREE_NODE; // mark node free + + retCode = WriteDirectoryRecord(volume, dos, DirNo); + if (retCode) + { + NWFSPrint("nwfs: error in directory write (%d)\n", (int)retCode); + return retCode; + } + + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if ((list->BlockNo == DirBlockNo) && + (list->DirOwner == Parent)) + { + // free directory record + list->FreeList[DirIndex >> 3] &= ~(1 << (DirIndex & 7)); + + // see if this block has any allocated dir entries, if so + // then exit, otherwise, re-hash the block into the + // free list + + for (i=0; i < DirsPerBlock; i++) + { + // check for allocated entries + if (((list->FreeList[i >> 3]) >> (i & 7)) & 1) + return 0; + } + + // if we get here the we assume that the entire directory + // block is now free. we remove this block from the + // previous assigned parent hash, then re-hash it into the + // directory free list (-1) + + UtilRemoveDirAssignHash(volume, list); + list->DirOwner = FREE_NODE; + UtilAddToDirAssignHash(volume, list); + return 0; + } + list = list->next; + } + + // if we could not locate the directory entry, then perform + // a brute force search of the record in all of the parent + // assign hash records. Netware does allow parent records + // to be mixed within a single block in rare circumstances. + // this should rarely happen, however, and if it ever does + // it indicates possible directory corruption. In any case, + // even if the directory is corrupt, we should allow folks + // the ability to purge these records. + + for (count=0; count < volume->DirAssignHashLimit; count++) + { + list = (DIR_ASSIGN_HASH *) HashTable[count].head; + while (list) + { + if (list->BlockNo == DirBlockNo) + { + NWFSPrint("nwfs: record freed in non-assigned parent block [%X/%X]\n", + (unsigned int)SubdirNo, + (unsigned int)list->DirOwner); + + // free directory record + list->FreeList[DirIndex >> 3] &= ~(1 << (DirIndex & 7)); + + // see if this block has any allocated dir entries, if so + // then exit, otherwise, re-hash the block into the + // free list + + for (i=0; i < DirsPerBlock; i++) + { + // check for allocated entries + if (((list->FreeList[i >> 3]) >> (i & 7)) & 1) + return 0; + } + + // if we get here the we assume that the entire directory + // block is now free. we remove this block from the + // previous assigned parent hash, then re-hash it into the + // directory free list (-1) + + UtilRemoveDirAssignHash(volume, list); + list->DirOwner = FREE_NODE; + UtilAddToDirAssignHash(volume, list); + return 0; + } + list = list->next; + } + } + return 0; +} + +ULONG FormatNamespaceRecord(VOLUME *volume, BYTE *Name, ULONG Len, + ULONG Parent, ULONG NWFlags, ULONG Namespace, + DOS *dos) +{ + register ULONG retCode; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + + NWFSSet(dos, 0, sizeof(DOS)); + + switch (Parent) + { + case FREE_NODE: + case SUBALLOC_NODE: + case RESTRICTION_NODE: + case TRUSTEE_NODE: + return -1; + + case ROOT_NODE: + switch (Namespace) + { + case LONG_NAME_SPACE: + // create LONG_NAME_SPACE root directory record + longname = (LONGNAME *) dos; + longname->Flags = SUBDIRECTORY_FILE; + longname->NameSpace = LONG_NAME_SPACE; + longname->Subdirectory = ROOT_NODE; + return 0; + + case UNIX_NAME_SPACE: + // create UNIX_NAME_SPACE root directory record + nfs = (NFS *) dos; + nfs->nlinks = 2; + nfs->Flags = SUBDIRECTORY_FILE; + nfs->NameSpace = UNIX_NAME_SPACE; + nfs->Subdirectory = ROOT_NODE; + return 0; + + case MAC_NAME_SPACE: + // create MAC_NAME_SPACE root directory record + mac = (MACINTOSH *) dos; + mac->Flags = SUBDIRECTORY_FILE; + mac->NameSpace = MAC_NAME_SPACE; + mac->Subdirectory = ROOT_NODE; + mac->ResourceFork = (ULONG) -1; + return 0; + + case NT_NAME_SPACE: + // create NT_NAME_SPACE root directory record + nt = (NTNAME *) dos; + nt->Flags = SUBDIRECTORY_FILE; + nt->NameSpace = NT_NAME_SPACE; + nt->Subdirectory = ROOT_NODE; + return 0; + + default: + return -1; + } + break; + + default: + switch (Namespace) + { + case MAC_NAME_SPACE: + mac = (MACINTOSH *) dos; + retCode = NWCreateMACName(volume, Name, Len, mac, Parent); + if (retCode) + return retCode; + + if (NWFlags & SUBDIRECTORY_FILE) + mac->Flags |= SUBDIRECTORY_FILE; + else + mac->Flags |= (NWFlags | NAMED_FILE); + mac->NameSpace = MAC_NAME_SPACE; + mac->Subdirectory = Parent; + mac->NameList = 0; + mac->PrimaryEntry = 0; + mac->ResourceForkSize = 0; + mac->ResourceFork = (ULONG) -1; + return 0; + + case UNIX_NAME_SPACE: + nfs = (NFS *) dos; + retCode = NWCreateNFSName(volume, Name, Len, nfs, Parent); + if (retCode) + return retCode; + + if (NWFlags & SUBDIRECTORY_FILE) + { + nfs->nlinks = 2; + nfs->Flags |= SUBDIRECTORY_FILE; + } + else + { + nfs->nlinks = 1; + nfs->Flags |= (NWFlags | NAMED_FILE); + } + if (NWFlags & SYMBOLIC_LINKED_FILE) + nfs->LinkedFlag = NFS_SYMBOLIC_LINK; + else + nfs->LinkedFlag = 0; + + nfs->NameSpace = UNIX_NAME_SPACE; + nfs->Subdirectory = Parent; + nfs->FileNameLength = (nfs->TotalFileNameLength <= MAX_NFS_NAME) + ? nfs->TotalFileNameLength : MAX_NFS_NAME; + nfs->gid = 0; + nfs->uid = 0; + nfs->mode = 0; + nfs->rdev = 0; + nfs->NameList = 0; + nfs->PrimaryEntry = 0; + return 0; + + case LONG_NAME_SPACE: + longname = (LONGNAME *) dos; + retCode = NWCreateLONGName(volume, Name, Len, longname, Parent); + if (retCode) + return retCode; + + if (NWFlags & SUBDIRECTORY_FILE) + longname->Flags |= SUBDIRECTORY_FILE; + else + longname->Flags |= (NWFlags | NAMED_FILE); + longname->NameSpace = LONG_NAME_SPACE; + longname->Subdirectory = Parent; + longname->NameList = 0; + longname->PrimaryEntry = 0; + return 0; + + case NT_NAME_SPACE: + nt = (NTNAME *) dos; + retCode = NWCreateLONGName(volume, Name, Len, (LONGNAME *)nt, Parent); + if (retCode) + return retCode; + + if (NWFlags & SUBDIRECTORY_FILE) + nt->Flags |= SUBDIRECTORY_FILE; + else + nt->Flags |= (NWFlags | NAMED_FILE); + nt->NameSpace = NT_NAME_SPACE; + nt->Subdirectory = Parent; + nt->NameList = 0; + nt->PrimaryEntry = 0; + return 0; + + default: + return -1; + } + } +} + +extern BYTE *NSDescription(ULONG ns); + +ULONG AddSpecificVolumeNamespace(VOLUME *volume, ULONG namespace) +{ + register ULONG Dir1Size, Dir2Size, i, j, k, ccode, owner; + register ULONG DirCount, DirBlocks, cbytes, DirsPerBlock, DirTotal; + register ULONG PrevLink, NameLink, NextLink, LinkCount; + LONGLONG VolumeSpace, NameSpaceSize; + register DOS *dos, *new, *prev, *name, *base; + register MACINTOSH *mac; + register NFS *nfs; + register LONGNAME *longname; + register NTNAME *nt; + register TRUSTEE *trustee; + register USER *user; + register ROOT *root; + register ROOT3X *root3x; + register ULONG MacID, LongID, NfsID, DosID, NtID, NewDirNo; + ULONG retRCode; + BYTE FoundNameSpace[MAX_NAMESPACES]; + + if (namespace == DOS_NAME_SPACE) + return -1; + + ccode = MountRawVolume(volume); + if (ccode) + return NwVolumeCorrupt; + + dos = NWFSCacheAlloc(IO_BLOCK_SIZE, DIR_WORKSPACE_TAG); + if (!dos) + { + DismountRawVolume(volume); + return NwInsufficientResources; + } + + new = NWFSCacheAlloc(IO_BLOCK_SIZE, DIR_WORKSPACE_TAG); + if (!new) + { + NWFSFree(dos); + DismountRawVolume(volume); + return NwInsufficientResources; + } + prev = (DOS *)&new[1]; // create temporary directory workspaces + name = (DOS *)&new[2]; + base = (DOS *)&new[3]; + mac = (MACINTOSH *)&new[4]; + nfs = (NFS *)&new[5]; + longname = (LONGNAME *)&new[6]; + nt = (NTNAME *)&new[7]; + + Dir1Size = GetChainSize(volume, volume->FirstDirectory); + Dir2Size = GetChainSize(volume, volume->SecondDirectory); + + if (!Dir1Size || !Dir2Size || (Dir1Size != Dir2Size)) + { + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return NwDirectoryCorrupt; + } + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + DirBlocks = (Dir1Size + (volume->BlockSize - 1)) / volume->BlockSize; + DirTotal = (Dir1Size + (sizeof(DOS) - 1)) / sizeof(DOS); + + NWFSPrint("\nAnalyzing space requirements for the %s namespace ...\n", + NSDescription(namespace)); + + ccode = UtilInitializeDirAssignHash(volume); + if (ccode) + { + NWFSPrint("nwfs: error during assign hash init\n"); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + for (DirCount = i = 0; i < DirBlocks; i++) + { + cbytes = NWReadFile(volume, + &volume->FirstDirectory, + 0, + Dir1Size, + i * volume->BlockSize, + (BYTE *)dos, + volume->BlockSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0, + TRUE); + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error reading directory file\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + for (owner = (ULONG) -1, j=0; j < DirsPerBlock; j++) + { + switch (dos[j].Subdirectory) + { + case ROOT_NODE: + if (owner == (ULONG) -1) + owner = 0; + root = (ROOT *) &dos[j]; + if (root->NameSpace == DOS_NAME_SPACE) + DirCount++; + break; + + case SUBALLOC_NODE: + if (owner == (ULONG) -1) + owner = 0; + break; + + case FREE_NODE: + break; + + case RESTRICTION_NODE: + user = (USER *) &dos[j]; + if (owner == (ULONG) -1) + owner = 0; + break; + + case TRUSTEE_NODE: + trustee = (TRUSTEE *) &dos[j]; + if (owner == (ULONG) -1) + owner = 0; + break; + + default: + if (owner == (ULONG) -1) + owner = dos[j].Subdirectory; + + if (dos[j].NameSpace == DOS_NAME_SPACE) + DirCount++; + break; + } + } + + ccode = UtilCreateDirAssignEntry(volume, owner, i, dos); + if (ccode) + { + NWFSPrint("nwfs: error creating dir assign hash\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + } + + VolumeSpace = (LONGLONG)((LONGLONG)volume->VolumeAllocatedClusters * + (LONGLONG)volume->ClusterSize); + NameSpaceSize = (LONGLONG)((LONGLONG)DirCount * (LONGLONG)sizeof(ROOT)); + + if (VolumeSpace >= 1024) + NWFSPrint("%u K of free space available on volume %s\n", + (unsigned int)(VolumeSpace / 1024), volume->VolumeName); + else + NWFSPrint("%u bytes of free space available on volume %s\n", + (unsigned int)VolumeSpace, volume->VolumeName); + + if (NameSpaceSize >= 1024) + NWFSPrint("%u K directory space required to add the %s namespace\n", + (unsigned int)(NameSpaceSize / 1024), NSDescription(namespace)); + else + NWFSPrint("%u bytes directory space required to add the %s namespace\n", + (unsigned int)NameSpaceSize, NSDescription(namespace)); + + if (NameSpaceSize >= (VolumeSpace + sizeof(ROOT))) + { + NWFSPrint("Insufficient space available to add namespace %s\n", + NSDescription(namespace)); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + NWFSPrint("\nAdding %s namespace to volume [%-15s]\n", + NSDescription(namespace), volume->VolumeName); + + // read the root directory record + root = (ROOT *) dos; + root3x = (ROOT3X *) dos; + ccode = ReadDirectoryRecord(volume, (DOS *)root, 0); + if (ccode) + { + NWFSPrint("nwfs: error reading volume root\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + // see if this is a Netware 4.x/5.x volume + if ((volume->VolumeFlags & NDS_FLAG) || + (volume->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + // check for duplicate namespace entries + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + for (j=0; j < volume->NameSpaceCount; j++) + { + if (volume->NameSpaceID[j] == namespace) + { + NWFSPrint("nwfs: duplicate namespace error\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + if (!j && volume->NameSpaceID[j]) + { + NWFSPrint("nwfs: dos namespace not present\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + if (j && (FoundNameSpace[volume->NameSpaceID[j] & 0xF])) + { + NWFSPrint("nwfs: multiple namespace error\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + FoundNameSpace[volume->NameSpaceID[j] & 0xF] = TRUE; + } + + // add the namespace to the list in the volume table + volume->NameSpaceID[volume->NameSpaceCount] = namespace; + volume->NameSpaceCount++; + root->NameSpaceCount = (BYTE) volume->NameSpaceCount; + + NWFSSet(&root->SupportedNameSpacesNibble[0], 0, 6); + for (j=0, k=0; j < volume->NameSpaceCount; j++) + { + if (j & 1) + { + root->SupportedNameSpacesNibble[k] |= + ((volume->NameSpaceID[j] << 4) & 0xF0); + k++; + } + else + { + root->SupportedNameSpacesNibble[k] |= + (volume->NameSpaceID[j] & 0xF); + } + } + } + else + { + // check for duplicate namespace entries + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + for (j=0; j < volume->NameSpaceCount; j++) + { + if (volume->NameSpaceID[j] == namespace) + { + NWFSPrint("nwfs: duplicate namespace error\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + if (!j && volume->NameSpaceID[j]) + { + NWFSPrint("nwfs: dos namespace not present\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + if (j && (FoundNameSpace[volume->NameSpaceID[j] & 0xF])) + { + NWFSPrint("nwfs: multiple namespace error\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + FoundNameSpace[volume->NameSpaceID[j] & 0xF] = TRUE; + } + + // add the namespace to the list in the volume table + volume->NameSpaceID[volume->NameSpaceCount] = namespace; + volume->NameSpaceCount++; + root3x->NameSpaceCount = (BYTE) volume->NameSpaceCount; + + // clear the current namespace entries in the root + // entry and reset. + + NWFSSet(&root3x->NameSpaceTable[0], 0, 10); + for (j=0; j < volume->NameSpaceCount; j++) + root3x->NameSpaceTable[j] = (BYTE)volume->NameSpaceID[j]; + } + + // write the modified root entry + ccode = WriteDirectoryRecord(volume, (DOS *)root, 0); + if (ccode) + { + NWFSPrint("nwfs: error writing volume root\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + // now add the new namespace records. DirTotal should be the upward + // limit of detected DOS namespace records. While we are allocating + // new records to add the namespace, the directory file will expand + // beyond this point, but this should be ok. + + for (i=0; i < DirTotal; i++) + { + ccode = ReadDirectoryRecord(volume, dos, i); + if (ccode) + { + NWFSPrint("nwfs: error reading volume directory\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + NtID = MacID = DosID = LongID = NfsID = (ULONG) -1; + if ((dos->Subdirectory != FREE_NODE) && + (dos->Subdirectory != SUBALLOC_NODE) && + (dos->Subdirectory != RESTRICTION_NODE) && + (dos->Subdirectory != TRUSTEE_NODE) && + (dos->NameSpace == DOS_NAME_SPACE)) + { + // copy the DOS root entry and store in temporary workspace + NWFSCopy(base, dos, sizeof(DOS)); + + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + PrevLink = i; + LinkCount = 1; + NameLink = dos->NameList; + DosID = i; + + // run the entire name list chain and look for duplicate + // namespace records. Also check for invalid name list + // linkage. + + while (NameLink) + { + if (LinkCount++ > volume->NameSpaceCount) + { + NWFSPrint("nwfs: invalid name list detected (add)\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + if (NameLink > DirTotal) + { + NWFSPrint("nwfs: directory number out of range (add namespace)\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + if (FoundNameSpace[dos->NameSpace & 0xF]) + { + NWFSPrint("nwfs: multiple name space error\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + FoundNameSpace[dos->NameSpace & 0xF] = TRUE; + + ccode = ReadDirectoryRecord(volume, dos, NameLink); + if (ccode) + { + NWFSPrint("nwfs: error reading volume directory\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + // record directory numbers for each namespace we encounter + // and make a copy of each of the diretory records + switch (dos->NameSpace) + { + case MAC_NAME_SPACE: + if (MacID == (ULONG) -1) + MacID = NameLink; + NWFSCopy(mac, dos, sizeof(DOS)); + break; + + case LONG_NAME_SPACE: + if (LongID == (ULONG) -1) + LongID = NameLink; + NWFSCopy(longname, dos, sizeof(DOS)); + break; + + case NT_NAME_SPACE: + if (NtID == (ULONG) -1) + NtID = NameLink; + NWFSCopy(nt, dos, sizeof(DOS)); + break; + + case UNIX_NAME_SPACE: + if (NfsID == (ULONG) -1) + NfsID = NameLink; + NWFSCopy(nfs, dos, sizeof(DOS)); + break; + + default: + break; + } + + // save the link to the next namespace record + NextLink = dos->NameList; + PrevLink = NameLink; + NameLink = NextLink; + } + + // select a name record to use to create the name for the new + // record. If we have a LONG or NFS namespace, use this + // namespace to provide the name for the new record, otherwise + // default to NT and MAC namespaces. If none of the cases + // are detected, then by default, we use the DOS namespace. + + if ((namespace != LONG_NAME_SPACE) && (LongID != (ULONG) -1)) + { + // format the new namespace record + ccode = FormatNamespaceRecord(volume, + longname->FileName, + longname->FileNameLength, + base->Subdirectory, + base->Flags, + namespace, + new); + } + else + if ((namespace != UNIX_NAME_SPACE) && (NfsID != (ULONG) -1)) + { + // format the new namespace record + ccode = FormatNamespaceRecord(volume, + nfs->FileName, + nfs->TotalFileNameLength, + base->Subdirectory, + base->Flags, + namespace, + new); + } + else + if ((namespace != NT_NAME_SPACE) && (NtID != (ULONG) -1)) + { + // format the new namespace record + ccode = FormatNamespaceRecord(volume, + nt->FileName, + nt->FileNameLength, + base->Subdirectory, + base->Flags, + namespace, + new); + } + else + { + // format the new namespace record + ccode = FormatNamespaceRecord(volume, + base->FileName, + base->FileNameLength, + base->Subdirectory, + base->Flags, + namespace, + new); + } + + // save a copy of the last namespace record in this chain. + NWFSCopy(prev, dos, sizeof(DOS)); + + if (ccode) + { + NWFSPrint("nwfs: error formatting namespace record\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + // now try to allocate a new directory record for this namespace + // entry. + + if (base->Subdirectory == ROOT_NODE) + NewDirNo = UtilAllocateDirectoryRecord(volume, 0); + else + NewDirNo = UtilAllocateDirectoryRecord(volume, base->Subdirectory); + + if (NewDirNo == (ULONG) -1) + { + NWFSPrint("nwfs: error allocating directory record\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + // set the last record in the namespace chain to point to this + // record and set the new record to point to the primary entry. + + prev->NameList = NewDirNo; + new->NameList = 0; + new->PrimaryEntry = prev->PrimaryEntry; + + ccode = WriteDirectoryRecord(volume, prev, PrevLink); + if (ccode) + { + NWFSPrint("nwfs: error writing volume directory\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + + ccode = WriteDirectoryRecord(volume, new, NewDirNo); + if (ccode) + { + NWFSPrint("nwfs: error writing volume directory\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + return -1; + } + } + } + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + NWFSFree(new); + + NWFSPrint("\n%s namespace added successfully to volume %s\n", + NSDescription(namespace), volume->VolumeName); + + return 0; +} + +ULONG RemoveSpecificVolumeNamespace(VOLUME *volume, ULONG namespace) +{ + register ULONG Dir1Size, Dir2Size, i, j, k, ccode, pFlag; + register ULONG DirTotal, PrevLink, NameLink, NextLink, LinkCount; + register DOS *dos; + register ROOT *root; + register ROOT3X *root3x; + BYTE FoundNameSpace[MAX_NAMESPACES]; + + if (namespace == DOS_NAME_SPACE) + return -1; + + ccode = MountRawVolume(volume); + if (ccode) + return NwVolumeCorrupt; + + dos = NWFSCacheAlloc(sizeof(ROOT), DIR_WORKSPACE_TAG); + if (!dos) + { + DismountRawVolume(volume); + return NwInsufficientResources; + } + + Dir1Size = GetChainSize(volume, volume->FirstDirectory); + Dir2Size = GetChainSize(volume, volume->SecondDirectory); + + if (!Dir1Size || !Dir2Size || (Dir1Size != Dir2Size)) + { + DismountRawVolume(volume); + NWFSFree(dos); + return NwDirectoryCorrupt; + } + + DirTotal = Dir1Size / sizeof(ROOT); + + NWFSPrint("\nRemoving %s namespace from volume %s\n", + NSDescription(namespace), volume->VolumeName); + + // read the root directory record + root = (ROOT *) dos; + root3x = (ROOT3X *) dos; + ccode = ReadDirectoryRecord(volume, (DOS *)root, 0); + if (ccode) + { + NWFSPrint("nwfs: error reading volume root\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + // see if this is a Netware 4.x/5.x volume + if ((volume->VolumeFlags & NDS_FLAG) || + (volume->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + // check for duplicate namespace entries + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + for (j=0; j < volume->NameSpaceCount; j++) + { + if (!j && volume->NameSpaceID[j]) + { + NWFSPrint("nwfs: dos namespace not present\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + if (j && (FoundNameSpace[volume->NameSpaceID[j] & 0xF])) + { + NWFSPrint("nwfs: multiple namespace error\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + FoundNameSpace[volume->NameSpaceID[j] & 0xF] = TRUE; + } + + // remove the namespace from the list in the volume table + for (j=0; j < volume->NameSpaceCount; j++) + { + if (volume->NameSpaceID[j] == namespace) + { + for (; j < volume->NameSpaceCount; j++) + { + if ((j + 1) >= volume->NameSpaceCount) + volume->NameSpaceID[j] = 0; + else + volume->NameSpaceID[j] = volume->NameSpaceID[j + 1]; + } + } + } + + // don't go negative if our count is zero + if (volume->NameSpaceCount) + volume->NameSpaceCount--; + + // if only the DOS namespace is present, then we set the + // namespace count to zero (Netware specific behavior). + if (volume->NameSpaceCount == 1) + root->NameSpaceCount = 0; + else + root->NameSpaceCount = (BYTE) volume->NameSpaceCount; + + + // clear the current namespace entries in the root + // entry and reset. + + NWFSSet(&root->SupportedNameSpacesNibble[0], 0, 6); + for (j=0, k=0; j < volume->NameSpaceCount; j++) + { + if (j & 1) + { + root->SupportedNameSpacesNibble[k] |= + ((volume->NameSpaceID[j] << 4) & 0xF0); + k++; + } + else + { + root->SupportedNameSpacesNibble[k] |= + (volume->NameSpaceID[j] & 0xF); + } + } + } + else + { + // check for duplicate namespace entries + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + for (j=0; j < volume->NameSpaceCount; j++) + { + if (!j && volume->NameSpaceID[j]) + { + NWFSPrint("nwfs: dos namespace not present\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + if (j && (FoundNameSpace[volume->NameSpaceID[j] & 0xF])) + { + NWFSPrint("nwfs: multiple namespace error\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + FoundNameSpace[volume->NameSpaceID[j] & 0xF] = TRUE; + } + + // remove the namespace from the list in the volume table + for (j=0; j < volume->NameSpaceCount; j++) + { + if (volume->NameSpaceID[j] == namespace) + { + for (; j < volume->NameSpaceCount; j++) + { + if ((j + 1) >= volume->NameSpaceCount) + volume->NameSpaceID[j] = 0; + else + volume->NameSpaceID[j] = volume->NameSpaceID[j + 1]; + } + } + } + + // don't go negative if our count is zero + if (volume->NameSpaceCount) + volume->NameSpaceCount--; + + // if only the DOS namespace is present, then we set the + // namespace count to zero (Netware specific behavior). + if (volume->NameSpaceCount == 1) + root3x->NameSpaceCount = 0; + else + root3x->NameSpaceCount = (BYTE) volume->NameSpaceCount; + + // clear the current namespace entries in the root + // entry and reset. + + NWFSSet(&root3x->NameSpaceTable[0], 0, 10); + for (j=0; j < volume->NameSpaceCount; j++) + root3x->NameSpaceTable[j] = (BYTE)volume->NameSpaceID[j]; + } + + // write the modified root entry + ccode = WriteDirectoryRecord(volume, (DOS *)root, 0); + if (ccode) + { + NWFSPrint("nwfs: error writing volume root\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + // now remove the affected namespace records + for (i=0; i < DirTotal; i++) + { + ccode = ReadDirectoryRecord(volume, dos, i); + if (ccode) + { + NWFSPrint("nwfs: error reading volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + if ((dos->Subdirectory != FREE_NODE) && + (dos->Subdirectory != SUBALLOC_NODE) && + (dos->Subdirectory != RESTRICTION_NODE) && + (dos->Subdirectory != TRUSTEE_NODE) && + (dos->NameSpace == DOS_NAME_SPACE)) + { + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + pFlag = 0; + PrevLink = i; + LinkCount = 1; + NameLink = dos->NameList; + + while (NameLink) + { + if (LinkCount++ > volume->NameSpaceCount) + { + NWFSPrint("nwfs: invalid name list detected (add)\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + if (NameLink > DirTotal) + { + NWFSPrint("nwfs: directory number out of range (remove)\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + if (FoundNameSpace[dos->NameSpace & 0xF]) + { + NWFSPrint("nwfs: multiple name space error\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + FoundNameSpace[dos->NameSpace & 0xF] = TRUE; + + ccode = ReadDirectoryRecord(volume, dos, NameLink); + if (ccode) + { + NWFSPrint("nwfs: error reading volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + // save the link to the next namespace record + NextLink = dos->NameList; + + if (dos->NameSpace == namespace) + { + // if this record is designated as primary namespace, + // then we must set the DOS_NAME_SPACE record as the + // new primary. + if (dos->Flags & PRIMARY_NAMESPACE) + pFlag = TRUE; + + // free this record + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG) FREE_NODE; + + // mark this record as free + ccode = WriteDirectoryRecord(volume, dos, NameLink); + if (ccode) + { + NWFSPrint("nwfs: error writing volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + // read the previous record + ccode = ReadDirectoryRecord(volume, dos, PrevLink); + if (ccode) + { + NWFSPrint("nwfs: error reading volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + // update previous namespace forward link to the next link + // for this namespace record + dos->NameList = NextLink; + + // write the previous record + ccode = WriteDirectoryRecord(volume, dos, PrevLink); + if (ccode) + { + NWFSPrint("nwfs: error writing volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + break; + } + PrevLink = NameLink; + NameLink = NextLink; + } + + // if we are removing a namespace record that was designated + // as PRIMARY_NAMESPACE, then set the DOS_NAME_SPACE entry + // as the new primary namespace record. + + if (pFlag) + { + ccode = ReadDirectoryRecord(volume, dos, i); + if (ccode) + { + NWFSPrint("nwfs: error reading volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + + dos->Flags |= PRIMARY_NAMESPACE; + ccode = WriteDirectoryRecord(volume, dos, i); + if (ccode) + { + NWFSPrint("nwfs: error writing volume directory\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return -1; + } + } + } + } + DismountRawVolume(volume); + NWFSFree(dos); + + NWFSPrint("\n%s namespace successfully removed from volume %s\n", + NSDescription(namespace), volume->VolumeName); + return 0; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwdir.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwdir.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwdir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwdir.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,3052 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWDIR.C +* DESCRIP : NWFS NetWare Directory Management +* DATE : December 7, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +BYTE *NameSpaceStrings[16]= +{ + "DOS ", "MAC ", "NFS ", "FTAM", "LONG", "NT ", "FEN ", "????", + "????", "????", "????", "????", "????", "????", "????", "????" +}; + +BYTE *AttributeDescription[]= +{ + "Ro - Read Only File", // 00000001 + "Hd - Hidden File", // 00000002 + "Sm - System File", // 00000004 + "Ex - Execute Only", // 00000008 + "Sd - Subdirectory", // 00000010 + "Ar - Archived", // 00000020 + "Reserved-00000040", // 00000040 + "Sh - Shareable", // 00000080 + "Reserved-00000100", // 00000100 + "Sm - Share Modes Supported", // 00000200 + "Sm - Share Modes Supported", // 00000400 + "Sd - Suballocation Disabled", // 00000800 + "Tr - Transactional File", // 00001000 + "Oi - Old Indexed On", // 00002000 + "Ra - Read Auditing On", // 00004000 + "Wa - Write Auditing On", // 00008000 + "Ip - Immediate Purge", // 00010000 + "Ri - Rename Inhibit", // 00020000 + "Di - Delete Inhibit", // 00040000 + "Ci - Copy Inhibit", // 00080000 + "Fa - File Auditing Enabled", // 00100000 + "Cn - Container File", // 00200000 + "Ra - Remote Data Access", // 00400000 + "Ri - Remote Data Save Inhibit", // 00800000 + "Rs - Remote Data Save Key", // 01000000 + "Ci - Compress Immediately", // 02000000 + "Cp - File is Compressed", // 04000000 + "Nc - Compression Disabled", // 08000000 + "Reserved-10000000", // 10000000 + "Cc - Cannot Compress File Data", // 20000000 + "Af - Compressed Archive File", // 40000000 + "Reserved-80000000", // 80000000 +}; + +BYTE *AttributeShorthand[]= +{ + "Ro", "Hd", "Sm", "Ex", "Sd", "Ar", "--", "Sh", "--", "Sm", + "Sm", "Sd", "Tr", "Oi", "Ra", "Wa", "Ip", "Ri", "Di", "Ci", // 00080000 + "Fa", "Cn", "Ra", "Ri", "Rs", "Ci", "Cp", "Nc", "--", "Cc", + "Af", "--", +}; + +void NWLockVolume(VOLUME *volume) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&volume->VolumeSemaphore) == -EINTR) + NWFSPrint("lock volume was interupted\n"); +#endif + +} +void NWUnlockVolume(VOLUME *volume) +{ + +#if (LINUX_SLEEP) + SignalSemaphore(&volume->VolumeSemaphore); +#endif +} + +void NWLockDirAssign(VOLUME *volume) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&volume->DirAssignSemaphore) == -EINTR) + NWFSPrint("lock dir assign was interupted\n"); +#endif +} + +void NWUnlockDirAssign(VOLUME *volume) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&volume->DirAssignSemaphore); +#endif +} + +void NWLockDirBlock(VOLUME *volume) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&volume->DirBlockSemaphore) == -EINTR) + NWFSPrint("lock dir block was interupted\n"); +#endif +} + +void NWUnlockDirBlock(VOLUME *volume) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&volume->DirBlockSemaphore); +#endif +} + +ULONG InitializeVolumeDirectory(VOLUME *volume) +{ + register ULONG retCode; + ULONG DirNo = 0; + + // if the DELETED.SAV directory does not exist, then create it. + + retCode = NWCreateDirectoryEntry(volume, + "DELETED.SAV", + 11, + (SUBDIRECTORY | HIDDEN | SYSTEM), + 0, + NW_SUBDIRECTORY_FILE, + 0, 0, 0, 0, &DirNo, + (ULONG) -1, 0, + (ULONG) -1, 0, + 0, 0); + if ((retCode) && (retCode != NwFileExists)) + return retCode; + + + // if the volume flags indicate that this is a Netware 4.x volume + // then create the Netware Directory Services Directory. + + if ((volume->VolumeFlags & NEW_TRUSTEE_COUNT) || + (volume->VolumeFlags & NDS_FLAG)) + { + retCode = NWCreateDirectoryEntry(volume, + "_NETWARE", + 8, + (SUBDIRECTORY | HIDDEN | SYSTEM | IMMEDIATE_PURGE), + 0, + NW_SUBDIRECTORY_FILE, + 0, 0, 0, 0, &DirNo, + (ULONG) -1, 0, + (ULONG) -1, 0, + 0, 0); + if ((retCode) && (retCode != NwFileExists)) + return retCode; + } + + // if suballocation is enabled for this volume, check if the + // chain has been created. if the suballoc chain heads have + // not been initialized, then create them. + + if (volume->VolumeFlags & SUB_ALLOCATION_ON) + { + if (!volume->VolumeSuballocRoot) + { + retCode = NWCreateSuballocRecords(volume); + if (retCode) + return retCode; + } + } + +#if (VERBOSE) + NWFSPrint("last dir block-%d last valid dir block-%d\n", + (int)volume->EndingBlockNo, + (int)volume->LastValidBlockNo); +#endif + + return 0; +} + +ULONG ValidateDirectoryRecord(VOLUME *volume, DOS *dos) +{ + switch (dos->Subdirectory) + { + case FREE_NODE: + return 0; + + case TRUSTEE_NODE: + { + register ULONG i; + TRUSTEE *trustee = (TRUSTEE *)dos; + + if ((trustee->Reserved1[0]) || (trustee->TrusteeCount > 16)) + { + NWFSPrint("Invalid trustee record res1-%d trustees-%d\n", + (int)trustee->Reserved1[0], + (int)trustee->TrusteeCount); + return 1; + } + + for (i=0; i < 16; i++) + { + if (trustee->TrusteeMask[i] & ~TRUSTEE_VALID_MASK) + { + NWFSPrint("Invalid trustee record mask-%08X MASK-%08X\n", + (unsigned)trustee->TrusteeMask[i], + (unsigned)TRUSTEE_VALID_MASK); + return 1; + } + } + } + return 0; + + case ROOT_NODE: + { + ROOT *root = (ROOT *)dos; + ROOT3X *root3x = (ROOT3X *)dos; + + if ((root->NameSpace > 10) || (root->NameSpaceCount > 10)) + { + NWFSPrint("Namespace/count (%d-%d) was > 10\n", + (int)root->NameSpace, (int)root->NameSpaceCount); + return 1; + } + + if ((volume->VolumeFlags & NDS_FLAG) || + (volume->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + if (root->VolumeFlags & ~VFLAGS_4X_MASK) + { + NWFSPrint("root 4X volume flags invalid (%08X) mask-%08X\n", + (unsigned)root->VolumeFlags, + (unsigned)VFLAGS_4X_MASK); + return 1; + } + } + else + { + if (root3x->VolumeFlags & ~VFLAGS_3X_MASK) + { + NWFSPrint("root 3X volume flags invalid (%08X) mask-%08X\n", + (unsigned)root3x->VolumeFlags, + (unsigned)VFLAGS_3X_MASK); + return 1; + } + } + } + return 0; + + case RESTRICTION_NODE: + { + USER *user = (USER *)dos; + + if ((user->Reserved1) || (user->TrusteeCount > 14)) + { + NWFSPrint("Invalid user record res1-%d trustees-%d\n", + (int)user->Reserved1, + (int)user->TrusteeCount); + return 1; + } + } + return 0; + + case SUBALLOC_NODE: + { + SUBALLOC *suballoc = (SUBALLOC *)dos; + register ULONG i; + + if (suballoc->SequenceNumber > 4) + { + NWFSPrint("Invalid suballocation record res-%d sequence-%d\n", + (int)suballoc->Reserved1, + (int)suballoc->SequenceNumber); + return 1; + } + + for (i=0; i < 28; i++) + { + // if any suballocation table entries exceed volume + // clusters, zero the invalid fat heads. + if (suballoc->StartingFATChain[i] > volume->VolumeClusters) + { + NWFSPrint("Invalid suballocation fat head %X (%X)\n", + (unsigned)suballoc->StartingFATChain[i], + (unsigned)volume->VolumeClusters); + return 1; + } + } + } + return 0; + + default: + if (dos->NameSpace > 10) + { + NWFSPrint("Invalid namespace record %d\n", (int)dos->NameSpace); + return 1; + } + + { + MACINTOSH *mac = (MACINTOSH *)dos; + NFS *nfs = (NFS *)dos; + LONGNAME *longname = (LONGNAME *)dos; + NTNAME *nt = (NTNAME *)dos; + + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: +#if (STRICT_NAMES) + if (NWValidDOSName(volume, dos->FileName, + dos->FileNameLength, 0, 0)) + { + NWFSPrint("Invalid dos name\n"); + return 1; + } +#endif + return 0; + + case MAC_NAME_SPACE: +#if (STRICT_NAMES) + if (NWValidMACName(volume, mac->FileName, + mac->FileNameLength, 0, 0)) + { + NWFSPrint("Invalid mac name\n"); + return 1; + } +#endif + return 0; + + case LONG_NAME_SPACE: +#if (STRICT_NAMES) + if (NWValidLONGName(volume, longname->FileName, + longname->FileNameLength, 0, 0)) + { + NWFSPrint("Invalid long name\n"); + return 1; + } +#endif + if (longname->ExtantsUsed > 3) + { + NWFSPrint("Invalid longname file extants-%d\n", + (int)longname->ExtantsUsed); + return 1; + } + + return 0; + + case UNIX_NAME_SPACE: +#if (STRICT_NAMES) + if (NWValidNFSName(volume, nfs->FileName, + nfs->TotalFileNameLength, 0, 0)) + { + NWFSPrint("Invalid nfs name\n"); + return 1; + } +#endif + + if (nfs->ExtantsUsed > 3) + { + NWFSPrint("Invalid nfs file extants-%d\n", + (int)nfs->ExtantsUsed); + return 1; + } + return 0; + + case NT_NAME_SPACE: +#if (STRICT_NAMES) + if (NWValidLONGName(volume, nt->FileName, + nt->FileNameLength, 0, 0)) + { + NWFSPrint("Invalid nt name\n"); + return 1; + } +#endif + + if (nt->ExtantsUsed > 3) + { + NWFSPrint("Invalid nt file extants-%d\n", + (int)nt->ExtantsUsed); + return 1; + } + return 0; + + default: + return 1; + } + } + + return 0; + } +} + +ULONG ReadDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo) +{ + register ULONG DirsPerCluster, hash, cbytes; + register ULONG Block, Offset; + register DIR_BLOCK_HASH_LIST *HashTable; + register DIR_BLOCK_HASH *list; + ULONG retCode = 0; + + if (!dos) + return NwInvalidParameter; + + DirsPerCluster = volume->ClusterSize / sizeof(DOS); + Block = DirNo / DirsPerCluster; + Offset = DirNo % DirsPerCluster; + + hash = (Block & (volume->DirBlockHashLimit - 1)); + HashTable = (DIR_BLOCK_HASH_LIST *) volume->DirBlockHash; + +// if the block hash is uninitialized and we are in utility mode, +// and we treat the directory as a file if the faster block +// hash is not present. + + if (!HashTable) + return NwInvalidParameter; + + NWLockDirBlock(volume); + list = (DIR_BLOCK_HASH *) HashTable[hash].head; + while (list) + { + if (list->BlockNo == Block) + { + cbytes = ReadClusterWithOffset(volume, list->Cluster1, + (Offset * sizeof(DOS)), + (BYTE *)dos, sizeof(DOS), + KERNEL_ADDRESS_SPACE, + &retCode, + DIRECTORY_PRIORITY); + if ((cbytes == sizeof(DOS)) && !retCode) + { + NWUnlockDirBlock(volume); + if (ValidateDirectoryRecord(volume, dos)) + { + NWFSPrint("directory # %X is invalid\n", (unsigned)DirNo); + return NwDirectoryCorrupt; + } + return 0; + } + + // if the first dir read failed, try the second + cbytes = ReadClusterWithOffset(volume, list->Cluster2, + (Offset * sizeof(DOS)), + (BYTE *)dos, sizeof(DOS), + KERNEL_ADDRESS_SPACE, + &retCode, + DIRECTORY_PRIORITY); + if ((cbytes == sizeof(DOS)) && !retCode) + { + NWUnlockDirBlock(volume); + if (ValidateDirectoryRecord(volume, dos)) + { + NWFSPrint("directory # %X is invalid\n", (unsigned)DirNo); + return NwDirectoryCorrupt; + } + return 0; + } + NWUnlockDirBlock(volume); + return NwDiskIoError; + } + list = list->next; + } + NWUnlockDirBlock(volume); + return NwNoEntry; + +} + +ULONG WriteDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo) +{ + register ULONG DirsPerCluster, hash, cbytes; + register ULONG Block, Offset; + register DIR_BLOCK_HASH_LIST *HashTable; + register DIR_BLOCK_HASH *list; + ULONG retCode = 0; + + if (!dos) + return NwInvalidParameter; + + if (ValidateDirectoryRecord(volume, dos)) + { + NWFSPrint("directory # %X is invalid\n", (unsigned)DirNo); + return NwDirectoryCorrupt; + } + + DirsPerCluster = volume->ClusterSize / sizeof(DOS); + Block = DirNo / DirsPerCluster; + Offset = DirNo % DirsPerCluster; + + hash = (Block & (volume->DirBlockHashLimit - 1)); + HashTable = (DIR_BLOCK_HASH_LIST *) volume->DirBlockHash; + +// if the block hash is uninitialized and we are in utility mode, +// and we treat the directory as a file if the faster block +// hash is not present. + + if (!HashTable) + return NwInvalidParameter; + + NWLockDirBlock(volume); + list = (DIR_BLOCK_HASH *) HashTable[hash].head; + while (list) + { + if (list->BlockNo == Block) + { + cbytes = WriteClusterWithOffset(volume, list->Cluster1, + (Offset * sizeof(DOS)), + (BYTE *)dos, sizeof(DOS), + KERNEL_ADDRESS_SPACE, + &retCode, + DIRECTORY_PRIORITY); + + if ((cbytes == sizeof(DOS)) && !retCode) + { +#if (!CREATE_DIR_MISMATCH) + // if first write succeeded, write mirror directory entry + cbytes = WriteClusterWithOffset(volume, list->Cluster2, + (Offset * sizeof(DOS)), + (BYTE *)dos, sizeof(DOS), + KERNEL_ADDRESS_SPACE, + &retCode, + DIRECTORY_PRIORITY); + + if ((cbytes == sizeof(DOS)) && !retCode) + { + NWUnlockDirBlock(volume); + return 0; + + } + NWUnlockDirBlock(volume); + NWFSPrint("mirror directory write failed dirno-%X\n", + (unsigned)DirNo); + return NwDiskIoError; +#else + return 0; +#endif + } + NWUnlockDirBlock(volume); + NWFSPrint("primary directory write failed dirno-%X\n", + (unsigned)DirNo); + return NwDiskIoError; + } + list = list->next; + } + NWUnlockDirBlock(volume); + return NwNoEntry; + +} + +ULONG CompareDirectoryTable(VOLUME *volume) +{ + register FAT_ENTRY *FAT1, *FAT2; + FAT_ENTRY FAT1_S, FAT2_S; + register ULONG retCode; + register long index1, index2; + register ULONG DirNo, DirBlock, block, entry; + register ULONG DirIndex = 0, owner; + register ULONG cluster1, cluster2; + register BYTE *Buffer1, *Buffer2; + register BYTE *PBuffer1, *PBuffer2; + register DOS *dos; + + NWFSPrint("*** Comparing Primary and Mirror Directory Files ***\n"); + + Buffer1 = NWFSCacheAlloc(volume->ClusterSize, DIR_WORKSPACE_TAG); + if (!Buffer1) + return -3; + + Buffer2 = NWFSCacheAlloc(volume->ClusterSize, DIR_WORKSPACE_TAG); + if (!Buffer2) + { + NWFSFree(Buffer1); + return -3; + } + + PBuffer1 = NWFSIOAlloc(volume->ClusterSize, DIR_WORKSPACE_TAG); + if (!PBuffer1) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + PBuffer2 = NWFSIOAlloc(volume->ClusterSize, DIR_WORKSPACE_TAG); + if (!PBuffer2) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + return -3; + } + + DirBlock = DirNo = 0; + cluster1 = volume->FirstDirectory; + cluster2 = volume->SecondDirectory; + + if ((cluster1 && !cluster2) || (!cluster1 && cluster2)) + { + NWFSPrint("nwfs: directory fat head chain mismatch (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -1; + } + + if ((!cluster1) || (!cluster2)) + { + NWFSPrint("nwfs: no root directory located for volume (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + if (((cluster1 == (ULONG)-1) && (cluster2 != (ULONG)-1)) || + ((cluster1 != (ULONG)-1) && (cluster2 == (ULONG)-1))) + { + NWFSPrint("nwfs: directory fat head chain mismatch (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -1; + } + + if ((cluster1 == (ULONG)-1) && (cluster2 == (ULONG)-1)) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return 0; + } + + // read directory root 1 + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, Buffer1, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + // read directory root 2 + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, Buffer2, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + // read directory root 1 + + retCode = ReadAbsoluteVolumeCluster(volume, cluster1, PBuffer1); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + // read directory root 2 + + retCode = ReadAbsoluteVolumeCluster(volume, cluster2, PBuffer2); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadFATTables (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -1; + } + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + while (TRUE) + { + if (NWFSCompare(Buffer1, Buffer2, volume->ClusterSize)) + { + register ULONG i; + extern void dumpRecordBytes(BYTE *, ULONG); + + for (i=0; i < (volume->ClusterSize / 64); i++) + { + if (NWFSCompare(&Buffer1[i * 64], &Buffer2[i * 64], 64)) + { + NWFSPrint("nwfs: directory data mirror mismatch (comp)\n"); + NWFSPrint("offset into cluster is 0x%X (%u bytes)\n", + (unsigned)(i * 64), (unsigned)(i * 64)); + + NWFSPrint("index1-%d cluster1-[%08X] next1-[%08X]\n", (int)index1, + (unsigned int)cluster1, + (unsigned int)FAT1->FATCluster); + dumpRecordBytes(&Buffer1[i * 64], 64); + + NWFSPrint("index2-%d cluster2-[%08X] next2-[%08X]\n", (int)index2, + (unsigned int)cluster2, + (unsigned int)FAT2->FATCluster); + dumpRecordBytes(&Buffer2[i * 64], 64); + break; + } + } + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + for (block=0; block < volume->BlocksPerCluster; block++, DirBlock++) + { + dos = (DOS *) &Buffer1[block * volume->BlockSize]; + for (entry = 0, owner = (ULONG) -1; + entry < (volume->BlockSize / sizeof(ROOT)); + entry++, DirNo++) + { + if (ValidateDirectoryRecord(volume, &dos[entry])) + { + NWFSPrint("Invalid directory record %X detected (comp).\n", + (unsigned)DirNo); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + } + } + + if (NWFSCompare(Buffer1, PBuffer1, volume->ClusterSize)) + { + NWFSPrint("lru/disk mismatch primary directory cluster-%X blocks %X-%X\n", + (unsigned)cluster1, + (unsigned)(cluster1 * volume->BlocksPerCluster), + (unsigned)((cluster1 * volume->BlocksPerCluster) + + volume->BlocksPerCluster)); + } + + if (NWFSCompare(Buffer1, PBuffer2, volume->ClusterSize)) + { + NWFSPrint("lru/disk mismatch mirror directory cluster-%X block %X-%X\n", + (unsigned)cluster2, + (unsigned)(cluster2 * volume->BlocksPerCluster), + (unsigned)((cluster2 * volume->BlocksPerCluster) + + volume->BlocksPerCluster)); + } + + retCode = WritePhysicalVolumeCluster(volume, cluster1, Buffer1, + volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + retCode = WritePhysicalVolumeCluster(volume, cluster2, Buffer2, + volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + if (FAT1->FATCluster == (ULONG) -1) + break; + + // if the other FAT chain terminated abruptly, exit the loop + + if (FAT2->FATCluster == (ULONG) -1) + break; + + if (!FAT1->FATCluster) + { + NWFSPrint("nwfs: Free Cluster detected in DIR1 Chain (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + if (!FAT2->FATCluster) + { + NWFSPrint("nwfs: Free Cluster detected in DIR2 Chain (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + if (FAT1->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in DIR1 (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + if (FAT2->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in DIR2 (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + DirIndex++; + cluster1 = FAT1->FATCluster; + cluster2 = FAT2->FATCluster; + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, Buffer1, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error Directory1 returned %d (comp)\n", (int)retCode); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, Buffer2, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error Directory2 returned %d (comp)\n", (int)retCode); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + // read directory root 1 + + retCode = ReadAbsoluteVolumeCluster(volume, cluster1, PBuffer1); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + // read directory root 2 + + retCode = ReadAbsoluteVolumeCluster(volume, cluster2, PBuffer2); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadDirectoryTables (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -1; + } + + // index numbers should always be ascending. if we detect a + // non-ascending sequence, this indicates a corrupt FAT chain + + if (index1 > FAT1->FATIndex) + { + NWFSPrint("nwfs: DIR1 fat index overlaps on itself (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -1; + } + + if (index2 > FAT2->FATIndex) + { + NWFSPrint("nwfs: DIR2 fat index overlaps on itself (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -1; + } + + // update FAT index number for chains + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + } + + if (FAT1->FATCluster != FAT2->FATCluster) + { + NWFSPrint("nwfs: Directory FAT chain mirror mismatch (comp)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return -3; + } + + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSFree(PBuffer1); + NWFSFree(PBuffer2); + return 0; + +} + +ULONG ReadDirectoryTable(VOLUME *volume) +{ + register FAT_ENTRY *FAT1, *FAT2; + FAT_ENTRY FAT1_S, FAT2_S; + register ULONG retCode; + register long index1, index2; + register ULONG DirNo, DirBlock, block, entry; + register ULONG DirIndex = 0, owner; + register ULONG cluster1, cluster2; + register BYTE *Buffer1, *Buffer2; + register DOS *dos; + register ROOT *root; + register TRUSTEE *trustee; + register USER *user; + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Scanning Directory File ***\n"); +#endif + + Buffer1 = NWFSCacheAlloc(volume->ClusterSize, DIR_WORKSPACE_TAG); + if (!Buffer1) + return -3; + + Buffer2 = NWFSCacheAlloc(volume->ClusterSize, DIR_WORKSPACE_TAG); + if (!Buffer2) + { + NWFSFree(Buffer1); + return -3; + } + + volume->EndingDirCluster1 = 0; + volume->EndingDirCluster2 = 0; + volume->EndingDirIndex = 0; + volume->EndingBlockNo = 0; + volume->LastValidBlockNo = (ULONG)-1; + + DirBlock = DirNo = 0; + cluster1 = volume->FirstDirectory; + cluster2 = volume->SecondDirectory; + + if ((cluster1 && !cluster2) || (!cluster1 && cluster2)) + { + NWFSPrint("nwfs: directory fat head chain mismatch\n"); + if (!cluster1) + { + volume->FirstDirectory = (ULONG) -1; + volume->EndingDirCluster1 = (ULONG)-1; + } + if (!cluster2) + { + volume->SecondDirectory = (ULONG) -1; + volume->EndingDirCluster2 = (ULONG)-1; + } + volume->EndingDirIndex = (ULONG)-1; + volume->EndingBlockNo = (ULONG)-1; + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + if ((!cluster1) || (!cluster2)) + { + NWFSPrint("nwfs: no root directory located for volume\n"); + volume->FirstDirectory = (ULONG) -1; + volume->SecondDirectory = (ULONG) -1; + volume->EndingDirCluster1 = (ULONG)-1; + volume->EndingDirCluster2 = (ULONG)-1; + volume->EndingDirIndex = (ULONG)-1; + volume->EndingBlockNo = (ULONG)-1; + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + if (((cluster1 == (ULONG)-1) && (cluster2 != (ULONG)-1)) || + ((cluster1 != (ULONG)-1) && (cluster2 == (ULONG)-1))) + { + NWFSPrint("nwfs: directory fat head chain mismatch\n"); + if (!cluster1) + { + volume->EndingDirCluster1 = (ULONG)-1; + volume->EndingDirIndex = (ULONG)-1; + volume->EndingBlockNo = -1; + } + if (!cluster2) + { + volume->EndingDirCluster2 = (ULONG)-1; + volume->EndingDirIndex = (ULONG)-1; + volume->EndingBlockNo = -1; + } + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + if ((cluster1 == (ULONG)-1) && (cluster2 == (ULONG)-1)) + { + volume->EndingDirCluster1 = (ULONG)-1; + volume->EndingDirCluster2 = (ULONG)-1; + volume->EndingDirIndex = (ULONG)-1; + volume->EndingBlockNo = -1; + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return 0; + } + + retCode = CreateDirBlockEntry(volume, cluster1, cluster2, DirIndex); + if (retCode) + { + NWFSPrint("nwfs: could not allocate Dir Block Hash element in ReadDirectory\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + // read directory root 1 + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, Buffer1, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + // read directory root 2 + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, Buffer2, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadFATTables\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + while (TRUE) + { + if (NWFSCompare(Buffer1, Buffer2, volume->ClusterSize)) + { + extern void dumpRecordBytes(BYTE *, ULONG); + + NWFSPrint("nwfs: directory data mirror mismatch\n"); + +#if (VERBOSE) + for (i=0; i < (volume->ClusterSize / 64); i++) + { + if (NWFSCompare(&Buffer1[i * 64], &Buffer2[i * 64], 64)) + { + NWFSPrint("offset into cluster is 0x%X (%u bytes)\n", + (unsigned)(i * 64), (unsigned)(i * 64)); + + NWFSPrint("index1-%d cluster1-[%08X] next1-[%08X]\n", (int)index1, + (unsigned int)cluster1, + (unsigned int)FAT1->FATCluster); + dumpRecordBytes(&Buffer1[i * 64], 64); + + NWFSPrint("index2-%d cluster2-[%08X] next2-[%08X]\n", (int)index2, + (unsigned int)cluster2, + (unsigned int)FAT2->FATCluster); + dumpRecordBytes(&Buffer2[i * 64], 64); + break; + } + } +#endif + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + // each 4K block in a Netware directory is assumed to + // be owned by a single parent. we parse the directory + // file in 4K blocks and each block is hashed based on + // parent. this speeds up creates since we can quickly + // find blocks by parent and search them for unused entries. + + for (block=0; block < volume->BlocksPerCluster; block++, DirBlock++) + { + dos = (DOS *) &Buffer1[block * volume->BlockSize]; + for (entry = 0, owner = (ULONG) -1; + entry < (volume->BlockSize / sizeof(ROOT)); + entry++, DirNo++) + { + if (ValidateDirectoryRecord(volume, &dos[entry])) + { + NWFSPrint("Invalid directory record %X detected.\n", + (unsigned)DirNo); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + switch (dos[entry].Subdirectory) + { + // we skip free nodes + case FREE_NODE: + break; + + case SUBALLOC_NODE: + retCode = HashDirectoryRecord(volume, &dos[entry], DirNo); + if (retCode) + { + NWFSPrint("nwfs: error hashing directory block (suballoc)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + break; + + case TRUSTEE_NODE: + trustee = (TRUSTEE *) &dos[entry]; + if (owner == (ULONG) -1) + { + owner = trustee->Subdirectory; + } + else + if (owner != trustee->Subdirectory) + { + NWFSPrint("nwfs: quota record not in assigned directory block\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + retCode = HashDirectoryRecord(volume, &dos[entry], DirNo); + if (retCode) + { + NWFSPrint("nwfs: error hashing directory block (trustee)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + break; + + case RESTRICTION_NODE: + user = (USER *) &dos[entry]; + if (owner == (ULONG) -1) + { + owner = user->Subdirectory; + } + else + if (owner != user->Subdirectory) + { + NWFSPrint("nwfs: quota record not in assigned directory block\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + retCode = HashDirectoryRecord(volume, &dos[entry], DirNo); + if (retCode) + { + NWFSPrint("nwfs: error hashing directory block (quota)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + break; + + case ROOT_NODE: + root = (ROOT *) &dos[entry]; + if (owner == (ULONG) -1) + owner = 0; + + retCode = HashDirectoryRecord(volume, &dos[entry], DirNo); + if (retCode) + { + NWFSPrint("nwfs: error hashing directory block (root)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + break; + + default: + if ((dos[entry].Flags & NW4_DELETED_FILE) || + (dos[entry].Flags & NW3_DELETED_FILE)) + { + if (owner == (ULONG) -1) + owner = (ULONG) -2; + else + if (owner != (ULONG) -2) + { + NWFSPrint("nwfs: deleted record not in assigned directory block\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + } + else + { + if (owner == (ULONG) -1) + owner = dos[entry].Subdirectory; + else + if (owner != dos[entry].Subdirectory) + { + NWFSPrint("nwfs(non-fatal): record not in assigned dir block DirNo-%X [%X/%X]\n", + (unsigned int) DirNo, + (unsigned int) owner, + (unsigned int) dos[entry].Subdirectory); + } + } + + retCode = HashDirectoryRecord(volume, &dos[entry], DirNo); + if (retCode) + { + NWFSPrint("nwfs: error hashing directory block (record)\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + break; + } + } + + // if we get here and owner is -1, then the entire block is + // filled with free entries. since we store it this way, + // the directory block free list can be accessed with a + // search value of -1; if owner is -2, then this block + // contains deleted files. + + // if the block is not completely free, record it as the + // last valid block number. + if (owner != (ULONG) -1) + volume->LastValidBlockNo = DirBlock; + + retCode = CreateDirAssignEntry(volume, owner, DirBlock, dos); + if (retCode) + { + NWFSPrint("nwfs: could not allocate Dir Block Assign element in ReadDirectory\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + volume->EndingBlockNo = DirBlock; + } + + if (FAT1->FATCluster == (ULONG) -1) + break; + + // if the other FAT chain terminated abruptly, exit the loop + + if (FAT2->FATCluster == (ULONG) -1) + break; + + if (!FAT1->FATCluster) + { + NWFSPrint("nwfs: Free Cluster detected in DIR1 Chain\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + if (!FAT2->FATCluster) + { + NWFSPrint("nwfs: Free Cluster detected in DIR2 Chain\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + if (FAT1->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in DIR1\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + if (FAT2->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: SubAlloc Node Detected in DIR2\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + DirIndex++; + cluster1 = FAT1->FATCluster; + cluster2 = FAT2->FATCluster; + + retCode = CreateDirBlockEntry(volume, cluster1, cluster2, DirIndex); + if (retCode) + { + NWFSPrint("nwfs: could not allocate Dir Block Hash element in ReadDirectory\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, Buffer1, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error Directory1 returned %d\n", (int)retCode); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, Buffer2, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSPrint("nwfs: Read Error Directory2 returned %d\n", (int)retCode); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadDirectoryTables\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + // index numbers should always be ascending. if we detect a + // non-ascending sequence, this indicates a corrupt FAT chain + + if (index1 > FAT1->FATIndex) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: DIR1 fat index overlaps on itself\n"); + return -1; + } + + if (index2 > FAT2->FATIndex) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: DIR2 fat index overlaps on itself\n"); + return -1; + } + + // update FAT index number for chains + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + } + + if (FAT1->FATCluster != FAT2->FATCluster) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: Directory FAT chain mirror mismatch\n"); + return -3; + } + + // record ending cluster and index values for directory + volume->EndingDirCluster1 = cluster1; + volume->EndingDirCluster2 = cluster2; + volume->EndingDirIndex = FAT1->FATIndex; + + NWFSFree(Buffer1); + NWFSFree(Buffer2); + + return 0; + +} + + +// +// +// + +ULONG InitializeDirBlockHash(VOLUME *volume) +{ + volume->DirListBlocks = 0; + volume->DirBlockHash = NWFSCacheAlloc(DIR_BLOCK_HASH_SIZE, + DIR_BLOCKHASH_TAG); + + if (!volume->DirBlockHash) + return -1; + + volume->DirBlockHashLimit = NUMBER_OF_DIR_BLOCK_ENTRIES; + NWFSSet(volume->DirBlockHash, 0, DIR_BLOCK_HASH_SIZE); + + return 0; +} + +ULONG CreateDirBlockEntry(VOLUME *volume, ULONG cluster, + ULONG mirror, ULONG index) +{ + register DIR_BLOCK_HASH *hash; + register ULONG retCode; + + hash = (DIR_BLOCK_HASH *) NWFSAlloc(sizeof(DIR_BLOCK_HASH), DIR_BLOCK_TAG); + if (hash) + { + NWFSSet(hash, 0, sizeof(DIR_BLOCK_HASH)); + hash->Cluster1 = cluster; + hash->Cluster2 = mirror; + hash->BlockNo = index; + + retCode = AddToDirBlockHash(volume, hash); + if (retCode) + { + NWFSFree(hash); + return -1; + } + + retCode = SetAssignedClusterValue(volume, cluster, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set cluster-%X\n", + (unsigned int)cluster); + } + + retCode = SetAssignedClusterValue(volume, mirror, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set mirror-%X\n", + (unsigned int)mirror); + } + + return 0; + } + return -1; + +} + +ULONG FreeDirBlockHash(VOLUME *volume) +{ + register DIR_BLOCK_HASH_LIST *HashTable; + register DIR_BLOCK_HASH *list, *hash; + register ULONG count; + + if (volume->DirBlockHash) + { + NWLockDirBlock(volume); + HashTable = (DIR_BLOCK_HASH_LIST *) volume->DirBlockHash; + for (count=0; count < volume->DirBlockHashLimit; count++) + { + + list = (DIR_BLOCK_HASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].head = 0; + while (list) + { + hash = list; + list = list->next; + NWFSFree(hash); + } + + } + NWUnlockDirBlock(volume); + } + + if (volume->DirBlockHash) + NWFSFree(volume->DirBlockHash); + volume->DirBlockHashLimit = 0; + volume->DirBlockHash = 0; + + return 0; + +} + +ULONG AddToDirBlockHash(VOLUME *volume, DIR_BLOCK_HASH *dblock) +{ + register ULONG hash; + register DIR_BLOCK_HASH_LIST *HashTable; + + hash = (dblock->BlockNo & (volume->DirBlockHashLimit - 1)); + HashTable = (DIR_BLOCK_HASH_LIST *) volume->DirBlockHash; + if (HashTable) + { + NWLockDirBlock(volume); + if (!HashTable[hash].head) + { + HashTable[hash].head = dblock; + HashTable[hash].tail = dblock; + dblock->next = dblock->prior = 0; + } + else + { + HashTable[hash].tail->next = dblock; + dblock->next = 0; + dblock->prior = HashTable[hash].tail; + HashTable[hash].tail = dblock; + } + NWUnlockDirBlock(volume); + return 0; + } + return -1; +} + +ULONG RemoveDirBlockHash(VOLUME *volume, DIR_BLOCK_HASH *dblock) +{ + register ULONG hash; + register DIR_BLOCK_HASH_LIST *HashTable; + + hash = (dblock->BlockNo & (volume->DirBlockHashLimit - 1)); + HashTable = (DIR_BLOCK_HASH_LIST *) volume->DirBlockHash; + if (HashTable) + { + NWLockDirBlock(volume); + if (HashTable[hash].head == dblock) + { + HashTable[hash].head = dblock->next; + if (HashTable[hash].head) + HashTable[hash].head->prior = NULL; + else + HashTable[hash].tail = NULL; + } + else + { + dblock->prior->next = dblock->next; + if (dblock != HashTable[hash].tail) + dblock->next->prior = dblock->prior; + else + HashTable[hash].tail = dblock->prior; + } + NWUnlockDirBlock(volume); + return 0; + } + return -1; +} + +ULONG IndexDeletedBlock(VOLUME *volume, DIR_BLOCK_HASH *dblock) +{ + DIR_BLOCK_HASH *old, *p; + + if (!volume->dblock_tail) + { + volume->dblock_head = dblock; + volume->dblock_tail = dblock; + dblock->dnext = dblock->dprior = 0; + } + else + { + p = volume->dblock_head; + old = NULL; + while (p) + { + if (p->DelBlockNo == dblock->DelBlockNo) + { + NWFSPrint("duplicate deleted block sequence number detected\n"); + return -1; + } + else + if (p->DelBlockNo < dblock->DelBlockNo) + { + old = p; + p = p->dnext; + } + else + { + if (p->dprior) + { + p->dprior->dnext = dblock; + dblock->dnext = p; + dblock->dprior = p->dprior; + p->dprior = dblock; + goto dblock_inserted; + } + dblock->dnext = p; + dblock->dprior = NULL; + p->dprior = dblock; + volume->dblock_head = dblock; + goto dblock_inserted; + } + } + old->dnext = dblock; + dblock->dnext = NULL; + dblock->dprior = old; + volume->dblock_tail = dblock; + } + +dblock_inserted:; + + return 0; +} + +ULONG AddDeletedBlock(VOLUME *volume, DIR_BLOCK_HASH *dblock) +{ + NWLockDirBlock(volume); + if (!volume->dblock_head) + { + volume->dblock_head = dblock; + volume->dblock_tail = dblock; + dblock->dnext = dblock->dprior = 0; + } + else + { + volume->dblock_tail->dnext = dblock; + dblock->dnext = 0; + dblock->dprior = volume->dblock_tail; + volume->dblock_tail = dblock; + } + NWUnlockDirBlock(volume); + return 0; +} + +ULONG RemoveDeletedBlock(VOLUME *volume, DIR_BLOCK_HASH *dblock) +{ + NWLockDirBlock(volume); + if (volume->dblock_head == dblock) + { + volume->dblock_head = dblock->dnext; + if (volume->dblock_head) + volume->dblock_head->dprior = NULL; + else + volume->dblock_tail = NULL; + } + else + { + dblock->dprior->dnext = dblock->dnext; + if (dblock != volume->dblock_tail) + dblock->dnext->dprior = dblock->dprior; + else + volume->dblock_tail = dblock->dprior; + } + NWUnlockDirBlock(volume); + return 0; +} + +// +// +// + +ULONG InitializeDirAssignHash(VOLUME *volume) +{ + volume->DirAssignBlocks = 0; + volume->DirAssignHash = NWFSCacheAlloc(ASSIGN_BLOCK_HASH_SIZE, + ASSN_BLOCKHASH_TAG); + + if (!volume->DirAssignHash) + return -1; + + volume->DirAssignHashLimit = NUMBER_OF_ASSIGN_BLOCK_ENTRIES; + NWFSSet(volume->DirAssignHash, 0, ASSIGN_BLOCK_HASH_SIZE); + + return 0; +} + +ULONG CreateDirAssignEntry(VOLUME *volume, ULONG Parent, ULONG BlockNo, + DOS *dos) +{ + register ULONG DirsPerBlock; + register DIR_ASSIGN_HASH *hash; + register ULONG retCode, i; + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + + hash = NWFSAlloc(sizeof(DIR_ASSIGN_HASH), ASSN_BLOCK_TAG); + if (hash) + { + NWFSSet(hash, 0, sizeof(DIR_ASSIGN_HASH)); + + hash->DirOwner = Parent; + hash->BlockNo = BlockNo; + + for (i=0; i < DirsPerBlock; i++) + { + switch (dos[i].Subdirectory) + { + case FREE_NODE: + hash->FreeList[i >> 3] &= ~(1 << (i & 7)); + break; + + case SUBALLOC_NODE: + case TRUSTEE_NODE: + case RESTRICTION_NODE: + case ROOT_NODE: + hash->FreeList[i >> 3] |= (1 << (i & 7)); + break; + + default: + hash->FreeList[i >> 3] |= (1 << (i & 7)); + break; + } + } + + retCode = AddToDirAssignHash(volume, hash); + if (retCode) + { + NWFSFree(hash); + return -1; + } + return 0; + } + return -1; + +} + +ULONG FreeDirAssignHash(VOLUME *volume) +{ + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list, *hash; + register ULONG count; + + if (volume->DirAssignHash) + { + NWLockDirAssign(volume); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + for (count=0; count < volume->DirAssignHashLimit; count++) + { + list = (DIR_ASSIGN_HASH *) HashTable[count].head; + HashTable[count].head = HashTable[count].head = 0; + while (list) + { + hash = list; + list = list->next; + + if (hash->DirOwner == (ULONG) -1) + if (volume->FreeDirectoryBlockCount) + volume->FreeDirectoryBlockCount--; + + NWFSFree(hash); + } + } + NWUnlockDirAssign(volume); + } + + if (volume->DirAssignHash) + NWFSFree(volume->DirAssignHash); + volume->DirAssignHashLimit = 0; + volume->DirAssignHash = 0; + + return 0; + +} + +ULONG AddToDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock) +{ + register ULONG hash; + register DIR_ASSIGN_HASH_LIST *HashTable; + + hash = (dblock->DirOwner & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (HashTable) + { + NWLockDirAssign(volume); + if (!HashTable[hash].head) + { + HashTable[hash].head = dblock; + HashTable[hash].tail = dblock; + dblock->next = dblock->prior = 0; + } + else + { + HashTable[hash].tail->next = dblock; + dblock->next = 0; + dblock->prior = HashTable[hash].tail; + HashTable[hash].tail = dblock; + } + + if (dblock->DirOwner == (ULONG) -1) + volume->FreeDirectoryBlockCount++; + + NWUnlockDirAssign(volume); + return 0; + } + return -1; +} + +ULONG RemoveDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock) +{ + register ULONG hash; + register DIR_ASSIGN_HASH_LIST *HashTable; + + hash = (dblock->DirOwner & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (HashTable) + { + NWLockDirAssign(volume); + if (HashTable[hash].head == dblock) + { + HashTable[hash].head = dblock->next; + if (HashTable[hash].head) + HashTable[hash].head->prior = NULL; + else + HashTable[hash].tail = NULL; + } + else + { + dblock->prior->next = dblock->next; + if (dblock != HashTable[hash].tail) + dblock->next->prior = dblock->prior; + else + HashTable[hash].tail = dblock->prior; + } + + if (dblock->DirOwner == (ULONG) -1) + if (volume->FreeDirectoryBlockCount) + volume->FreeDirectoryBlockCount--; + + NWUnlockDirAssign(volume); + return 0; + } + return -1; +} + +ULONG AddToDirAssignHashNoLock(VOLUME *volume, DIR_ASSIGN_HASH *dblock) +{ + register ULONG hash; + register DIR_ASSIGN_HASH_LIST *HashTable; + + hash = (dblock->DirOwner & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (HashTable) + { + if (!HashTable[hash].head) + { + HashTable[hash].head = dblock; + HashTable[hash].tail = dblock; + dblock->next = dblock->prior = 0; + } + else + { + HashTable[hash].tail->next = dblock; + dblock->next = 0; + dblock->prior = HashTable[hash].tail; + HashTable[hash].tail = dblock; + } + + if (dblock->DirOwner == (ULONG) -1) + volume->FreeDirectoryBlockCount++; + + return 0; + } + return -1; +} + +ULONG RemoveDirAssignHashNoLock(VOLUME *volume, DIR_ASSIGN_HASH *dblock) +{ + register ULONG hash; + register DIR_ASSIGN_HASH_LIST *HashTable; + + hash = (dblock->DirOwner & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (HashTable) + { + if (HashTable[hash].head == dblock) + { + HashTable[hash].head = dblock->next; + if (HashTable[hash].head) + HashTable[hash].head->prior = NULL; + else + HashTable[hash].tail = NULL; + } + else + { + dblock->prior->next = dblock->next; + if (dblock != HashTable[hash].tail) + dblock->next->prior = dblock->prior; + else + HashTable[hash].tail = dblock->prior; + } + + if (dblock->DirOwner == (ULONG) -1) + if (volume->FreeDirectoryBlockCount) + volume->FreeDirectoryBlockCount--; + + return 0; + } + return -1; +} + +ULONG AllocateDirectoryRecord(VOLUME *volume, ULONG Parent) +{ + register ULONG hash, i, DirsPerBlock, DirNo, DirsPerCluster; + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list; + register VOLUME_WORKSPACE *WorkSpace; + register BYTE *cBuffer; + register ULONG cbytes, vindex, retCode, block, BlockNo; + register long cluster1, cluster2; + register DOS *dos; + ULONG retRCode; + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + + hash = (Parent & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + { + register ULONG dirOwner, dirFileSize, dirBlocks, dirTotal, j; + register ULONG FoundFreeRecord; + register TRUSTEE *trustee; + register USER *user; + register ROOT *root; + + NWFSPrint("accessing raw directory mode\n"); + + // we go ahead and allocate a full cluster of storage just in + // case we need to extend the directory file; + + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + return -1; + cBuffer = &WorkSpace->Buffer[0]; + + // get directory file size + dirFileSize = GetChainSize(volume, volume->FirstDirectory); + dirBlocks = (dirFileSize + (volume->BlockSize - 1)) / volume->BlockSize; + dirTotal = (dirFileSize + (sizeof(DOS) - 1)) / sizeof(DOS); + + // scan each block until we find either the proper parent + // directory block or we encounter a free block in the + // dir file. + + for (j=0; j < dirBlocks; j++) + { + cbytes = NWReadFile(volume, + &volume->FirstDirectory, + 0, + dirFileSize, + j * volume->BlockSize, + cBuffer, + volume->BlockSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0, + TRUE); + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error reading directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // scan through this directory block + for (FoundFreeRecord = dirOwner = (ULONG) -1, i=0; + i < DirsPerBlock; i++) + { + dos = (DOS *) &cBuffer[i * sizeof(DOS)]; + switch (dos->Subdirectory) + { + // root is owned by directory (0) + case ROOT_NODE: + root = (ROOT *) dos; + if (dirOwner == (ULONG) -1) + dirOwner = 0; + break; + + // suballoc nodes are owned by the root (0) + case SUBALLOC_NODE: + if (dirOwner == (ULONG) -1) + dirOwner = 0; + break; + + case FREE_NODE: + // remember the first free record found on this + // block. + if (FoundFreeRecord == (ULONG) -1) + FoundFreeRecord = i; + break; + + case RESTRICTION_NODE: + user = (USER *) dos; + if (dirOwner == (ULONG) -1) + dirOwner = user->Subdirectory; + break; + + case TRUSTEE_NODE: + trustee = (TRUSTEE *) dos; + if (dirOwner == (ULONG) -1) + dirOwner = trustee->Subdirectory; + break; + + default: + if (dirOwner == (ULONG) -1) + dirOwner = dos->Subdirectory; + break; + } + } + + // if there was a free record found, then return its directory + // number + if (FoundFreeRecord != (ULONG) -1) + { + // The entire block is free. return first element. + if (dirOwner == (ULONG) -1) + { + dos = (DOS *) cBuffer; + dos->Subdirectory = Parent; + + cbytes = NWWriteFile(volume, + &volume->FirstDirectory, + 0, + j * volume->BlockSize, + cBuffer, + volume->BlockSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error writing directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + cbytes = NWWriteFile(volume, + &volume->SecondDirectory, + 0, + j * volume->BlockSize, + cBuffer, + volume->BlockSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error writing directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + FreeWorkspace(volume, WorkSpace); + return (j * DirsPerBlock); + } + else + if (dirOwner == Parent) + { + dos = (DOS *) &cBuffer[FoundFreeRecord * sizeof(DOS)]; + dos->Subdirectory = Parent; + + cbytes = NWWriteFile(volume, + &volume->FirstDirectory, + 0, + j * volume->BlockSize, + cBuffer, + volume->BlockSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error writing directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + cbytes = NWWriteFile(volume, + &volume->SecondDirectory, + 0, + j * volume->BlockSize, + cBuffer, + volume->BlockSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error writing directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + FreeWorkspace(volume, WorkSpace); + return ((j * DirsPerBlock) + FoundFreeRecord); + } + } + } + + // if we get here, then we need to extend the directory file + // by one cluster and fill this cluster with free entries because + // the entire directory file is full. + + // fill cluster buffer with free directory record entries. + NWFSSet(cBuffer, 0, volume->ClusterSize); + for (i=0; i < (volume->ClusterSize / sizeof(DOS)); i++) + { + dos = (DOS *) &cBuffer[i * sizeof(DOS)]; + if (!i) + dos->Subdirectory = Parent; // assign first record + else + dos->Subdirectory = (ULONG) -1; + } + + // write free cluster to the end of the primary directory chain + cbytes = NWWriteFile(volume, + &volume->FirstDirectory, + 0, + dirBlocks * volume->BlockSize, + cBuffer, + volume->ClusterSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->ClusterSize) + { + NWFSPrint("nwfs: error extending primary directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // write free cluster to the end of the mirror directory chain + cbytes = NWWriteFile(volume, + &volume->SecondDirectory, + 0, + dirBlocks * volume->BlockSize, + cBuffer, + volume->ClusterSize, + 0, + 0, + &retRCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + if (cbytes != volume->ClusterSize) + { + NWFSPrint("nwfs: error extending mirror directory file\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + FreeWorkspace(volume, WorkSpace); + return (dirBlocks * DirsPerBlock); + } + + + + NWLockDirAssign(volume); + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == Parent) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list, set it + // then return the allocated DirNo + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + list->FreeList[i >> 3] |= (1 << (i & 7)); + DirNo = ((DirsPerBlock * list->BlockNo) + i); + + NWUnlockDirAssign(volume); + return DirNo; + } + } + } + list = list->next; + } + + // if we got here, then we could not locate an assigned directory + // block with available entries. at this point, we scan the free + // list hash (-1) and search free directory blocks for available + // entries. if we find a free block, then we assign this + // dir block as owned by the specified parent. + + hash = ((ULONG)FREE_NODE & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + { + NWUnlockDirAssign(volume); + return -1; + } + + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == FREE_NODE) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list, set it + // then return the allocated DirNo + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + // set directory entry as allocated + list->FreeList[i >> 3] |= (1 << (i & 7)); + + // re-hash block assign record to reflect + // new parent + RemoveDirAssignHashNoLock(volume, list); + list->DirOwner = Parent; + AddToDirAssignHashNoLock(volume, list); + + // calculate and return directory number + DirNo = ((DirsPerBlock * list->BlockNo) + i); + + NWUnlockDirAssign(volume); + return DirNo; + } + } + } + list = list->next; + } + NWUnlockDirAssign(volume); + + // if we got here, then the directory is completely full, and we need + // to extend the directory by allocating another cluster for both the + // primary and mirror copies of the directory. + + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + return -1; + cBuffer = &WorkSpace->Buffer[0]; + + // initialize new cluster and fill with free directory + // entries + NWFSSet(cBuffer, 0, volume->ClusterSize); + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + for (i=0; i < DirsPerCluster; i++) + { + dos = (DOS *) &cBuffer[i * sizeof(ROOT)]; + dos->Subdirectory = FREE_NODE; + } + + // modifying global data, lock the volume structure + NWLockVolume(volume); + + // set vindex to next cluster index + vindex = volume->EndingDirIndex + 1; + + // allocate cluster for primary directory. we try to get both clusters + // first before we start modifying the dir fat chain just in case we + // run out of disk space. this makes error handling and unwinding of + // a failed create much easier. + + cluster1 = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (cluster1 == -1) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // allocate cluster for mirrored directory + cluster2 = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (cluster2 == -1) + { + NWUnlockVolume(volume); + FreeCluster(volume, cluster1); // free the cluster + FreeWorkspace(volume, WorkSpace); + return -1; + } + +#if (ZERO_FILL_SECTORS) + ZeroPhysicalVolumeCluster(volume, cluster1, DIRECTORY_PRIORITY); + ZeroPhysicalVolumeCluster(volume, cluster2, DIRECTORY_PRIORITY); +#endif + + + // now write both newly allocated clusters with a pre-initialized + // cluster of free directory records. if either write fails, then + // free both clusters. we have not spliced them into the dir fat + // chain as of yet. + + cbytes = WriteClusterWithOffset(volume, cluster1, 0, cBuffer, + volume->ClusterSize, KERNEL_ADDRESS_SPACE, + &retRCode, DIRECTORY_PRIORITY); + if (cbytes != volume->ClusterSize) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + FreeCluster(volume, cluster1); + FreeCluster(volume, cluster2); + return -1; + } + + cbytes = WriteClusterWithOffset(volume, cluster2, 0, cBuffer, + volume->ClusterSize, KERNEL_ADDRESS_SPACE, + &retRCode, DIRECTORY_PRIORITY); + if (cbytes != volume->ClusterSize) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + FreeCluster(volume, cluster1); + FreeCluster(volume, cluster2); + return -1; + } + + // success, now we can link both the primary and mirrored + // directory fat chains to point to these new clusters. + + if (volume->EndingDirCluster1 == (ULONG)-1) + volume->FirstDirectory = cluster1; + else + SetClusterValue(volume, volume->EndingDirCluster1, cluster1); + + if (volume->EndingDirCluster2 == (ULONG)-1) + volume->SecondDirectory = cluster2; + else + SetClusterValue(volume, volume->EndingDirCluster2, cluster2); + + // update ending cluster and ending index values + volume->EndingDirCluster1 = cluster1; + volume->EndingDirCluster2 = cluster2; + volume->EndingDirIndex = vindex; + + // at this point, we have successfully extended both the primary and + // mirrored directories. now we update in memory meta-data and hash + // structures to reflect the changes to the directory file. + + retCode = CreateDirBlockEntry(volume, cluster1, cluster2, vindex); + if (retCode) + { + NWUnlockVolume(volume); + NWFSPrint("nwfs: could not allocate dir block during dir extend\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // set BlockNo to the next logical block number + BlockNo = volume->EndingBlockNo + 1; + for (block=0; block < volume->BlocksPerCluster; block++, BlockNo++) + { + dos = (DOS *) &cBuffer[block * volume->BlockSize]; + retCode = CreateDirAssignEntry(volume, FREE_NODE, BlockNo, dos); + if (retCode) + { + NWUnlockVolume(volume); + NWFSPrint("nwfs: could not allocate dir block Assign element during extend\n"); + FreeWorkspace(volume, WorkSpace); + return -1; + } + volume->EndingBlockNo = BlockNo; // save the new ending block number + } + + NWUnlockVolume(volume); + + // free the workspace + FreeWorkspace(volume, WorkSpace); + + // now try to scan the free list hash (-1) and search free + // directory blocks for available entries. if we find a free + // block (we'd better, we just created one above), then we mark + // this dir block as owned by the specified parent. we should + // never get here unless we successfully extended the directory file. + + hash = ((ULONG)FREE_NODE & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + return -1; + + NWLockDirAssign(volume); + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == FREE_NODE) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list, set it + // then return the allocated DirNo + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + // set directory entry as allocated + list->FreeList[i >> 3] |= (1 << (i & 7)); + + // re-hash block assign record to reflect + // new parent + RemoveDirAssignHashNoLock(volume, list); + list->DirOwner = Parent; + AddToDirAssignHashNoLock(volume, list); + + // calculate and return directory number + DirNo = ((DirsPerBlock * list->BlockNo) + i); + + NWUnlockDirAssign(volume); + return DirNo; + } + } + } + list = list->next; + } + NWUnlockDirAssign(volume); + return -1; + +} + +ULONG FreeDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo, + ULONG Parent) +{ + register ULONG hash, i, count, SubdirNo; + register ULONG DirsPerBlock, DirsPerCluster; + register ULONG DirIndex, DirBlockNo; + register ULONG retCode; + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list; + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + DirBlockNo = DirNo / DirsPerBlock; + DirIndex = DirNo % DirsPerBlock; + + hash = ((ULONG)Parent & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + + if (!HashTable) + return NwHashCorrupt; + + NWLockDirAssign(volume); + + SubdirNo = Parent; + NWFSSet(dos, 0, sizeof(ROOT)); + dos->Subdirectory = FREE_NODE; // mark node free + + retCode = WriteDirectoryRecord(volume, dos, DirNo); + if (retCode) + { + NWUnlockDirAssign(volume); + NWFSPrint("nwfs: error in directory write (%d)\n", (int)retCode); + return retCode; + } + + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if ((list->BlockNo == DirBlockNo) && + (list->DirOwner == Parent)) + { + // free directory record + list->FreeList[DirIndex >> 3] &= ~(1 << (DirIndex & 7)); + + // see if this block has any allocated dir entries, if so + // then exit, otherwise, re-hash the block into the + // free list + + for (i=0; i < DirsPerBlock; i++) + { + // check for allocated entries + if (((list->FreeList[i >> 3]) >> (i & 7)) & 1) + { + NWUnlockDirAssign(volume); + return 0; + } + } + + // if we get here the we assume that the entire directory + // block is now free. we remove this block from the + // previous assigned parent hash, then re-hash it into the + // directory free list (-1) + + RemoveDirAssignHashNoLock(volume, list); + list->DirOwner = FREE_NODE; + AddToDirAssignHashNoLock(volume, list); + + NWUnlockDirAssign(volume); + return 0; + } + list = list->next; + } + + // if we could not locate the directory entry, then perform + // a brute force search of the record in all of the parent + // assign hash records. Netware does allow parent records + // to be mixed within a single block in rare circumstances. + // this should rarely happen, however, and if it ever does + // it indicates possible directory corruption. In any case, + // even if the directory is corrupt, we should allow folks + // the ability to purge these records. + + for (count=0; count < volume->DirAssignHashLimit; count++) + { + list = (DIR_ASSIGN_HASH *) HashTable[count].head; + while (list) + { + if (list->BlockNo == DirBlockNo) + { + NWFSPrint("nwfs: record freed in non-assigned parent block [%X/%X]\n", + (unsigned int)SubdirNo, + (unsigned int)list->DirOwner); + + // free directory record + list->FreeList[DirIndex >> 3] &= ~(1 << (DirIndex & 7)); + + // see if this block has any allocated dir entries, if so + // then exit, otherwise, re-hash the block into the + // free list + + for (i=0; i < DirsPerBlock; i++) + { + // check for allocated entries + if (((list->FreeList[i >> 3]) >> (i & 7)) & 1) + { + NWUnlockDirAssign(volume); + return 0; + } + } + + // if we get here the we assume that the entire directory + // block is now free. we remove this block from the + // previous assigned parent hash, then re-hash it into the + // directory free list (-1) + + RemoveDirAssignHashNoLock(volume, list); + list->DirOwner = FREE_NODE; + AddToDirAssignHashNoLock(volume, list); + + NWUnlockDirAssign(volume); + return 0; + } + list = list->next; + } + } + + NWUnlockDirAssign(volume); + return 0; + +} + +ULONG ReleaseDirectoryRecord(VOLUME *volume, ULONG DirNo, ULONG Parent) +{ + register ULONG hash, i, count; + register ULONG DirsPerBlock, DirsPerCluster; + register ULONG DirIndex, DirBlockNo; + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list; + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + DirBlockNo = DirNo / DirsPerBlock; + DirIndex = DirNo % DirsPerBlock; + + hash = ((ULONG)Parent & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + + if (!HashTable) + return NwHashCorrupt; + + NWLockDirAssign(volume); + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if ((list->BlockNo == DirBlockNo) && + (list->DirOwner == Parent)) + { + // free directory record + list->FreeList[DirIndex >> 3] &= ~(1 << (DirIndex & 7)); + + // see if this block has any allocated dir entries, if so + // then exit, otherwise, re-hash the block into the + // free list + + for (i=0; i < DirsPerBlock; i++) + { + // check for allocated entries + // if we find an allocated record, then exit + if (((list->FreeList[i >> 3]) >> (i & 7)) & 1) + { + NWUnlockDirAssign(volume); + return 0; + } + } + + // if we get here the we assume that the entire directory + // block is now free. we remove this block from the + // previous assigned parent hash, then re-hash it into the + // directory free list (-1) + + RemoveDirAssignHashNoLock(volume, list); + list->DirOwner = FREE_NODE; + AddToDirAssignHashNoLock(volume, list); + + NWUnlockDirAssign(volume); + return 0; + } + list = list->next; + } + + // if we could not locate the directory entry, then perform + // a brute force search of the record in all of the parent + // assign hash records. Netware does allow parent records + // to be mixed within a single block in rare circumstances. + // this should rarely happen, however, and if it ever does + // it indicates possible directory corruption. In any case, + // even if the directory is corrupt, we should allow folks + // the ability to purge these records. + + for (count=0; count < volume->DirAssignHashLimit; count++) + { + list = (DIR_ASSIGN_HASH *) HashTable[count].head; + while (list) + { + if (list->BlockNo == DirBlockNo) + { + NWFSPrint("nwfs: record freed in non-assigned parent block [%X/%X]\n", + (unsigned int)Parent, + (unsigned int)list->DirOwner); + + // free directory record + list->FreeList[DirIndex >> 3] &= ~(1 << (DirIndex & 7)); + + // see if this block has any allocated dir entries, if so + // then exit, otherwise, re-hash the block into the + // free list + + for (i=0; i < DirsPerBlock; i++) + { + // check for allocated entries + // if we find an allocated record, then exit + if (((list->FreeList[i >> 3]) >> (i & 7)) & 1) + { + NWUnlockDirAssign(volume); + return 0; + } + } + + // if we get here the we assume that the entire directory + // block is now free. we remove this block from the + // previous assigned parent hash, then re-hash it into the + // directory free list (-1) + + RemoveDirAssignHashNoLock(volume, list); + list->DirOwner = FREE_NODE; + AddToDirAssignHashNoLock(volume, list); + + NWUnlockDirAssign(volume); + return 0; + } + list = list->next; + } + } + NWUnlockDirAssign(volume); + return NwNoEntry; +} + +// This function pre-allocates a cluster of free directory records +// then creates an assignment hash and a block hash for the blocks +// that make up this cluster. + +ULONG PreAllocateFreeDirectoryRecords(VOLUME *volume) +{ + register ULONG hash, i, DirsPerBlock, DirsPerCluster; + register DIR_ASSIGN_HASH_LIST *HashTable; + register DIR_ASSIGN_HASH *list; + register VOLUME_WORKSPACE *WorkSpace; + register BYTE *cBuffer; + register ULONG cbytes, vindex, retCode, block, BlockNo; + register long cluster1, cluster2; + register DOS *dos; + ULONG retRCode; + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + hash = ((ULONG)FREE_NODE & (volume->DirAssignHashLimit - 1)); + HashTable = (DIR_ASSIGN_HASH_LIST *) volume->DirAssignHash; + if (!HashTable) + return -1; + + NWLockDirAssign(volume); + list = (DIR_ASSIGN_HASH *) HashTable[hash].head; + while (list) + { + if (list->DirOwner == FREE_NODE) + { + for (i=0; i < DirsPerBlock; i++) + { + // if we locate a free entry in the bit list + // then return + if (!(((list->FreeList[i >> 3]) >> (i & 7)) & 1)) + { + NWUnlockDirAssign(volume); + return 0; + } + } + } + list = list->next; + } + NWUnlockDirAssign(volume); + + // no free directory space left, allocate a new cluster for the free list + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + return -1; + cBuffer = &WorkSpace->Buffer[0]; + + // initialize new cluster and fill with free directory entries + NWFSSet(cBuffer, 0, volume->ClusterSize); + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + for (i=0; i < DirsPerCluster; i++) + { + dos = (DOS *) &cBuffer[i * sizeof(ROOT)]; + dos->Subdirectory = FREE_NODE; + } + + // modifying global data, lock the volume structure + NWLockVolume(volume); + + // set vindex to next cluster index + vindex = volume->EndingDirIndex + 1; + + // allocate cluster for primary directory. we try to get both clusters + // first before we start modifying the dir fat chain just in case we + // run out of disk space. this makes error handling and unwinding of + // a failed create much easier. + + cluster1 = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (cluster1 == -1) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // allocate cluster for mirrored directory + cluster2 = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (cluster2 == -1) + { + NWUnlockVolume(volume); + FreeCluster(volume, cluster1); // free the cluster + FreeWorkspace(volume, WorkSpace); + return -1; + } + +#if (ZERO_FILL_SECTORS) + ZeroPhysicalVolumeCluster(volume, cluster1, DIRECTORY_PRIORITY); + ZeroPhysicalVolumeCluster(volume, cluster2, DIRECTORY_PRIORITY); +#endif + + // now write both newly allocated clusters with a pre-initialized + // cluster of free directory records. if either write fails, then + // free both clusters. we have not spliced them into the dir fat + // chain as of yet. + + cbytes = WriteClusterWithOffset(volume, cluster1, 0, cBuffer, + volume->ClusterSize, KERNEL_ADDRESS_SPACE, + &retRCode, DIRECTORY_PRIORITY); + if (cbytes != volume->ClusterSize) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + FreeCluster(volume, cluster1); + FreeCluster(volume, cluster2); + return -1; + } + + cbytes = WriteClusterWithOffset(volume, cluster2, 0, cBuffer, + volume->ClusterSize, KERNEL_ADDRESS_SPACE, + &retRCode, DIRECTORY_PRIORITY); + if (cbytes != volume->ClusterSize) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + FreeCluster(volume, cluster1); + FreeCluster(volume, cluster2); + return -1; + } + + // success, now we can link both the primary and mirrored + // directory fat chains to point to these new clusters. + + if (volume->EndingDirCluster1 == (ULONG)-1) + volume->FirstDirectory = cluster1; + else + SetClusterValue(volume, volume->EndingDirCluster1, cluster1); + + if (volume->EndingDirCluster2 == (ULONG)-1) + volume->SecondDirectory = cluster2; + else + SetClusterValue(volume, volume->EndingDirCluster2, cluster2); + + // update ending cluster and ending index values + volume->EndingDirCluster1 = cluster1; + volume->EndingDirCluster2 = cluster2; + volume->EndingDirIndex = vindex; + + // at this point, we have successfully extended both the primary and + // mirrored directories. now we update in memory meta-data and hash + // structures to reflect the changes to the directory file. + + retCode = CreateDirBlockEntry(volume, cluster1, cluster2, vindex); + if (retCode) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // set BlockNo to the next logical block number + BlockNo = volume->EndingBlockNo + 1; + for (block=0; block < volume->BlocksPerCluster; block++, BlockNo++) + { + dos = (DOS *) &cBuffer[block * volume->BlockSize]; + retCode = CreateDirAssignEntry(volume, FREE_NODE, BlockNo, dos); + if (retCode) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + volume->EndingBlockNo = BlockNo; // save the new ending block number + } + + NWUnlockVolume(volume); + + // free the workspace + FreeWorkspace(volume, WorkSpace); + + return 0; +} + +// This function pre-allocates a cluster of free directory records +// but does not create any assignment or block hash records. + +ULONG PreAllocateEmptyDirectorySpace(VOLUME *volume) +{ + register ULONG i, DirsPerCluster; + register VOLUME_WORKSPACE *WorkSpace; + register BYTE *cBuffer; + register ULONG cbytes, vindex, retCode, block, BlockNo; + register long cluster1, cluster2; + register DOS *dos; + ULONG retRCode; + + // allocate a new cluster for the free list + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + return -1; + cBuffer = &WorkSpace->Buffer[0]; + + // initialize new cluster and fill with free directory entries + NWFSSet(cBuffer, 0, volume->ClusterSize); + + DirsPerCluster = volume->ClusterSize / sizeof(ROOT); + for (i=0; i < DirsPerCluster; i++) + { + dos = (DOS *) &cBuffer[i * sizeof(ROOT)]; + dos->Subdirectory = FREE_NODE; + } + + // modifying global data, lock the volume structure + NWLockVolume(volume); + + // set vindex to next cluster index + vindex = volume->EndingDirIndex + 1; + + // allocate cluster for primary directory. we try to get both clusters + // first before we start modifying the dir fat chain just in case we + // run out of disk space. this makes error handling and unwinding of + // a failed create much easier. + + cluster1 = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (cluster1 == -1) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // allocate cluster for mirrored directory + cluster2 = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (cluster2 == -1) + { + NWUnlockVolume(volume); + FreeCluster(volume, cluster1); // free the cluster + FreeWorkspace(volume, WorkSpace); + return -1; + } + +#if (ZERO_FILL_SECTORS) + ZeroPhysicalVolumeCluster(volume, cluster1, DIRECTORY_PRIORITY); + ZeroPhysicalVolumeCluster(volume, cluster2, DIRECTORY_PRIORITY); +#endif + + // now write both newly allocated clusters with a pre-initialized + // cluster of free directory records. if either write fails, then + // free both clusters. we have not spliced them into the dir fat + // chain as of yet. + + cbytes = WriteClusterWithOffset(volume, cluster1, 0, cBuffer, + volume->ClusterSize, KERNEL_ADDRESS_SPACE, + &retRCode, DIRECTORY_PRIORITY); + if (cbytes != volume->ClusterSize) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + FreeCluster(volume, cluster1); + FreeCluster(volume, cluster2); + return -1; + } + + cbytes = WriteClusterWithOffset(volume, cluster2, 0, cBuffer, + volume->ClusterSize, KERNEL_ADDRESS_SPACE, + &retRCode, DIRECTORY_PRIORITY); + if (cbytes != volume->ClusterSize) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + FreeCluster(volume, cluster1); + FreeCluster(volume, cluster2); + return -1; + } + + // success, now we can link both the primary and mirrored + // directory fat chains to point to these new clusters. + + if (volume->EndingDirCluster1 == (ULONG)-1) + volume->FirstDirectory = cluster1; + else + SetClusterValue(volume, volume->EndingDirCluster1, cluster1); + + if (volume->EndingDirCluster2 == (ULONG)-1) + volume->SecondDirectory = cluster2; + else + SetClusterValue(volume, volume->EndingDirCluster2, cluster2); + + // update ending cluster and ending index values + volume->EndingDirCluster1 = cluster1; + volume->EndingDirCluster2 = cluster2; + volume->EndingDirIndex = vindex; + + // at this point, we have successfully extended both the primary and + // mirrored directories. now we update in memory meta-data and hash + // structures to reflect the changes to the directory file. + + retCode = CreateDirBlockEntry(volume, cluster1, cluster2, vindex); + if (retCode) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + + // set BlockNo to the next logical block number + BlockNo = volume->EndingBlockNo + 1; + for (block=0; block < volume->BlocksPerCluster; block++, BlockNo++) + { + dos = (DOS *) &cBuffer[block * volume->BlockSize]; + retCode = CreateDirAssignEntry(volume, FREE_NODE, BlockNo, dos); + if (retCode) + { + NWUnlockVolume(volume); + FreeWorkspace(volume, WorkSpace); + return -1; + } + volume->EndingBlockNo = BlockNo; // save the new ending block number + } + + NWUnlockVolume(volume); + + // free the workspace + FreeWorkspace(volume, WorkSpace); + + return 0; +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwdir.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwdir.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwdir.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwdir.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,609 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWDIR.H +* DESCRIP : FENRIS On-Disk Directory Structures +* DATE : November 1, 1998 +* +* +***************************************************************************/ + + +#ifndef _NWFS_NWDIR_ +#define _NWFS_NWDIR_ + +/********************************************************************** +* +* Directory Control Flags +* +***********************************************************************/ + +#define FREE_NODE -1 +#define TRUSTEE_NODE -2 +#define ROOT_NODE -3 +#define RESTRICTION_NODE -4 +#define SUBALLOC_NODE -5 + +// deleted files belong to this directory +#define DELETED_DIRECTORY -2 + +/********************************************************************** +* +* Extended Directory Signatures +* +* NOTE: These values are documented in the SDK/HDK and were +* verified by debugging a live NetWare server File System. +* +***********************************************************************/ + +// NOTE: I haven't implemented all of the EA record types for the +// extended directory (but I do read and cache them into the ext +// directoty list) and I'm not certain they make much sense for +// linux at present, however, if users had stored OS2 files on +// a Netware server, then linux at least can provide the data, even +// though the EA way of doing things is probably obsolete these days. + +#define EXTENDED_DIR_STAMP 0x13579ACE // "black box" EA +#define LONG_EXTENDED_DIR_STAMP 0xABA12190 // holds extra name +#define NT_EXTENDED_DIR_STAMP 0x5346544E // holds extra name +#define NFS_EXTENDED_DIR_STAMP 0x554E4958 // holds extra name +#define MIGRATE_DIR_STAMP 0xAFDE5713 // points migrated file +#define TALLY_EXTENDED_DIR_STAMP 0x2E4E414A // "black box" EA +#define EXTENDED_ATTRIBUTE_DIR_STAMP 0x2E6E616A // "?????" OS2 specific + +/********************************************************************** +* +* Name Space Flag Settings +* +***********************************************************************/ + +#define DOS_NAME_SPACE 0 +#define MAC_NAME_SPACE 1 +#define UNIX_NAME_SPACE 2 +#define FTAM_NAME_SPACE 3 +#define LONG_NAME_SPACE 4 +#define NT_NAME_SPACE 5 + +/********************************************************************** +* +* File Attribute Flag Settings +* +* NOTE: Novell documented these flags in the SDK/HDK Kits for NetWare +* 4.11 and 5.x. +* +***********************************************************************/ + +#define READ_ONLY 0x00000001 +#define HIDDEN 0x00000002 +#define SYSTEM 0x00000004 +#define EXECUTE 0x00000008 +#define SUBDIRECTORY 0x00000010 +#define ARCHIVE 0x00000020 + +// warning!!! this attribute seems to mean something different depending +// on whether you are 3.x or 4.x. +#define SHAREABLE 0x00000080 +#define DIR_HIDDEN 0x00000080 + +#define SHARE_MODES 0x00000700 +#define NO_SUBALLOC 0x00000800 +#define TRANSACTION 0x00001000 +#define OLD_INDEXED 0x00002000 +#define READ_AUDIT 0x00004000 +#define WRITE_AUDIT 0x00008000 +#define IMMEDIATE_PURGE 0x00010000 +#define RENAME_INHIBIT 0x00020000 +#define DELETE_INHIBIT 0x00040000 +#define COPY_INHIBIT 0x00080000 +#define FILE_AUDITING 0x00100000 +#define CDS_CONTAINER 0x00200000 +#define REMOTE_DATA_ACCESS 0x00400000 +#define REMOTE_DATA_INHIBIT 0x00800000 +#define REMOTE_DATA_SAVE_KEY 0x01000000 +#define COMPRESS_FILE_IMMEDIATELY 0x02000000 +#define DATA_STREAM_IS_COMPRESSED 0x04000000 +#define DO_NOT_COMPRESS_FILE 0x08000000 +#define CANT_COMPRESS_DATA_STREAM 0x20000000 +#define ARCHIVE_FILE 0x40000000 + +/********************************************************************** +* +* Directory Entry Flag Settings +* +***********************************************************************/ + +// +// Netware provides several useful bit fields for storing Unix Style +// semantics, such as hardlinks, softlinks, and symbolic links. +// Some entries are ambiguous, but Netware also allows special +// "Phantom" files as well as deleted files. Note that Netware uses +// a different bit to distinguish between 4.x and 3.x deleted files +// (which seems broken to me). We make all Phantom files visible +// in the current implementation. +// + +#define NW3_DELETED_FILE 0x001 +#define PHANTOM_FILE 0x002 +#define SUBDIRECTORY_FILE 0x004 +#define NAMED_FILE 0x008 +#define PRIMARY_NAMESPACE 0x010 +#define NW4_DELETED_FILE 0x020 +#define HARD_LINKED_FILE 0x040 +#define SYMBOLIC_LINKED_FILE 0x080 +#define RAW_FILE 0x100 + +/********************************************************************** +* +* Volume Segment Flag Settings +* +***********************************************************************/ + +// Volume Table Flags Settings + +// bit that tells you wether this is a SYS volume or not +#define SYSTEM_VOLUME 0x01 +#define READ_ONLY_VOLUME 0x80 + +// Root Directory Volume Flags values (root->VolumeFlags) + +#define AUDITING_ON 0x01 +#define SUB_ALLOCATION_ON 0x02 +#define FILE_COMPRESSION_ON 0x04 +#define DATA_MIGRATION_ON 0x08 + +#define NEW_TRUSTEE_COUNT 0x10 // 3.x/4.x Flag +// For 3.x we assume six trustees per record. for 4.x and above the number +// is usually four. These records are opaque to FENRIS (we do not +// need them). At some future date, we may implement trustees for other +// operating systems than NetWare. + +#define NDS_FLAG 0x20 // 3.x/4.x Flag +// In theory, this identifies a volume as hosting an NDS (NetWare +// Directory Service) database. We use the Directory Services Object ID +// as the volume serial number in Microsoft-based file systems. Unix +// has no parallel at present. + +#define VFLAGS_3X_MASK (AUDITING_ON | SUB_ALLOCATION_ON | FILE_COMPRESSION_ON | DATA_MIGRATION_ON) + +#define VFLAGS_4X_MASK (AUDITING_ON | SUB_ALLOCATION_ON | FILE_COMPRESSION_ON | DATA_MIGRATION_ON | NEW_TRUSTEE_COUNT | NDS_FLAG) + +/********************************************************************** +* +* Trustee Flag Settings +* +***********************************************************************/ + +// Netware trustee security bits + +#define TrusteeReadFile 0x0001 +#define TrusteeWriteFile 0x0002 +#define TrusteeOpenFile 0x0004 +#define TrusteeCreateFile 0x0008 +#define TrusteeDeleteFile 0x0010 +#define TrusteeAccessControl 0x0020 +#define TrusteeScanFile 0x0040 +#define TrusteeModifyFile 0x0080 +#define TrusteeSupervisor 0x0100 + +#define TRUSTEE_VALID_MASK 0x01FF + +#define MAX_DOS_NAME 12 +#define DOS_FILENAME 8 +#define DOS_EXTENSION 3 +#define MAX_MAC_NAME 31 // should be 32, bug in Netware we must reproduce + +// This is the general purpose id for the NetWare Supervisor Account. +#define SUPERVISOR 0x01000000 + +// allow extended directory to create ext chains for this +#define MAX_NFS_NAME 255 // limit NFS, LONG, and NT names to 255 +#define MAX_LONG_NAME 255 // +#define MAX_NT_NAME 255 // + +// +// The GNU compiler won't byte pack our on-disk structures unless we +// specifically tell it to do so. We tell it to pack structures +// with the [ __attribute__ ((packed)) ] modifier. +// + +typedef struct _ROOT +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE NameSpaceCount __attribute__ ((packed)); + + // Really weird -- Looks as though at a later date someone needed + // to squeeze extra space out of the root directory entry for an + // NDS volume stamp. Since namespace entries are never greater than + // 12, a nibble turns out to be enough. In 4.x the name space table + // is only 6 bytes (12 nibbles/12 possible namespaces). In 3.x, each + // namespace takes a single byte instead of a single nibble. Since + // NetWare has never defined more than 7 namespaces, the last bytes + // are still ok to use as volume flags. In 3.x, these last fields + // always contain zero. + + ULONG DirectoryServicesObjectID __attribute__ ((packed)); + BYTE SupportedNameSpacesNibble[6] __attribute__ ((packed)); + BYTE DOSType __attribute__ ((packed)); + BYTE VolumeFlags __attribute__ ((packed)); + ULONG CreateDateAndTime __attribute__ ((packed)); + ULONG OwnerID __attribute__ ((packed)); + ULONG LastArchivedDateAndTime __attribute__ ((packed)); + ULONG LastArchivedID __attribute__ ((packed)); + ULONG LastModifiedDateAndTime __attribute__ ((packed)); + ULONG NextTrusteeEntry __attribute__ ((packed)); + ULONG Trustees[8] __attribute__ ((packed)); + WORD TrusteeMask[8] __attribute__ ((packed)); + ULONG MaximumSpace __attribute__ ((packed)); + WORD MaximumAccessMask __attribute__ ((packed)); + WORD SubdirectoryFirstBlockGone __attribute__ ((packed)); + ULONG ExtendedDirectoryChain0 __attribute__ ((packed)); + ULONG ExtendedDirectoryChain1 __attribute__ ((packed)); + ULONG ExtendedAttributes __attribute__ ((packed)); + ULONG ModifyTimeInSeconds __attribute__ ((packed)); + ULONG SubAllocationList __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} ROOT; + +typedef struct _ROOT3X +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE NameSpaceCount __attribute__ ((packed)); + + // Really weird -- Looks as though at a later date someone needed + // to squeeze extra space out of the root directory entry for an + // NDS volume stamp. Since namespace entries are never greater than + // 12, a nibble turns out to be enough. In 4.x the name space table + // is only 6 bytes (12 nibbles/12 possible namespaces). In 3.x, each + // namespace takes a single byte instead of a single nibble. Since + // NetWare has never defined more than 7 namespaces, the last bytes + // are still ok to use as volume flags. In 3.x, these last fields + // always contain zero. + + BYTE NameSpaceTable[10] __attribute__ ((packed)); + BYTE DOSType __attribute__ ((packed)); + BYTE VolumeFlags __attribute__ ((packed)); + ULONG CreateDateAndTime __attribute__ ((packed)); + ULONG OwnerID __attribute__ ((packed)); + ULONG LastArchivedDateAndTime __attribute__ ((packed)); + ULONG LastArchivedID __attribute__ ((packed)); + ULONG LastModifiedDateAndTime __attribute__ ((packed)); + ULONG NextTrusteeEntry __attribute__ ((packed)); + ULONG Trustees[8] __attribute__ ((packed)); + WORD TrusteeMask[8] __attribute__ ((packed)); + ULONG MaximumSpace __attribute__ ((packed)); + WORD MaximumAccessMask __attribute__ ((packed)); + WORD SubdirectoryFirstBlockGone __attribute__ ((packed)); + ULONG ExtendedDirectoryChain0 __attribute__ ((packed)); + ULONG ExtendedDirectoryChain1 __attribute__ ((packed)); + ULONG ExtendedAttributes __attribute__ ((packed)); + ULONG ModifyTimeInSeconds __attribute__ ((packed)); + ULONG SubAllocationList __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} ROOT3X; + +typedef struct _DOS +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[12] __attribute__ ((packed)); + ULONG CreateDateAndTime __attribute__ ((packed)); + ULONG OwnerID __attribute__ ((packed)); + ULONG LastArchivedDateAndTime __attribute__ ((packed)); + ULONG LastArchivedID __attribute__ ((packed)); + ULONG LastUpdatedDateAndTime __attribute__ ((packed)); + ULONG LastUpdatedID __attribute__ ((packed)); + ULONG FileSize __attribute__ ((packed)); + ULONG FirstBlock __attribute__ ((packed)); + ULONG NextTrusteeEntry __attribute__ ((packed)); + ULONG Trustees[4] __attribute__ ((packed)); + ULONG LookUpEntryNumber __attribute__ ((packed)); + ULONG LastUpdatedInSeconds __attribute__ ((packed)); + WORD TrusteeMask[4] __attribute__ ((packed)); + WORD ChangeReferenceID __attribute__ ((packed)); + WORD Reserved[1] __attribute__ ((packed)); + WORD MaximumAccessMask __attribute__ ((packed)); + WORD LastAccessedDate __attribute__ ((packed)); + ULONG DeletedFileTime __attribute__ ((packed)); + ULONG DeletedDateAndTime __attribute__ ((packed)); + ULONG DeletedID __attribute__ ((packed)); + ULONG ExtendedAttributes __attribute__ ((packed)); + ULONG DeletedBlockSequenceNumber __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} DOS; + +typedef struct _SUBDIR +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[12] __attribute__ ((packed)); + ULONG CreateDateAndTime __attribute__ ((packed)); + ULONG OwnerID __attribute__ ((packed)); + ULONG LastArchivedDateAndTime __attribute__ ((packed)); + ULONG LastArchivedID __attribute__ ((packed)); + ULONG LastModifiedDateAndTime __attribute__ ((packed)); + ULONG NextTrusteeEntry __attribute__ ((packed)); + ULONG Trustees[8] __attribute__ ((packed)); + WORD TrusteeMask[8] __attribute__ ((packed)); + ULONG MaximumSpace __attribute__ ((packed)); + WORD MaximumAccessMask __attribute__ ((packed)); + WORD SubdirectoryFirstBlockGone __attribute__ ((packed)); + ULONG MigrationBindID __attribute__ ((packed)); + ULONG Reserved __attribute__ ((packed)); + ULONG ExtendedAttributes __attribute__ ((packed)); + ULONG LastModifiedInSeconds __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} SUB_DIRECTORY; + +typedef struct _TRUSTEE +{ + ULONG Flag __attribute__ ((packed)); + ULONG Attributes __attribute__ ((packed)); + BYTE ID __attribute__ ((packed)); + BYTE TrusteeCount __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE Reserved1[1] __attribute__ ((packed)); + ULONG Subdirectory __attribute__ ((packed)); + ULONG NextTrusteeEntry __attribute__ ((packed)); + ULONG FileEntryNumber __attribute__ ((packed)); + ULONG Trustees[16] __attribute__ ((packed)); + WORD TrusteeMask[16] __attribute__ ((packed)); + BYTE Reserved2[4] __attribute__ ((packed)); + ULONG DeletedBlockSequenceNumber __attribute__ ((packed)); +} TRUSTEE; + +typedef struct _USER +{ + ULONG Flag __attribute__ ((packed)); + ULONG Reserved1 __attribute__ ((packed)); + BYTE ID __attribute__ ((packed)); + BYTE TrusteeCount __attribute__ ((packed)); + BYTE Reserved2[2] __attribute__ ((packed)); + ULONG Subdirectory __attribute__ ((packed)); + ULONG Trustees[14] __attribute__ ((packed)); + ULONG Restriction[14] __attribute__ ((packed)); +} USER; + +typedef struct _SUBALLOC +{ + ULONG Flag __attribute__ ((packed)); + ULONG Reserved1 __attribute__ ((packed)); + BYTE ID __attribute__ ((packed)); + BYTE SequenceNumber __attribute__ ((packed)); + BYTE Reserved2[2] __attribute__ ((packed)); + ULONG SubAllocationList __attribute__ ((packed)); + ULONG StartingFATChain[28] __attribute__ ((packed)); +} SUBALLOC; + +typedef struct _MACINTOSH +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[32] __attribute__ ((packed)); + ULONG ResourceFork __attribute__ ((packed)); + ULONG ResourceForkSize __attribute__ ((packed)); + BYTE FinderInfo[32] __attribute__ ((packed)); + BYTE ProDosInfo[6] __attribute__ ((packed)); + BYTE DirRightsMask[4] __attribute__ ((packed)); + BYTE Reserved0[2] __attribute__ ((packed)); + ULONG CreateTime __attribute__ ((packed)); + ULONG BackupTime __attribute__ ((packed)); + BYTE Reserved1[12] __attribute__ ((packed)); + ULONG DeletedBlockSequenceNumber __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} MACINTOSH; + +#define NFS_HASSTREAM_HARD_LINK 0x01 +#define NFS_SYMBOLIC_LINK 0x02 +#define NFS_HARD_LINK 0x04 + +typedef struct _NFS +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + + BYTE FileName[40] __attribute__ ((packed)); + BYTE TotalFileNameLength __attribute__ ((packed)); + BYTE ExtantsUsed __attribute__ ((packed)); + ULONG StartExtantNumber __attribute__ ((packed)); + ULONG mode __attribute__ ((packed)); + ULONG flags __attribute__ ((packed)); + ULONG gid __attribute__ ((packed)); + ULONG rdev __attribute__ ((packed)); + ULONG nlinks __attribute__ ((packed)); + BYTE LinkedFlag __attribute__ ((packed)); + BYTE FirstCreated __attribute__ ((packed)); + ULONG LinkNextDirNo __attribute__ ((packed)); + ULONG LinkEndDirNo __attribute__ ((packed)); + ULONG LinkPrevDirNo __attribute__ ((packed)); + ULONG uid __attribute__ ((packed)); + BYTE ACSFlags __attribute__ ((packed)); + WORD LastAccessedTime __attribute__ ((packed)); + BYTE Reserved[17] __attribute__ ((packed)); + ULONG DeletedBlockSequenceNumber __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} NFS; + +typedef struct _LONGNAME +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[80] __attribute__ ((packed)); + ULONG ExtendedSpace __attribute__ ((packed)); + BYTE ExtantsUsed __attribute__ ((packed)); + BYTE LengthData __attribute__ ((packed)); + BYTE Reserved1[18] __attribute__ ((packed)); + ULONG Reserved2 __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} LONGNAME; + +typedef struct _NTNAME +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[80] __attribute__ ((packed)); + ULONG ExtendedSpace __attribute__ ((packed)); + BYTE ExtantsUsed __attribute__ ((packed)); + BYTE LengthData __attribute__ ((packed)); + WORD ExtendedFlags __attribute__ ((packed)); + ULONG FileIdentifierStamp[2] __attribute__ ((packed)); + ULONG Reserved1[2] __attribute__ ((packed)); + ULONG Reserved2 __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} NTNAME; + +typedef struct _FENRIS_ROOT +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[80] __attribute__ ((packed)); + ULONG BlockSize __attribute__ ((packed)); + ULONG SplitSize __attribute__ ((packed)); + ULONG FenrisNext __attribute__ ((packed)); + ULONG FenrisPrior __attribute__ ((packed)); + ULONG FenrisParent __attribute__ ((packed)); + ULONG FenrisChild __attribute__ ((packed)); + ULONG FenrisFlags __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} FENRIS_ROOT; + +typedef struct _FENRIS +{ + ULONG Subdirectory __attribute__ ((packed)); + ULONG FileAttributes __attribute__ ((packed)); + BYTE UniqueID __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE FileNameLength __attribute__ ((packed)); + BYTE FileName[80] __attribute__ ((packed)); + ULONG ExtendedSpace __attribute__ ((packed)); + BYTE ExtantsUsed __attribute__ ((packed)); + BYTE LengthData __attribute__ ((packed)); + ULONG frNext __attribute__ ((packed)); + ULONG frPrior __attribute__ ((packed)); + ULONG frParent __attribute__ ((packed)); + ULONG frChild __attribute__ ((packed)); + ULONG frFlags __attribute__ ((packed)); + BYTE Reserved1[2] __attribute__ ((packed)); + ULONG PrimaryEntry __attribute__ ((packed)); + ULONG NameList __attribute__ ((packed)); +} FENRIS; + +typedef struct _UNIX_EXTENDED_DIR +{ + ULONG Signature __attribute__ ((packed)); + ULONG Length __attribute__ ((packed)); + ULONG DirectoryNumber __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE ControlFlags __attribute__ ((packed)); + BYTE Reserved __attribute__ ((packed)); + BYTE NameLength __attribute__ ((packed)); + BYTE Name[1] __attribute__ ((packed)); +} UNIX_EXTENDED_DIR; + +typedef struct _EXTENDED_DIR +{ + ULONG Signature __attribute__ ((packed)); + ULONG Length __attribute__ ((packed)); + ULONG DirectoryNumber __attribute__ ((packed)); + BYTE NameSpace __attribute__ ((packed)); + BYTE Flags __attribute__ ((packed)); + BYTE ControlFlags __attribute__ ((packed)); + BYTE Reserved __attribute__ ((packed)); +} EXTENDED_DIR; + +typedef struct _SUBALLOC_MAP { + ULONG Count; + long Size; + ULONG clusterIndex[2]; + ULONG clusterOffset[2]; + ULONG clusterNumber[2]; + ULONG clusterSize[2]; +} SUBALLOC_MAP; + +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwerror.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwerror.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwerror.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwerror.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,93 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWERROR.H +* DESCRIP : NWFS Error Codes +* DATE : April 3, 1999 +* +* +***************************************************************************/ + +#ifndef _NWFS_ERROR_ +#define _NWFS_ERROR_ + +/********************************************************************** +* +* NWFS Error Codes +* +***********************************************************************/ + +typedef enum _NW_STATUS +{ + NwSuccess, // 0 + NwFileCorrupt, // 1 + NwDirectoryCorrupt, // 2 + NwVolumeCorrupt, // 3 + NwHashCorrupt, // 4 + NwHashError, // 5 + NwDiskIoError, // 6 + NwInsufficientResources, // 7 + NwInvalidParameter, // 8 + NwNoMoreMirrors, // 9 + NwOtherError, // 10 + NwEndOfFile, // 11 + NwFileExists, // 12 + NwBadName, // 13 + NwVolumeFull, // 14 + NwFatCorrupt, // 15 + NwAccessError, // 16 + NwMissingSegment, // 17 + NwMirrorGroupFailure, // 18 + NwNotEmpty, // 19 + NwNoEntry, // 20 + NwNotPermitted, // 21 + NwSuballocMissing, // 22 + NwSuballocExceeded, // 23 + NwMemoryFault, // 24 + NwChainBad // 25 +} NW_STATUS; + + +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwext.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwext.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwext.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwext.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,472 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWEXT.C +* DESCRIP : NWFS NetWare Extended Directory Management +* DATE : January 4, 1999 +* +* +***************************************************************************/ + +#include "globals.h" + +extern void NWLockVolume(VOLUME *volume); +extern void NWUnlockVolume(VOLUME *volume); + +ULONG ValidateEXTRecord(EXTENDED_DIR *dir, ULONG DirNo) +{ + register UNIX_EXTENDED_DIR *udir = (UNIX_EXTENDED_DIR *)dir; + + if (!DirNo) + { + if (NWFSCompare(dir, ZeroBuffer, sizeof(ROOT))) + return 1; + return 0; + } + + switch (dir->Signature) + { + case NFS_EXTENDED_DIR_STAMP: + case EXTENDED_DIR_STAMP: + case LONG_EXTENDED_DIR_STAMP: + case NT_EXTENDED_DIR_STAMP: + case MIGRATE_DIR_STAMP: + case TALLY_EXTENDED_DIR_STAMP: + case EXTENDED_ATTRIBUTE_DIR_STAMP: + if (dir->DirectoryNumber > 0x00FFFFFF) // 16 million file limit + return 1; + + if (dir->NameSpace > 10) + return 1; + + if ((dir->Flags > 2) || (dir->ControlFlags > 2)) + return 1; + + if (NFS_EXTENDED_DIR_STAMP == dir->Signature) + { + if (udir->NameLength > 255) + return 1; + } + else + { + if (dir->Length > 255) + return 1; + } + return 0; + + default: + return 1; + } + +} + +ULONG ReadExtDirectoryRecords(VOLUME *volume, EXTENDED_DIR *dir, BYTE *data, + ULONG DirNo, ULONG count) +{ + register ULONG cbytes; + ULONG retCode = 0; + + cbytes = NWReadFile(volume, + &volume->ExtDirectory1, + 0, + -1, + DirNo * sizeof(DOS), + (BYTE *)dir, + sizeof(DOS) * count, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0, + TRUE); + + if ((cbytes == (sizeof(DOS) * count)) && !retCode) + { + if (ValidateEXTRecord(dir, DirNo)) + { + NWFSPrint("ext directory # %X is invalid\n", (unsigned)DirNo); + return NwDirectoryCorrupt; + } + return 0; + } + + cbytes = NWReadFile(volume, + &volume->ExtDirectory2, + 0, + -1, + DirNo * sizeof(DOS), + (BYTE *)dir, + sizeof(DOS) * count, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0, + TRUE); + + if ((cbytes == (sizeof(DOS) * count)) && !retCode) + { + if (ValidateEXTRecord(dir, DirNo)) + { + NWFSPrint("ext directory # %X is invalid\n", (unsigned)DirNo); + return NwDirectoryCorrupt; + } + return 0; + } + return 0; +} + +ULONG WriteExtDirectoryRecords(VOLUME *volume, EXTENDED_DIR *dir, BYTE *data, + ULONG DirNo, ULONG count) +{ + register ULONG cbytes; + ULONG retCode = 0; + + if (ValidateEXTRecord(dir, DirNo)) + { + NWFSPrint("ext directory # %X is invalid\n", (unsigned)DirNo); + return NwDirectoryCorrupt; + } + + cbytes = NWWriteFile(volume, + &volume->ExtDirectory1, + 0, + DirNo * sizeof(DOS), + (BYTE *)dir, + sizeof(DOS) * count, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + + if ((cbytes == (sizeof(DOS) * count)) && !retCode) + { +#if (!CREATE_EDIR_MISMATCH) + // write mirror ext directory + cbytes = NWWriteFile(volume, + &volume->ExtDirectory2, + 0, + DirNo * sizeof(DOS), + (BYTE *)dir, + sizeof(DOS) * count, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + + if ((cbytes == (sizeof(DOS) * count)) && !retCode) +#endif + return 0; + } + return NwDiskIoError; +} + +ULONG ValidateExtendedDirectory(VOLUME *volume) +{ + register FAT_ENTRY *FAT1, *FAT2; + FAT_ENTRY FAT1_S, FAT2_S; + register ULONG retCode; + register long index1, index2; + register ULONG DirNo; + register ULONG cluster1, cluster2, DirCount; + register BYTE *Buffer1, *Buffer2; + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Validating Extended Directory ***\n"); +#endif + + Buffer1 = NWFSCacheAlloc(volume->ClusterSize, EXT_WORKSPACE_TAG); + if (!Buffer1) + { + NWFSPrint("nwfs: could not alloc extended directory buffer\n"); + return -3; + } + + Buffer2 = NWFSCacheAlloc(volume->ClusterSize, EXT_WORKSPACE_TAG); + if (!Buffer2) + { + NWFSPrint("nwfs: could not alloc extended directory buffer\n"); + NWFSFree(Buffer1); + return -3; + } + + DirNo = 0; + cluster1 = volume->ExtDirectory1; + cluster2 = volume->ExtDirectory2; + + if ((cluster1 && !cluster2) || (!cluster1 && cluster2)) + { + NWFSPrint("nwfs: extended directory fat head chain mismatch\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + // Extended Directory File is empty + if ((!cluster1) || (!cluster2)) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return 0; + } + + // read extended directory root 1 + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, Buffer1, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + // read extended directory root 2 + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, Buffer2, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return retCode; + } + + retCode = SetAssignedClusterValue(volume, cluster1, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set edir cluster-%X\n", + (unsigned int)cluster1); + } + + retCode = SetAssignedClusterValue(volume, cluster2, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set edir mirror-%X\n", + (unsigned int)cluster2); + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadExtDirectory\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + DirCount = volume->ClusterSize / sizeof(DOS); + + while (TRUE) + { + if (NWFSCompare(Buffer1, Buffer2, volume->ClusterSize)) + { + extern void dumpRecordBytes(BYTE *, ULONG); + + NWFSPrint("nwfs: Extended Directory data mirror mismatch\n"); + +#if (VERBOSE) + NWFSPrint("index1-%d cluster1-[%08X] next1-[%08X]\n", (int)index1, + (unsigned int)cluster1, + (unsigned int)FAT1->FATCluster); + dumpRecordBytes(Buffer1, 64); + + NWFSPrint("index2-%d cluster2-[%08X] next2-[%08X]\n", (int)index2, + (unsigned int)cluster2, + (unsigned int)FAT2->FATCluster); + dumpRecordBytes(Buffer2, 64); +#endif + + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -3; + } + + if (FAT1->FATCluster == (ULONG) -1) + break; + + // if the other FAT chain terminated abruptly, exit the loop + + if (FAT2->FATCluster == (ULONG) -1) + break; + + if (!FAT1->FATCluster) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: Free Cluster detected in Ext DIR1 Chain\n"); + return -3; + } + + if (!FAT2->FATCluster) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: Free Cluster detected in Ext DIR2 Chain\n"); + return -3; + } + + if (FAT1->FATCluster & 0x80000000) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: SubAlloc Node Detected in Ext DIR1\n"); + return -3; + } + + if (FAT2->FATCluster & 0x80000000) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: SubAlloc Node Detected in Ext DIR2\n"); + return -3; + } + + cluster1 = FAT1->FATCluster; + cluster2 = FAT2->FATCluster; + + retCode = ReadPhysicalVolumeCluster(volume, cluster1, Buffer1, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: Read Error Ext Directory1 returned %d\n", (int)retCode); + return retCode; + } + + retCode = ReadPhysicalVolumeCluster(volume, cluster2, Buffer2, volume->ClusterSize, + DIRECTORY_PRIORITY); + if (retCode) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: Read Error Ext Directory2 returned %d\n", (int)retCode); + return retCode; + } + + retCode = SetAssignedClusterValue(volume, cluster1, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set edir cluster-%X\n", + (unsigned int)cluster1); + } + + retCode = SetAssignedClusterValue(volume, cluster2, 1); + if (retCode) + { + NWFSPrint("nwfs: assigned bit block value not set edir mirror-%X\n", + (unsigned int)cluster2); + } + + FAT1 = GetFatEntry(volume, cluster1, &FAT1_S); + FAT2 = GetFatEntry(volume, cluster2, &FAT2_S); + if (!FAT1 || !FAT2) + { + NWFSPrint("nwfs: error reading fat entry ReadExtDirectory\n"); + NWFSFree(Buffer1); + NWFSFree(Buffer2); + return -1; + } + + // index numbers should always be ascending. if we detect a + // non-ascending sequence, this indicates a corrupt FAT chain + + if (index1 > (long)FAT1->FATIndex) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: EXTDIR1 fat index overlaps on itself\n"); + return -1; + } + + if (index2 > (long)FAT2->FATIndex) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: EXTDIR2 fat index overlaps on itself\n"); + return -1; + } + + // update FAT index number for chains + + index1 = FAT1->FATIndex; + index2 = FAT2->FATIndex; + + } + + if (FAT1->FATCluster != FAT2->FATCluster) + { + NWFSFree(Buffer1); + NWFSFree(Buffer2); + NWFSPrint("nwfs: Extended Directory FAT chain mirror mismatch\n"); + return -3; + } + + NWFSFree(Buffer1); + NWFSFree(Buffer2); + + return 0; + +} + +ULONG ReadExtendedDirectory(VOLUME *volume) +{ + return 0; +} + + + + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwfile.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwfile.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwfile.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwfile.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,1572 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWFILE.C +* DESCRIP : NWFS NetWare File Management +* DATE : December 14, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +ULONG NWLockFile(HASH *hash) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore((struct semaphore *)&hash->Semaphore) == -EINTR) + NWFSPrint("lock file (%s) was interrupted\n", hash->Name); +#endif + return 0; +} + +ULONG NWLockFileExclusive(HASH *hash) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore((struct semaphore *)&hash->Semaphore) == -EINTR) + NWFSPrint("lock file (%s) was interrupted\n", hash->Name); +#endif + return 0; +} + +void NWUnlockFile(HASH *hash) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&hash->Semaphore); +#endif +} + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +ULONG NWSyncFile(VOLUME *volume, HASH *hash) +{ + register long FATChain; + register ULONG ccode; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + SUBALLOC_MAP map; + extern ULONG SyncCluster(VOLUME *, ULONG); +#if (!HASH_FAT_CHAINS) + DOS dos; +#endif + + if (!hash || (hash->Flags & SUBDIRECTORY_FILE)) + return (ULONG) -1; + +#if (HASH_FAT_CHAINS) + FATChain = hash->FirstBlock; +#else + ccode = ReadDirectoryRecord(volume, &dos, hash->DirNo); + if (ccode) + return -1; + + FATChain = dos.FirstBlock; +#endif + + if (FATChain & 0x80000000) + { + // check for EOF + if (FATChain == (ULONG) -1) + return 0; + + ccode = MapSuballocNode(volume, &map, FATChain); + if (ccode) + return (ULONG) ccode; + + if (map.Count == 1) + { + ccode = SyncCluster(volume, map.clusterNumber[0]); + if (ccode) + return ccode; + } + else + { + ccode = SyncCluster(volume, map.clusterNumber[0]); + if (ccode) + return ccode; + + ccode = SyncCluster(volume, map.clusterNumber[1]); + if (ccode) + return ccode; + } + } + + FAT = GetFatEntry(volume, FATChain, &FAT_S); + while (FAT && FAT->FATCluster) + { + ccode = SyncCluster(volume, FATChain); + if (ccode) + return ccode; + + // bump to the next cluster + FATChain = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF marker + if (FATChain & 0x80000000) + { + // end of file + if (FATChain == (ULONG) -1) + return 0; + + ccode = MapSuballocNode(volume, &map, FATChain); + if (ccode) + return (ULONG) ccode; + + if (map.Count == 1) + { + ccode = SyncCluster(volume, map.clusterNumber[0]); + if (ccode) + return ccode; + } + else + { + ccode = SyncCluster(volume, map.clusterNumber[0]); + if (ccode) + return ccode; + + ccode = SyncCluster(volume, map.clusterNumber[1]); + if (ccode) + return ccode; + } + return 0; + } + + FAT = GetFatEntry(volume, FATChain, &FAT_S); + } + return 0; + +} + +ULONG NWReadFile(VOLUME *volume, ULONG *Chain, ULONG Flags, ULONG FileSize, + ULONG offset, BYTE *buf, long count, long *Context, + ULONG *Index, ULONG *retCode, ULONG as, ULONG SAFlag, + ULONG Attributes, ULONG readAhead) +{ + register long PrevContext = 0; + register ULONG PrevIndex = 0; + register ULONG FATChain, index; + register long bytesRead = 0, bytesLeft = 0; + register ULONG StartIndex, StartOffset; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + register ULONG voffset, vsize, vindex, cbytes; + + if (!Chain) + return 0; + + if (!(*Chain)) + return 0; + + if (retCode) + *retCode = 0; + + // adjust size and range check for EOF + + if ((offset + count) > FileSize) + count = FileSize - offset; + + if (count <= 0) + return 0; + + // if a subdirectory then return 0 + if (Flags & SUBDIRECTORY_FILE) + { + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + bytesLeft = count; + StartIndex = offset / volume->ClusterSize; + StartOffset = offset % volume->ClusterSize; + + // we always start with an index of zero + index = 0; + FATChain = *Chain; + vindex = StartIndex; + + // see if we are starting on or after the supplied index/cluster pointer. + // if (StartIndex < *Index), then we are being asked to start before + // the user supplied context. In this case, start at the beginning of + // the chain. + + if (Index && (StartIndex >= (*Index))) + { + if (Context && (*Context)) + { + PrevContext = FATChain = *Context; + PrevIndex = index = *Index; + } + } + + if ((bytesLeft > 0) && (FATChain & 0x80000000)) + { + // check for EOF + if (FATChain == (ULONG) -1) + { + // filesize may exceed allocation, which means the rest of + // the file is sparse. fill zeros into the requested + // size. bytesLeft will have been set by count, which is + // range checked to the actual length of the file. + + if (bytesLeft > 0) + { + if (buf) + { + if (NWFSSetUserSpace(buf, 0, bytesLeft)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + bytesRead += bytesLeft; + } + if (Context) + *Context = PrevContext; + if (Index) + *Index = PrevIndex; + return bytesRead; + } + + // if we got here, then we detected a suballocation element. See + // if this is legal for this file. + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || + (Attributes & TRANSACTION) || (Flags & RAW_FILE)) + { + if (retCode) + *retCode = NwNotPermitted; + return bytesRead; + } + + // check for valid index + if (index == vindex) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + // if this value exceeds the suballoc record size, + // ReadSuballoc record will reduce this size to the + // current record allocation. + vsize = bytesLeft; + + if (buf) + cbytes = ReadSuballocRecord(volume, voffset, FATChain, buf, vsize, as, retCode); + else + cbytes = vsize; + + bytesRead += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + if (Context) + *Context = FATChain; + if (Index) + *Index = index; + } + + // filesize may exceed allocation, which means the rest of + // the file is sparse. fill zeros into the requested + // size. + + if (bytesLeft > 0) + { + if (buf) + { + if (NWFSSetUserSpace(buf, 0, bytesLeft)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + bytesRead += bytesLeft; + } + return bytesRead; + } + + vindex = StartIndex; + FAT = GetFatEntry(volume, FATChain, &FAT_S); + if (FAT) + { + if (Context) + *Context = FATChain; + index = FAT->FATIndex; + if (Index) + *Index = index; + } + + while (FAT && FAT->FATCluster && (bytesLeft > 0)) + { + // if we found a hole, then return zeros until we + // either satisfy the requested read size or + // we span to the next valid index entry + + while ((bytesLeft > 0) && (vindex < index)) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + if (buf) + { + if (NWFSSetUserSpace(buf, 0, vsize)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + bytesRead += vsize; + bytesLeft -= vsize; + buf += vsize; + vindex++; + } + + // found our index block, perform the copy operation + + if ((bytesLeft > 0) && (vindex == index)) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + if (buf) + cbytes = ReadClusterWithOffset(volume, FATChain, voffset, buf, vsize, + as, retCode, + ((Flags & RAW_FILE) + ? RAW_PRIORITY + : DATA_PRIORITY)); + else + cbytes = vsize; + +#if (READ_AHEAD_ON) + // do read ahead on the next valid cluster + if (((FAT->FATCluster & 0x80000000) == 0) && (buf) && readAhead && + (!(Flags & RAW_FILE))) + { + ULONG mirror = (ULONG)-1; + + PerformBlockReadAhead(&DataLRU, volume, + (FAT->FATCluster * volume->BlocksPerCluster), + volume->BlocksPerCluster, 1, &mirror); + } +#endif + + bytesRead += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + vindex++; + } + + // bump to the next cluster + PrevContext = FATChain; + PrevIndex = index; + FATChain = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF marker + if ((bytesLeft > 0) && (FATChain & 0x80000000)) + { + // end of file + if (FATChain == (ULONG) -1) + { + // filesize may exceed allocation, which means the rest of + // the file is sparse. fill zeros into the requested + // size. + if (bytesLeft > 0) + { + if (buf) + { + if (NWFSSetUserSpace(buf, 0, bytesLeft)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + bytesRead += bytesLeft; + } + if (Context) + *Context = PrevContext; + if (Index) + *Index = PrevIndex; + return bytesRead; + } + + // if we got here, then we detected a suballocation element. See + // if this is legal for this file. + + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || + (Attributes & TRANSACTION) || (Flags & RAW_FILE)) + { + if (retCode) + *retCode = NwNotPermitted; + return bytesRead; + } + + // check for valid index + if ((index + 1) == vindex) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + // if this value exceeds the suballoc record size, + // ReadSuballoc record will reduce this size to the + // current record allocation. + vsize = bytesLeft; + + if (buf) + cbytes = ReadSuballocRecord(volume, voffset, FATChain, buf, + vsize, as, retCode); + else + cbytes = vsize; + + bytesRead += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + if (Context) + *Context = FATChain; + if (Index) + *Index = (index + 1); + } + + // filesize may exceed allocation, which means the rest of + // the file is sparse. fill zeros into the requested + // size. + if (bytesLeft > 0) + { + if (buf) + { + if (NWFSSetUserSpace(buf, 0, bytesLeft)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + bytesRead += bytesLeft; + } + return bytesRead; + } + + // get next fat table entry and index + FAT = GetFatEntry(volume, FATChain, &FAT_S); + if (FAT) + { + if (Context) + *Context = FATChain; + index = FAT->FATIndex; + if (Index) + *Index = index; + } + } + + // filesize may exceed allocation, which means the rest of + // the file is sparse. fill zeros into the requested + // size. + if (bytesLeft > 0) + { + if (buf) + { + if (NWFSSetUserSpace(buf, 0, bytesLeft)) + { + if (retCode) + *retCode = NwMemoryFault; + return bytesRead; + } + } + bytesRead += bytesLeft; + } + return bytesRead; + +} + +// +// if you pass a NULL buffer address, this function will extend the +// meta-data for a file and preallocate mapped space for memory mapped +// file support. +// + +ULONG NWWriteFile(VOLUME *volume, ULONG *Chain, ULONG Flags, + ULONG offset, BYTE *buf, long count, long *Context, + ULONG *Index, ULONG *retCode, ULONG as, ULONG SAFlag, + ULONG Attributes) +{ + register long PrevContext = 0; + register ULONG PrevIndex = 0; + register ULONG FATChain, index; + register long bytesWritten = 0, bytesLeft = 0; + register ULONG lcount = 0; + register ULONG StartIndex, StartOffset, SuballocSize; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + register ULONG voffset, vsize, vindex, cbytes; + register ULONG PrevCluster, NewCluster; + register VOLUME_WORKSPACE *WorkSpace; + MIRROR_LRU *lru = 0; + + if (!Chain) + return 0; + + if (!(*Chain)) + { + NWFSPrint("nwfs: fat chain was NULL (write)\n"); + if (retCode) + *retCode = NwFileCorrupt; + return 0; + } + + if (retCode) + *retCode = 0; + + // if a subdirectory then return 0 + if (Flags & SUBDIRECTORY_FILE) + { + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + bytesLeft = count; + StartIndex = offset / volume->ClusterSize; + StartOffset = offset % volume->ClusterSize; + + // we always start with an index of zero + index = 0; + PrevCluster = (ULONG) -1; + FATChain = *Chain; + vindex = StartIndex; + +#if (VERBOSE) + NWFSPrint("nwfs_write: count-%d offset-%d ctx-%08X ndx-%08X chn-%08X\n", + (int)count, (int)offset, + (unsigned int) (Context ? *Context : 0), + (unsigned int) (Index ? *Index : 0), + (unsigned int) *Chain); +#endif + + // see if we are starting on or after the supplied index/cluster pointer. + // if (StartIndex < *Index), then we are being asked to start before + // the user supplied context. In this case, start at the beginning of + // the chain. + + if (Index && (StartIndex >= (*Index))) + { + if (Context && (*Context)) + { + PrevContext = FATChain = *Context; + PrevIndex = index = *Index; + } + } + + if ((bytesLeft > 0) && (FATChain & 0x80000000)) + { + // check for EOF + if (FATChain == (ULONG) -1) + { + while (bytesLeft > 0) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + return bytesWritten; + } + + // we have detected a suballoc element in the fat chain if we + // get to this point + + // if we got here, then we detected a suballocation element. See + // if this is legal for this file. + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || + (Attributes & TRANSACTION) || (Flags & RAW_FILE)) + { + if (retCode) + *retCode = NwNotPermitted; + return bytesWritten; + } + + SuballocSize = GetSuballocSize(volume, FATChain); + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + // these cases assume we will free the current suballoc element + // because our write either exceeds the current suballoc size + // or we are writing our starting index beyond the suballocation + // element itself in the chain. In either case, we must free + // the current suballocation element. + + // if we are asked to write beyond the current suballoc element + if (vindex > index) + { +#if (VERBOSE) + NWFSPrint("nwfs: we were asked to write to the next index\n"); +#endif + // convert the suballoc record into an allocated cluster + // and copy the data from the suballoc record. + + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + { + // if we could not get memory to copy the suballoc record, + // then return (out of drive space) + if (retCode) + *retCode = NwInsufficientResources; + return bytesWritten; + } + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, index, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // here we read the previous data from the suballoc element + cbytes = ReadSuballocRecord(volume, 0, FATChain, + &WorkSpace->Buffer[0], + SuballocSize, KERNEL_ADDRESS_SPACE, + retCode); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // now write the previous data from the suballoc element + // into the newly allocated cluster. + cbytes = WriteClusterWithOffset(volume, NewCluster, 0, &WorkSpace->Buffer[0], SuballocSize, + KERNEL_ADDRESS_SPACE, retCode, + ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // free the suballoc element in bit block list + FreeSuballocRecord(volume, FATChain); + + // set previous cluster chain to point to this entry + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + PrevCluster = NewCluster; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = index; + + FreeWorkspace(volume, WorkSpace); + + while (bytesLeft > 0) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + return bytesWritten; + } + else + if ((vindex == index) && ((bytesLeft + voffset) >= SuballocSize)) + { +#if (VERBOSE) + NWFSPrint("nwfs: we were asked to write beyond the suballoc\n"); +#endif + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + { + // if we could not get memory to copy the suballoc record, + // then return (out of drive space) + if (retCode) + *retCode = NwInsufficientResources; + + return bytesWritten; + } + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, (ULONG) -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // here we read the previous data from the suballoc element + cbytes = ReadSuballocRecord(volume, 0, FATChain, &WorkSpace->Buffer[0], + SuballocSize, KERNEL_ADDRESS_SPACE, + retCode); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // now write the previous data from the suballoc element + // into the newly allocated cluster. + cbytes = WriteClusterWithOffset(volume, NewCluster, 0, &WorkSpace->Buffer[0], SuballocSize, + KERNEL_ADDRESS_SPACE, retCode, + ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // free the suballoc element in bit block list + FreeSuballocRecord(volume, FATChain); + + // if we are the first cluster, then save the chain head in + // the directory record + + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + PrevCluster = NewCluster; + + // now write the user data into the suballoc element + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + + FreeWorkspace(volume, WorkSpace); + + while (bytesLeft > 0) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + return bytesWritten; + } + else + if (vindex == index) + { + // for this case, since our target write size fits within + // the previously allocated suballoc element, then just + // write the data. +#if (VERBOSE) + NWFSPrint("nwfs: we were asked to write within the suballoc\n"); +#endif + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + // at this point, bytesLeft is either equal to or + // less than the size of the current suballocation + // record. + + vsize = bytesLeft; + + if (buf) + cbytes = WriteSuballocRecord(volume, voffset, FATChain, + buf, vsize, as, retCode); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + } + else + NWFSPrint("nwfs: suballoc write was index(%d) < vindex(%d) (0)\n", + (int)index, (int)vindex); + + return bytesWritten; + } + + FAT = GetFatEntryAndLRU(volume, FATChain, &lru, &FAT_S); + if (FAT) + { + if (Context) + *Context = FATChain; + index = FAT->FATIndex; + } + + while (FAT && FAT->FATCluster && (bytesLeft > 0)) + { + // if we found a hole, then allocate and add a new cluster + // to the file and continue to add clusters and write until + // bytesLeft is < 0 or we find the next valid cluster in the + // fat chain + + while ((bytesLeft > 0) && (vindex < index)) + { + // we can only get here if we detected the next + // fat element is greater than the target index + // (the file has holes, and we hit an index + // larger than we expected). + + // we simply extend the file by allocating clusters + // until we complete the write or the target index + // equals the current cluster. obvioulsy, we must + // insert nodes into the fat chain for each element we + // allocate. + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to next cluster + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, FATChain); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + // if PrevCluster is not equal to -1, then we are + // inserting at the front of the cluster chain + // so save the new directory chain head. + + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + + // found our index block, perform the copy operation + + if ((bytesLeft > 0) && (vindex == index)) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + if (buf) + cbytes = WriteClusterWithOffset(volume, FATChain, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = FATChain; + if (Index) + *Index = vindex; + vindex++; + } + + // save the previous cluster + PrevCluster = FATChain; + + // bump to the next cluster + FATChain = FAT->FATCluster; + + // check if the next cluster is a suballoc element or EOF + if ((bytesLeft > 0) && (FATChain & 0x80000000)) + { + // end of file + if (FATChain == (ULONG) -1) + { + while (bytesLeft > 0) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + return bytesWritten; + } + + // we have detected a suballoc element in the fat chain if we + // get to this point + + // if we got here, then we detected a suballocation element. See + // if this is legal for this file. + if ((!SAFlag) || (Attributes & NO_SUBALLOC) || + (Attributes & TRANSACTION) || (Flags & RAW_FILE)) + { + if (retCode) + *retCode = NwNotPermitted; + return bytesWritten; + } + + SuballocSize = GetSuballocSize(volume, FATChain); + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + // this case assumes we will free the current suballoc element + // because our write either exceeds the current suballoc size + // or we are writing our starting index beyond the suballocation + // element itself in the chain. In either case, we must free + // the current suballocation element. + + if (vindex > (index + 1)) + { +#if (VERBOSE) + NWFSPrint("nwfs: we were asked to write to the next index\n"); +#endif + // convert the suballoc record into an allocated cluster + // and copy the data from the suballoc record. + + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + { + // if we could not get memory to copy the suballoc record, + // then return (out of drive space) + if (retCode) + *retCode = NwInsufficientResources; + return bytesWritten; + } + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, (index + 1), + -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // here we read the previous data from the suballoc element + cbytes = ReadSuballocRecord(volume, 0, FATChain, &WorkSpace->Buffer[0], + SuballocSize, KERNEL_ADDRESS_SPACE, + retCode); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // now write the previous data from the suballoc element + // into the newly allocated cluster. + cbytes = WriteClusterWithOffset(volume, NewCluster, 0, &WorkSpace->Buffer[0], SuballocSize, + KERNEL_ADDRESS_SPACE, retCode, + ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // free the suballoc element in bit block list + FreeSuballocRecord(volume, FATChain); + + // set previous cluster chain to point to this entry + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = (index + 1); + + FreeWorkspace(volume, WorkSpace); + + while (bytesLeft > 0) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + return bytesWritten; + } + else + if ((vindex == (index + 1)) && ((bytesLeft + voffset) >= SuballocSize)) + { +#if (VERBOSE) + NWFSPrint("nwfs: we were asked to write beyond the end of the suballoc\n"); +#endif + WorkSpace = AllocateWorkspace(volume); + if (!WorkSpace) + { + // if we could not get memory to copy the suballoc record, + // then return (out of drive space) + if (retCode) + *retCode = NwInsufficientResources; + return bytesWritten; + } + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // here we read the previous data from the suballoc element + cbytes = ReadSuballocRecord(volume, 0, FATChain, &WorkSpace->Buffer[0], + SuballocSize, KERNEL_ADDRESS_SPACE, + retCode); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // now write the previous data from the suballoc element + // into the newly allocated cluster. + cbytes = WriteClusterWithOffset(volume, NewCluster, 0, + &WorkSpace->Buffer[0], SuballocSize, + KERNEL_ADDRESS_SPACE, retCode, + ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + if (cbytes != SuballocSize) + { + FreeWorkspace(volume, WorkSpace); + if (retCode) + *retCode = NwDiskIoError; + return bytesWritten; + } + + // free the suballoc element in bit block list + FreeSuballocRecord(volume, FATChain); + + // set previous cluster chain to point to this entry + if (PrevCluster == (ULONG) -1) + *Chain = NewCluster; + else + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + + FreeWorkspace(volume, WorkSpace); + + while (bytesLeft > 0) + { + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + vsize = (bytesLeft > (long)(volume->ClusterSize - voffset)) + ? (volume->ClusterSize - voffset) : bytesLeft; + + // allocate cluster and point forward link to EOF + NewCluster = AllocateClusterSetIndexSetChain(volume, vindex, -1); + if (NewCluster == -1) + { + // if we could not get a free cluster, then return + // (out of drive space) + if (retCode) + *retCode = NwVolumeFull; + return bytesWritten; + } + +#if (ZERO_FILL_SECTORS) + // zero fill the new cluster + ZeroPhysicalVolumeCluster(volume, NewCluster, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); +#endif + + // set previous cluster chain to point to this entry + SetClusterValue(volume, PrevCluster, NewCluster); + + // update previous cluster to new cluster + // this will force inserts after the end of this cluster + PrevCluster = NewCluster; + + if (buf) + cbytes = WriteClusterWithOffset(volume, NewCluster, voffset, buf, vsize, + as, retCode, ((Flags & RAW_FILE) ? RAW_PRIORITY : DATA_PRIORITY)); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + buf += cbytes; + + // update context pointer with adjusted offset + if (Context) + *Context = NewCluster; + if (Index) + *Index = vindex; + vindex++; + } + return bytesWritten; + } + else + if (vindex == (index + 1)) + { +#if (VERBOSE) + NWFSPrint("nwfs: we were asked to write the current suballoc\n"); +#endif + // for this case, since our target write size fits within + // the previously allocated suballoc element, then just + // write the data. + + voffset = 0; + if (vindex == StartIndex) + voffset = StartOffset; + + // at this point, bytesLeft is either equal to or + // less than the size of the current suballocation + // record. + + vsize = bytesLeft; + + if (buf) + cbytes = WriteSuballocRecord(volume, voffset, FATChain, + buf, vsize, as, retCode); + else + cbytes = vsize; + + bytesWritten += cbytes; + bytesLeft -= cbytes; + } + else + NWFSPrint("nwfs: suballoc write was index(%d) < vindex(%d) (0)\n", + (int)index, (int)vindex); + + return bytesWritten; + } + + // get next fat table entry and index + FAT = GetFatEntryAndLRU(volume, FATChain, &lru, &FAT_S); + if (FAT) + { + if (Context) + *Context = FATChain; + index = FAT->FATIndex; + if (Index) + *Index = vindex; + } + + // if the fat chain terminates, then exit + if (!FAT) + return bytesWritten; + + lcount++; + } + return bytesWritten; + +} + +#endif + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwfix.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwfix.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwfix.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwfix.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,734 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWFIX.C +* DESCRIP : NWFS Volume Repair Module +* DATE : July 15, 2000 +* +* +***************************************************************************/ + +#include "globals.h" + +void NWLockScan(void); +void NWUnlockScan(void); + +ULONG UtilInitializeDirAssignHash(VOLUME *volume); +ULONG UtilCreateDirAssignEntry(VOLUME *volume, ULONG Parent, ULONG BlockNo, + DOS *dos); +ULONG UtilFreeDirAssignHash(VOLUME *volume); +ULONG UtilAddToDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock); +ULONG UtilRemoveDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock); +ULONG UtilAllocateDirectoryRecord(VOLUME *volume, ULONG Parent); +ULONG UtilFreeDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo, + ULONG Parent); + +typedef struct _NWREPAIR_STATS +{ + ULONG max_entries; + ULONG bad_trustee_records; + ULONG bad_trustee_mask; + ULONG bad_name_records; + ULONG bad_root_records; + ULONG bad_root_flags; + ULONG bad_dos_records; + ULONG bad_mac_records; + ULONG bad_nfs_records; + ULONG bad_nfs_extants; + ULONG bad_long_records; + ULONG bad_long_extants; + ULONG bad_nt_records; + ULONG bad_nt_extants; + ULONG bad_suballoc_records; + ULONG bad_user_records; + ULONG bad_free_records; + ULONG cross_linked_files; + ULONG orphaned_fat_chains; + ULONG unowned_trustee_records; + ULONG orphaned_name_entries; +} NWREPAIR_STATS; + +ULONG StrictValidateDirectoryRecord(VOLUME *volume, DOS *dos, + ULONG DirNo, NWREPAIR_STATS *stats); + +ULONG RepairTwoFiles(VOLUME *volume, ULONG *c1, ULONG *c2); + +ULONG NWRepairVolume(VOLUME *volume, ULONG flags) +{ + register ULONG Dir1Size, Dir2Size; + register ULONG eDir1Size, eDir2Size; + register ULONG i, j, owner, ccode, cbytes; + register ULONG DirTotal, DirCount, DirsPerBlock, DirBlocks; + register DOS *dos; + register USER *user; + register ROOT *root; + register TRUSTEE *trustee; + nwvp_fat_fix_info fi; + ULONG retCode = 0; + NWREPAIR_STATS stats; + + NWFSSet(&stats, 0, sizeof(NWREPAIR_STATS)); + + NWFSPrint("[ Repairing Volume FAT Tables ]\n"); + + NWLockScan(); + if (!volume->VolumePresent) + { + NWFSPrint("nwfs: volume %s is missing one or more segments\n", + volume->VolumeName); + NWUnlockScan(); + return NwFatCorrupt; + } + + if (VolumeMountedTable[volume->VolumeNumber]) + { + NWFSPrint("nwfs: volume %s disk(%d) is currently mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + NWUnlockScan(); + return NwFatCorrupt; + } + + if (nwvp_vpartition_open(volume->nwvp_handle) != 0) + { + NWFSPrint("nwfs: volume %s could not attach to NVMP\n", + volume->VolumeName); + NWUnlockScan(); + return NwFatCorrupt; + } + + ccode = nwvp_vpartition_fat_fix(volume->nwvp_handle, &fi, TRUE); + if (ccode) + { + NWFSPrint("nwrepair: FAT tables could not be repaired\n"); + NWUnlockScan(); + return NwFatCorrupt; + } + nwvp_vpartition_close(volume->nwvp_handle); + + NWUnlockScan(); + + NWFSPrint("total_fat_blocks : %d ",(int)fi.total_fat_blocks); + NWFSPrint("valid_mirror_blocks : %d\n",(int)fi.total_valid_mirror_blocks); + NWFSPrint("valid_single_blocks : %d ",(int)fi.total_valid_single_blocks); + NWFSPrint("missing_blocks : %d\n",(int)fi.total_missing_blocks); + NWFSPrint("mismatched_blocks : %d ",(int)fi.total_mismatch_blocks); + NWFSPrint("table_entries : %d\n",(int)fi.total_entries); + NWFSPrint("index_mismatches : %d ",(int)fi.total_index_mismatch_entries); + NWFSPrint("end_null_entries : %d\n",(int)fi.total_end_null_entries); + NWFSPrint("suballoc_null_entries : %d ",(int)fi.total_SA_null_entries); + NWFSPrint("fat_null_entries : %d\n",(int)fi.total_FAT_null_entries); + NWFSPrint("suballoc_mismatches : %d ",(int)fi.total_SA_mismatch_entries); + NWFSPrint("fat_mismatch_entries : %d\n",(int)fi.total_FAT_mismatch_entries); + + NWFSPrint("[ Verifying Volume FAT Tables ]\n"); + + ccode = MountRawVolume(volume); + if (ccode) + { + NWFSPrint("nwrepair: FAT Tables failed verify\n"); + return NwVolumeCorrupt; + } + + dos = NWFSCacheAlloc(IO_BLOCK_SIZE, DIR_WORKSPACE_TAG); + if (!dos) + { + DismountRawVolume(volume); + NWFSPrint("nwrepair: not enough memory to repair volume\n"); + return NwInsufficientResources; + } + + NWFSPrint("[ Verifying Directory Primary/Mirror Chains ]\n"); + if (!volume->FirstDirectory || !volume->SecondDirectory) + { + DismountRawVolume(volume); + NWFSFree(dos); + NWFSPrint("nwrepair: directory primary/mirror files are mismatched\n"); + return NwDirectoryCorrupt; + } + + Dir1Size = GetChainSize(volume, volume->FirstDirectory); + Dir2Size = GetChainSize(volume, volume->SecondDirectory); + if (!Dir1Size || !Dir2Size || (Dir1Size != Dir2Size)) + { + DismountRawVolume(volume); + NWFSFree(dos); + NWFSPrint("nwrepair: directory primary/mirror file mismatch %d-%d\n", + (int)Dir1Size, (int)Dir2Size); + return NwDirectoryCorrupt; + } + + NWFSPrint("[ Verifying Extended Directory Primary/Mirror Chains ]\n"); + if (!volume->ExtDirectory1 && !volume->ExtDirectory2) + NWFSPrint("nwrepair: ext directory primary/mirror files are NULL\n"); + else + if (volume->ExtDirectory1 && !volume->ExtDirectory2) + volume->ExtDirectory2 = volume->ExtDirectory1; + else + if (!volume->ExtDirectory1 && volume->ExtDirectory2) + volume->ExtDirectory1 = volume->ExtDirectory2; + + if (volume->ExtDirectory1 && volume->ExtDirectory2) + { + eDir1Size = GetChainSize(volume, volume->ExtDirectory1); + eDir2Size = GetChainSize(volume, volume->ExtDirectory2); + if (eDir1Size != eDir2Size) + { + DismountRawVolume(volume); + NWFSFree(dos); + NWFSPrint("nwrepair: ext dir primary/mirror file mismatch %d-%d\n", + (int)eDir1Size, (int)eDir2Size); + return NwDirectoryCorrupt; + } + } + + DirsPerBlock = volume->BlockSize / sizeof(ROOT); + DirBlocks = (Dir1Size + (volume->BlockSize - 1)) / volume->BlockSize; + DirTotal = (Dir1Size + (sizeof(DOS) - 1)) / sizeof(DOS); + stats.max_entries = DirTotal; + + NWFSPrint("[ Directory Pass 1 -- Verifying Directory Records ]\n"); + + for (DirCount = i = 0; i < DirBlocks; i++) + { + cbytes = NWReadFile(volume, + &volume->FirstDirectory, + 0, + Dir1Size, + i * volume->BlockSize, + (BYTE *)dos, + volume->BlockSize, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0, + TRUE); + + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error reading directory file\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + return NwInsufficientResources; + } + + for (owner = (ULONG) -1, j=0; j < DirsPerBlock; j++, DirCount++) + { + ccode = StrictValidateDirectoryRecord(volume, &dos[j], + DirCount, &stats); + } + + cbytes = NWWriteFile(volume, + &volume->FirstDirectory, + 0, + i * volume->BlockSize, + (BYTE *)dos, + volume->BlockSize, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + + if (cbytes != volume->BlockSize) + NWFSPrint("nwfs: error writing directory primary file\n"); + + cbytes = NWWriteFile(volume, + &volume->SecondDirectory, + 0, + i * volume->BlockSize, + (BYTE *)dos, + volume->BlockSize, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0); + + if (cbytes != volume->BlockSize) + NWFSPrint("nwfs: error writing directory mirror file\n"); + } + + NWFSPrint("[ Directory Pass 2 -- Verifying Root and Suballocation ]\n"); + + NWFSPrint("[ Directory Pass 3 -- Verifying Name Link Consistency ]\n"); + + NWFSPrint("[ Directory Pass 4 -- Checking User and Trustee Records ]\n"); + + NWFSPrint("[ Directory Pass 5 -- Checking for Cross Linked Files ]\n"); + + NWFSPrint("[ Directory Pass 6 -- Converting Lost Chains to Files\n"); + + ccode = UtilInitializeDirAssignHash(volume); + if (ccode) + { + NWFSPrint("nwfs: error during assign hash init\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return NwInsufficientResources; + } + + for (DirCount = i = 0; i < DirBlocks; i++) + { + cbytes = NWReadFile(volume, + &volume->FirstDirectory, + 0, + Dir1Size, + i * volume->BlockSize, + (BYTE *)dos, + volume->BlockSize, + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + 0, + TRUE); + + if (cbytes != volume->BlockSize) + { + NWFSPrint("nwfs: error reading directory file\n"); + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + return NwInsufficientResources; + } + + for (owner = (ULONG) -1, j=0; j < DirsPerBlock; j++, DirCount++) + { + ccode = StrictValidateDirectoryRecord(volume, dos, DirCount, &stats); + if (ccode) + { + } + + switch (dos[j].Subdirectory) + { + case ROOT_NODE: + if (owner == (ULONG) -1) + owner = 0; + root = (ROOT *) &dos[j]; + if (root->NameSpace == DOS_NAME_SPACE) + DirCount++; + break; + + case SUBALLOC_NODE: + if (owner == (ULONG) -1) + owner = 0; + break; + + case FREE_NODE: + break; + + case RESTRICTION_NODE: + user = (USER *) &dos[j]; + if (owner == (ULONG) -1) + owner = 0; + break; + + case TRUSTEE_NODE: + trustee = (TRUSTEE *) &dos[j]; + if (owner == (ULONG) -1) + owner = 0; + break; + + default: + if (owner == (ULONG) -1) + owner = dos[j].Subdirectory; + + if (dos[j].NameSpace == DOS_NAME_SPACE) + DirCount++; + break; + } + } + + ccode = UtilCreateDirAssignEntry(volume, owner, i, dos); + if (ccode) + { + NWFSPrint("nwrepair: error creating dir assign hash\n"); + DismountRawVolume(volume); + NWFSFree(dos); + return NwInsufficientResources; + } + } + + UtilFreeDirAssignHash(volume); + DismountRawVolume(volume); + NWFSFree(dos); + + NWFSPrint("bad_trustee_records : %d ", + (int)stats.bad_trustee_records); + NWFSPrint("bad_trustee_mask : %d\n", (int)stats.bad_trustee_mask); + NWFSPrint("bad_name_records : %d ", (int)stats.bad_name_records); + NWFSPrint("bad_root_records : %d\n", (int)stats.bad_root_records); + NWFSPrint("bad_root_flags : %d ", (int)stats.bad_root_flags); + NWFSPrint("bad_dos_records : %d\n", (int)stats.bad_dos_records); + NWFSPrint("bad_mac_records : %d ", (int)stats.bad_mac_records); + NWFSPrint("bad_nfs_records : %d\n", (int)stats.bad_nfs_records); + NWFSPrint("bad_nfs_extants : %d ", (int)stats.bad_nfs_extants); + NWFSPrint("bad_long_records : %d\n", (int)stats.bad_long_records); + NWFSPrint("bad_long_extants : %d ", (int)stats.bad_long_extants); + NWFSPrint("bad_nt_records : %d\n", (int)stats.bad_nt_records); + NWFSPrint("bad_nt_extants : %d ", (int)stats.bad_nt_extants); + NWFSPrint("bad_suballoc_records : %d\n",(int)stats.bad_suballoc_records); + NWFSPrint("bad_user_records : %d ", (int)stats.bad_user_records); + NWFSPrint("bad_free_records : %d\n", (int)stats.bad_free_records); + NWFSPrint("cross_linked_files : %d ", (int)stats.cross_linked_files); + NWFSPrint("orphaned_fat_chains : %d\n", (int)stats.orphaned_fat_chains); + NWFSPrint("unowned_trustee_records : %d ", + (int)stats.unowned_trustee_records); + NWFSPrint("orphaned_name_entries : %d\n", + (int)stats.orphaned_name_entries); + + NWFSPrint("[ Freeing Unassigned Clusters \n"); + + return 0; +} + +ULONG RepairTwoFiles(VOLUME *volume, ULONG *c1, ULONG *c2) +{ + return 0; +} + +ULONG StrictValidateDirectoryRecord(VOLUME *volume, DOS *dos, + ULONG DirNo, NWREPAIR_STATS *stats) +{ + switch (dos->Subdirectory) + { + case FREE_NODE: + if (NWFSCompare(&dos->FileAttributes, ZeroBuffer, + (sizeof(DOS) - sizeof(ULONG)))) + { + // repair free record + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_free_records++; + return 1; + } + return 0; + + case TRUSTEE_NODE: + { + register ULONG i; + TRUSTEE *trustee = (TRUSTEE *)dos; + + if ((trustee->Reserved1[0]) || (trustee->TrusteeCount > 16)) + { +#if (VERBOSE) + NWFSPrint("Invalid trustee record res1-%d trustees-%d\n", + (int)trustee->Reserved1[0], + (int)trustee->TrusteeCount); +#endif + stats->bad_trustee_records++; + return 1; + } + + for (i=0; i < 16; i++) + { + if (trustee->TrusteeMask[i] & ~TRUSTEE_VALID_MASK) + { +#if (VERBOSE) + NWFSPrint("Invalid trustee record mask-%08X MASK-%08X\n", + (unsigned)trustee->TrusteeMask[i], + (unsigned)TRUSTEE_VALID_MASK); +#endif + stats->bad_trustee_mask++; + return 1; + } + } + } + return 0; + + case ROOT_NODE: + { + ROOT *root = (ROOT *)dos; + ROOT3X *root3x = (ROOT3X *)dos; + + if ((root->NameSpace > 10) || (root->NameSpaceCount > 10)) + { +#if (VERBOSE) + NWFSPrint("Namespace/count (%d-%d) was > 10\n", + (int)root->NameSpace, (int)root->NameSpaceCount); +#endif + stats->bad_root_records++; + return 1; + } + + if (root->NameSpace != DOS_NAME_SPACE) + break; + + if ((volume->VolumeFlags & NDS_FLAG) || + (volume->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + if (root->VolumeFlags & ~VFLAGS_4X_MASK) + { +#if (VERBOSE) + NWFSPrint("root 4X volume flags invalid (%08X) mask-%08X\n", + (unsigned)root->VolumeFlags, + (unsigned)VFLAGS_4X_MASK); +#endif + stats->bad_root_flags++; + return 1; + } + } + else + { + if (root3x->VolumeFlags & ~VFLAGS_3X_MASK) + { +#if (VERBOSE) + NWFSPrint("root 3X volume flags invalid (%08X) mask-%08X\n", + (unsigned)root3x->VolumeFlags, + (unsigned)VFLAGS_3X_MASK); +#endif + stats->bad_root_flags++; + return 1; + } + } + } + return 0; + + case RESTRICTION_NODE: + { + USER *user = (USER *)dos; + + if ((user->Reserved1) || (user->TrusteeCount > 14)) + { +#if (VERBOSE) + NWFSPrint("Invalid user record res1-%d trustees-%d\n", + (int)user->Reserved1, + (int)user->TrusteeCount); +#endif + stats->bad_user_records++; + return 1; + } + } + return 0; + + case SUBALLOC_NODE: + { + SUBALLOC *suballoc = (SUBALLOC *)dos; + register ULONG i; + + if (suballoc->SequenceNumber > 4) + { +#if (VERBOSE) + NWFSPrint("Invalid suballocation record res-%d sequence-%d\n", + (int)suballoc->Reserved1, + (int)suballoc->SequenceNumber); +#endif + stats->bad_suballoc_records++; + return 1; + } + + for (i=0; i < 28; i++) + { + // if any suballocation table entries exceed volume + // clusters, zero the invalid fat heads. + if (suballoc->StartingFATChain[i] > volume->VolumeClusters) + suballoc->StartingFATChain[i] = 0; + } + } + return 0; + + default: + if (dos->NameSpace > 10) + { +#if (VERBOSE) + NWFSPrint("Invalid namespace record %d\n", (int)dos->NameSpace); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_name_records++; + return 1; + } + + { + MACINTOSH *mac = (MACINTOSH *)dos; + NFS *nfs = (NFS *)dos; + LONGNAME *longname = (LONGNAME *)dos; + NTNAME *nt = (NTNAME *)dos; + + switch (dos->NameSpace) + { + case DOS_NAME_SPACE: + if (NWValidDOSName(volume, dos->FileName, + dos->FileNameLength, 0, 0)) + { +#if (VERBOSE) + NWFSPrint("Invalid dos name\n"); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_dos_records++; + return 1; + } + return 0; + + case MAC_NAME_SPACE: + if (NWValidMACName(volume, mac->FileName, + mac->FileNameLength, 0, 0)) + { +#if (VERBOSE) + NWFSPrint("Invalid mac name\n"); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_mac_records++; + return 1; + } + return 0; + + case LONG_NAME_SPACE: + if (NWValidLONGName(volume, longname->FileName, + longname->FileNameLength, 0, 0)) + { +#if (VERBOSE) + NWFSPrint("Invalid long name\n"); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_long_records++; + return 1; + } + + if (longname->ExtantsUsed > 3) + { +#if (VERBOSE) + NWFSPrint("Invalid longname file extants-%d\n", + (int)longname->ExtantsUsed); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_long_extants++; + return 1; + } + + return 0; + + case UNIX_NAME_SPACE: + if (NWValidNFSName(volume, nfs->FileName, + nfs->TotalFileNameLength, 0, 0)) + { +#if (VERBOSE) + NWFSPrint("Invalid nfs name\n"); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_nfs_records++; + return 1; + } + + if (nfs->ExtantsUsed > 3) + { +#if (VERBOSE) + NWFSPrint("Invalid nfs file extants-%d\n", + (int)nfs->ExtantsUsed); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_nfs_extants++; + return 1; + } + return 0; + + case NT_NAME_SPACE: + if (NWValidLONGName(volume, nt->FileName, + nt->FileNameLength, 0, 0)) + { +#if (VERBOSE) + NWFSPrint("Invalid nt name\n"); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_nt_records++; + return 1; + } + + if (nt->ExtantsUsed > 3) + { +#if (VERBOSE) + NWFSPrint("Invalid nt file extants-%d\n", + (int)nt->ExtantsUsed); +#endif + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + + stats->bad_nt_extants++; + return 1; + } + return 0; + + default: + // set record as free + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG)-1; + return 1; + } + } + return 0; + } + return 0; +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwfs.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwfs.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwfs.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,403 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWFS.H +* DESCRIP : NWFS Volume and System On Disk Structures +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#ifndef _NWFS_ +#define _NWFS_ + +#define NWFS_GET_ATTRIBUTES 0x11 +#define NWFS_GET_TRUSTEES 0x12 +#define NWFS_GET_QUOTA 0x13 +#define NWFS_SET_ATTRIBUTES 0x14 +#define NWFS_SET_TRUSTEES 0x15 +#define NWFS_SET_QUOTA 0x16 + +#define NETWARE_286_ID 0x64 +#define NETWARE_386_ID 0x65 +#define PARTITION_ID 0xAA55 +#define NW3X_PARTITION 1 +#define NW4X_PARTITION 0 + +#define FOUR_K_BLOCK 3 +#define EIGHT_K_BLOCK 4 +#define SIXTEEN_K_BLOCK 5 +#define THIRTYTWO_K_BLOCK 6 +#define SIXTYFOUR_K_BLOCK 7 + +// these defines describe the location of the Hot Fix and Mirroring Tables + +#define MULTI_TRACK_COUNT 4 + +#define VOLUME_TABLE_LOCATION_0 0x20 +#define VOLUME_TABLE_LOCATION_1 0x40 +#define VOLUME_TABLE_LOCATION_2 0x60 +#define VOLUME_TABLE_LOCATION_3 0x80 + +#define HOTFIX_LOCATION_0 0x20 +#define HOTFIX_LOCATION_1 0x40 +#define HOTFIX_LOCATION_2 0x60 +#define HOTFIX_LOCATION_3 0x80 + +#define MIRROR_LOCATION_0 0x21 +#define MIRROR_LOCATION_1 0x41 +#define MIRROR_LOCATION_2 0x61 +#define MIRROR_LOCATION_3 0x81 + +#define HOTFIX_SIGNATURE "HOTFIX00" +#define MIRROR_SIGNATURE "MIRROR00" +#define VOLUME_SIGNATURE "NetWare Volumes" + +#define USER_ADDRESS_SPACE 0 +#define KERNEL_ADDRESS_SPACE 1 + +// +// memory tracking labels +// + +typedef struct _TRACKING +{ + BYTE *label; + ULONG units; + ULONG count; +} TRACKING; + +extern TRACKING HOTFIX_TRACKING; +extern TRACKING HOTFIX_DATA_TRACKING; +extern TRACKING HOTFIX_TABLE_TRACKING; +extern TRACKING MIRROR_TRACKING; +extern TRACKING MIRROR_DATA_TRACKING; +extern TRACKING HASH_TRACKING; +extern TRACKING EXT_HASH_TRACKING; +extern TRACKING BITBLOCK_TRACKING; +extern TRACKING BITBUFFER_TRACKING; +extern TRACKING NWPART_TRACKING; +extern TRACKING NWDISK_TRACKING; +extern TRACKING DISKBUF_TRACKING; +extern TRACKING TABLE_TRACKING; +extern TRACKING FAT_TRACKING; +extern TRACKING FATLRU_TRACKING; +extern TRACKING FATHASH_TRACKING; +extern TRACKING DIRLRU_TRACKING; +extern TRACKING DIRHASH_TRACKING; +extern TRACKING DIR_TRACKING; +extern TRACKING DIR_BLOCK_TRACKING; +extern TRACKING DIR_BLOCKHASH_TRACKING; +extern TRACKING EXT_BLOCK_TRACKING; +extern TRACKING EXT_BLOCKHASH_TRACKING; +extern TRACKING ASSN_BLOCK_TRACKING; +extern TRACKING ASSN_BLOCKHASH_TRACKING; +extern TRACKING BLOCK_TRACKING; +extern TRACKING CREATE_TRACKING; +extern TRACKING TRUSTEE_TRACKING; +extern TRACKING USER_TRACKING; +extern TRACKING NWDIR_TRACKING; +extern TRACKING NWEXT_TRACKING; +extern TRACKING FAT_WORKSPACE_TRACKING; +extern TRACKING DIR_WORKSPACE_TRACKING; +extern TRACKING EXT_WORKSPACE_TRACKING; +extern TRACKING CRT_WORKSPACE_TRACKING; +extern TRACKING SA_WORKSPACE_TRACKING; +extern TRACKING TRUNC_WORK_TRACKING; +extern TRACKING SECTOR_TRACKING; +extern TRACKING CLUSTER_TRACKING; +extern TRACKING VOLUME_TRACKING; +extern TRACKING VOLUME_WS_TRACKING; +extern TRACKING VOLUME_DATA_TRACKING; +extern TRACKING LRU_TRACKING; +extern TRACKING LRU_HASH_TRACKING; +extern TRACKING LRU_BUFFER_TRACKING; +extern TRACKING ALIGN_BUF_TRACKING; +extern TRACKING NAM_HASH_TRACKING; +extern TRACKING DNM_HASH_TRACKING; +extern TRACKING PAR_HASH_TRACKING; +extern TRACKING EXD_HASH_TRACKING; +extern TRACKING TRS_HASH_TRACKING; +extern TRACKING DEL_HASH_TRACKING; +extern TRACKING QUO_HASH_TRACKING; +extern TRACKING SUBALLOC_HEAD_TRACKING; +extern TRACKING PAGED_FAT_BUF_TRACKING; +extern TRACKING PAGED_WORK_BUF_TRACKING; +extern TRACKING PAGED_PART_BUF_TRACKING; +extern TRACKING PAGED_VOL_BUF_TRACKING; +extern TRACKING PAGED_SECT_BUF_TRACKING; +extern TRACKING SEMAPHORE_TRACKING; +extern TRACKING NAME_STORAGE_TRACKING; +extern TRACKING NWVP_TRACKING; +extern TRACKING BH_TRACKING; +extern TRACKING ASYNCH_HASH_TRACKING; + + +#define HOTFIX_TAG &HOTFIX_TRACKING +#define HOTFIX_DATA_TAG &HOTFIX_DATA_TRACKING +#define HOTFIX_TABLE_TAG &HOTFIX_TABLE_TRACKING +#define MIRROR_TAG &MIRROR_TRACKING +#define MIRROR_DATA_TAG &MIRROR_DATA_TRACKING +#define HASH_TAG &HASH_TRACKING +#define EXT_HASH_TAG &EXT_HASH_TRACKING +#define BITBLOCK_TAG &BITBLOCK_TRACKING +#define BITBUFFER_TAG &BITBUFFER_TRACKING +#define NWPART_TAG &NWPART_TRACKING +#define NWDISK_TAG &NWDISK_TRACKING +#define DISKBUF_TAG &DISKBUF_TRACKING +#define TABLE_TAG &TABLE_TRACKING +#define FAT_TAG &FAT_TRACKING +#define FATLRU_TAG &FATLRU_TRACKING +#define FATHASH_TAG &FATHASH_TRACKING +#define DIRLRU_TAG &DIRLRU_TRACKING +#define DIRHASH_TAG &DIRHASH_TRACKING +#define DIR_TAG &DIR_TRACKING +#define DIR_BLOCK_TAG &DIR_BLOCK_TRACKING +#define DIR_BLOCKHASH_TAG &DIR_BLOCKHASH_TRACKING +#define EXT_BLOCK_TAG &EXT_BLOCK_TRACKING +#define EXT_BLOCKHASH_TAG &EXT_BLOCKHASH_TRACKING +#define ASSN_BLOCK_TAG &ASSN_BLOCK_TRACKING +#define ASSN_BLOCKHASH_TAG &ASSN_BLOCKHASH_TRACKING +#define BLOCK_TAG &BLOCK_TRACKING +#define CREATE_TAG &CREATE_TRACKING +#define TRUSTEE_TAG &TRUSTEE_TRACKING +#define USER_TAG &USER_TRACKING +#define NWDIR_TAG &NWDIR_TRACKING +#define NWEXT_TAG &NWEXT_TRACKING +#define FAT_WORKSPACE_TAG &FAT_WORKSPACE_TRACKING +#define DIR_WORKSPACE_TAG &DIR_WORKSPACE_TRACKING +#define EXT_WORKSPACE_TAG &EXT_WORKSPACE_TRACKING +#define CRT_WORKSPACE_TAG &CRT_WORKSPACE_TRACKING +#define SA_WORKSPACE_TAG &SA_WORKSPACE_TRACKING +#define TRUNC_WORK_TAG &TRUNC_WORK_TRACKING +#define SECTOR_TAG &SECTOR_TRACKING +#define CLUSTER_TAG &CLUSTER_TRACKING +#define VOLUME_TAG &VOLUME_TRACKING +#define VOLUME_WS_TAG &VOLUME_WS_TRACKING +#define VOLUME_DATA_TAG &VOLUME_DATA_TRACKING +#define LRU_TAG &LRU_TRACKING +#define LRU_HASH_TAG &LRU_HASH_TRACKING +#define LRU_BUFFER_TAG &LRU_BUFFER_TRACKING +#define ALIGN_BUF_TAG &ALIGN_BUF_TRACKING +#define NAM_HASH_TAG &NAM_HASH_TRACKING +#define DNM_HASH_TAG &DNM_HASH_TRACKING +#define PAR_HASH_TAG &PAR_HASH_TRACKING +#define EXD_HASH_TAG &EXD_HASH_TRACKING +#define TRS_HASH_TAG &TRS_HASH_TRACKING +#define DEL_HASH_TAG &DEL_HASH_TRACKING +#define QUO_HASH_TAG &QUO_HASH_TRACKING +#define SUBALLOC_HEAD_TAG &SUBALLOC_HEAD_TRACKING +#define PAGED_FAT_BUF &PAGED_FAT_BUF_TRACKING +#define PAGED_WORK_BUF &PAGED_WORK_BUF_TRACKING +#define PAGED_PART_BUF &PAGED_PART_BUF_TRACKING +#define PAGED_VOL_BUF &PAGED_VOL_BUF_TRACKING +#define PAGED_SECT_BUF &PAGED_SECT_BUF_TRACKING +#define SEMAPHORE_TAG &SEMAPHORE_TRACKING +#define NAME_STORAGE_TAG &NAME_STORAGE_TRACKING +#define NWVP_TAG &NWVP_TRACKING +#define BH_TAG &BH_TRACKING +#define ASYNCH_HASH_TAG &ASYNCH_HASH_TRACKING + +// +// Hotfix and Mirroring Tables occupy the first sections +// of a Netware 386 Partition. There are four copies of these +// tables. Netware treats all on-disk structures as zero relative +// from the beginning of any segment of the disk. Following +// these tables are the Volume Segment Tables that define +// specific information about a volume. There are four copies of these +// tables as well. All of these copies are aligned on track boundries +// for fault-tolerance so in the event a track fails, at least one good +// copy of these tables is preserved. +// +// The Volume Tables contain all the information about volume +// segments on that drive, and volumes that occupy the partition. +// Also in these tables are stored the logical starting block for +// the volume FAT and the first Directory Entry. The Netware directory +// is actually treated just like a file, and is mapped via the FAT +// table. This is different that the way MS-DOS implements their +// directory, which chains directory blocks and stores an LBA in each +// directory object. +// +// Volumes that have more than one volume segment require that the +// host operating system read all the disks present in the system +// and their corresponding VolumeTables to locate the segments for +// a particular Netware Volume. If any segments or disks are missing +// then it is impossible to properly mount a Netware Volume unless a +// mirror is present. +// +// The Netware FAT (File Allocation Table) begins at logical +// block 0 on a logical Netware volume. There are always two +// copies of the FAT per logical volume. The first field of the FAT +// points to the file index. Netware allows files to have "holes" +// to preserve disk space. For example, if someone creates a file +// that is 4MB, then only writes two blocks, one a 0 and another at 16K, +// the index field will point to the actual block index within the +// logical file (i.e. FAT enties would be 0, 4). The second field is +// the continuation index into the FAT to the next entry for the file. +// The Netware FAT is identical to a DOS FAT in that it is a true +// one-to-one mapping block-to-fat entry. If someone tries to read an +// offset within a file that overlaps a "hole", zeros are returned +// indicating that no data has actually been written there. +// + +#if (LINUX) + +/* Boot sector info (62 byte structure) */ + +struct BOOT_SECTOR +{ + BYTE Jmp[3] __attribute__ ((packed)); + BYTE OEMname[8] __attribute__ ((packed)); + WORD bps __attribute__ ((packed)); + BYTE SecPerClstr __attribute__ ((packed)); + WORD ResSectors __attribute__ ((packed)); + BYTE FATs __attribute__ ((packed)); + WORD RootDirEnts __attribute__ ((packed)); + WORD Sectors __attribute__ ((packed)); + BYTE Media __attribute__ ((packed)); + WORD SecPerFAT __attribute__ ((packed)); + WORD SecPerTrack __attribute__ ((packed)); + WORD Heads __attribute__ ((packed)); + ULONG HiddenSecs __attribute__ ((packed)); + ULONG HugeSecs __attribute__ ((packed)); + BYTE DriveNum __attribute__ ((packed)); + BYTE Rsvd1 __attribute__ ((packed)); + BYTE BootSig __attribute__ ((packed)); + ULONG VolID __attribute__ ((packed)); + BYTE VolLabel[11] __attribute__ ((packed)); + BYTE FileSysType[8] __attribute__ ((packed)); /* 62 bytes */ +}; + +/* Partition Table Entry info. 16 bytes */ + +struct PartitionTableEntry +{ + BYTE fBootable __attribute__ ((packed)); + BYTE HeadStart __attribute__ ((packed)); + BYTE SecStart __attribute__ ((packed)); + BYTE CylStart __attribute__ ((packed)); + BYTE SysFlag __attribute__ ((packed)); + BYTE HeadEnd __attribute__ ((packed)); + BYTE SecEnd __attribute__ ((packed)); + BYTE CylEnd __attribute__ ((packed)); + ULONG StartLBA __attribute__ ((packed)); + ULONG nSectorsTotal __attribute__ ((packed)); +}; + +typedef struct _VOLUME_TABLE_ENTRY +{ + BYTE VolumeName[16] __attribute__ ((packed)); // length preceded string format + ULONG LastVolumeSegment __attribute__ ((packed)); + ULONG VolumeSignature __attribute__ ((packed)); + ULONG VolumeRoot __attribute__ ((packed)); + ULONG SegmentSectors __attribute__ ((packed)); + ULONG VolumeClusters __attribute__ ((packed)); + ULONG SegmentClusterStart __attribute__ ((packed)); // Logical Block Segment Start + ULONG FirstFAT __attribute__ ((packed)); // FAT index for 1st FAT Table + ULONG SecondFAT __attribute__ ((packed)); // FAT index for 2nd FAT Table + ULONG FirstDirectory __attribute__ ((packed)); // FAT index for 1st Directory Block + ULONG SecondDirectory __attribute__ ((packed)); // FAT index for 2nd Directory Block + ULONG Padding __attribute__ ((packed)); +} VOLUME_TABLE_ENTRY; + +typedef struct _VOLUME_TABLE +{ + BYTE VolumeTableSignature[16] __attribute__ ((packed)); // length preceded string here + ULONG NumberOfTableEntries __attribute__ ((packed)); + ULONG Reserved[3] __attribute__ ((packed)); + VOLUME_TABLE_ENTRY VolumeEntry[MAX_VOLUME_ENTRIES] __attribute__ ((packed)); +} VOLUME_TABLE; + +typedef struct _HOT_FIX_BLOCK_TABLE +{ + ULONG HotFix1 __attribute__ ((packed)); // these tables are sector based offsets from + ULONG BadBlock1 __attribute__ ((packed)); + ULONG HotFix2 __attribute__ ((packed)); // the beginning of the partition + ULONG BadBlock2 __attribute__ ((packed)); +} HOTFIX_BLOCK_TABLE; + +typedef struct _HOTFIX { + BYTE HotFixStamp[8] __attribute__ ((packed)); + ULONG PartitionID __attribute__ ((packed)); // Novell HDK/SDK says ..... + ULONG HotFixFlags __attribute__ ((packed)); // (WORD / WORD - data bits/synch number) + ULONG HotFixDateStamp __attribute__ ((packed)); // (B/B/B/B BSize/BUMask/BShift/BMask) + ULONG HotFixTotalSectors __attribute__ ((packed)); + ULONG HotFixSize __attribute__ ((packed)); + HOTFIX_BLOCK_TABLE HotFixTable[MAX_HOTFIX_BLOCKS] __attribute__ ((packed)); +} HOTFIX; + +typedef struct _MIRROR +{ + BYTE MirrorStamp[8] __attribute__ ((packed)); + ULONG PartitionID __attribute__ ((packed)); // Novell's website says .... + ULONG MirrorFlags __attribute__ ((packed)); // (B/B/W DataBadBits/MirrorActive/SyncNumber) + ULONG Reserved1 __attribute__ ((packed)); // (B/B/B/B BSize/BUMask/BShift/BMask) + ULONG MirrorStatus __attribute__ ((packed)); // (B/B/W DeviceBadBits/DeviceActive/SynchNumber) + ULONG MirrorTotalSectors __attribute__ ((packed)); + ULONG MirrorGroupID __attribute__ ((packed)); + ULONG MirrorMemberID[MAX_MIRRORS] __attribute__ ((packed)); +} MIRROR; + +typedef struct _FAT_ENTRY +{ + long FATIndex __attribute__ ((packed)); + long FATCluster __attribute__ ((packed)); +} FAT_ENTRY; + +typedef struct _SUBALLOC_DIR +{ + ULONG Flag __attribute__ ((packed)); + ULONG Reserved1 __attribute__ ((packed)); + BYTE ID __attribute__ ((packed)); + BYTE SequenceNumber __attribute__ ((packed)); + BYTE Reserved2[2] __attribute__ ((packed)); + ULONG SubAllocationList __attribute__ ((packed)); + ULONG StartingFATChain[28] __attribute__ ((packed)); +} SUBALLOC_DIR; + +#endif + + +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwhash.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwhash.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwhash.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwhash.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,276 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWHASH.H +* DESCRIP : NWFS Netware Partition Module +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#ifndef _NWFS_HASH_ +#define _NWFS_HASH_ + +// file data states for read ahead and suballocation +#define NWFS_UNMODIFIED 0x00 +#define NWFS_MODIFIED 0x01 +#define NWFS_SEQUENTIAL 0x02 + +#if (LINUX) + +typedef struct _RAPID_FAT { + struct _RAPID_FAT *next; + struct _RAPID_FAT *prior; + ULONG BlockNo; + ULONG *IndexTable; + ULONG TableSize; +} RAPID_FAT; + +typedef struct _FILE_CONTROL_BLOCK +{ + RAPID_FAT *head; + RAPID_FAT *tail; + +#if (LINUX_SLEEP) + struct semaphore Semaphore; +#endif + +} FCB; + +typedef struct _HASH +{ + struct _HASH *next; + struct _HASH *prior; + struct _HASH *dnext; + struct _HASH *dprior; + struct _HASH *pnext; + struct _HASH *pprior; + struct _HASH *nlnext; + struct _HASH *nlprior; + struct _HASH *nlroot; + + ULONG Parent; + ULONG Root; + ULONG DirNo; + ULONG NameLink; + + ULONG Signature; + ULONG NextTrustee; + ULONG Blocks; + ULONG Flags; + +#if (HASH_FAT_CHAINS) + ULONG FirstBlock; + ULONG FileSize; + ULONG FileAttributes; +#endif + +#if (LINUX_SLEEP) + struct semaphore Semaphore; +#endif + + BYTE State; + ULONG TurboFATCluster; + ULONG TurboFATIndex; + BYTE NameSpace; + WORD NameLength; + BYTE *Name; +} HASH; + +typedef struct _THASH +{ + struct _THASH *next; + struct _THASH *prior; + struct _THASH *dnext; + struct _THASH *dprior; + struct _THASH *pnext; + struct _THASH *pprior; + struct _THASH *nlnext; + struct _THASH *nlprior; + struct _THASH *trustee_list; + + ULONG Parent; + ULONG DirNo; + + ULONG TrusteeCount; + ULONG NextTrustee; + ULONG FileEntryNumber; + ULONG Flags; + ULONG Attributes; +} THASH; + +typedef struct _UHASH +{ + struct _UHASH *next; + struct _UHASH *prior; + struct _UHASH *dnext; + struct _UHASH *dprior; + struct _UHASH *pnext; + struct _UHASH *pprior; + struct _UHASH *nlnext; + struct _UHASH *nlprior; + + ULONG Parent; + ULONG DirNo; + + ULONG TrusteeCount; +} UHASH; + +typedef struct _HASH_LIST { + HASH *head; + HASH *tail; +} HASH_LIST; + +typedef struct _THASH_LIST { + THASH *head; + THASH *tail; +} THASH_LIST; + +typedef struct _UHASH_LIST { + UHASH *head; + UHASH *tail; +} UHASH_LIST; + +typedef struct _EXTENDED_DIR_HASH +{ + struct _EXTENDED_DIR_HASH *next; + struct _EXTENDED_DIR_HASH *prior; + ULONG Signature; + ULONG Length; + ULONG ExtDirNo; + ULONG Parent; + ULONG Root; + BYTE NameSpace; + BYTE Flags; + BYTE ControlFlags; + BYTE NameLength; + BYTE Name[1]; +} EXTENDED_DIR_HASH; + +typedef struct _EXT_HASH_LIST { + EXTENDED_DIR_HASH *head; + EXTENDED_DIR_HASH *tail; +} EXT_HASH_LIST; + +typedef union _HASH_UNION +{ + UHASH UHash; + THASH THash; + HASH Hash; +} HASH_UNION; + +#endif + + +typedef struct _DIR_BLOCK_HASH +{ + struct _DIR_BLOCK_HASH *next; + struct _DIR_BLOCK_HASH *prior; + struct _DIR_BLOCK_HASH *dnext; + struct _DIR_BLOCK_HASH *dprior; + ULONG Cluster1; + ULONG Cluster2; + ULONG BlockNo; + ULONG DelBlockNo; +} DIR_BLOCK_HASH; + +typedef struct _DIR_BLOCK_HASH_LIST +{ + DIR_BLOCK_HASH *head; + DIR_BLOCK_HASH *tail; +} DIR_BLOCK_HASH_LIST; + +typedef struct _DIR_ASSIGN_HASH +{ + struct _DIR_ASSIGN_HASH *next; + struct _DIR_ASSIGN_HASH *prior; + struct _DIR_ASSIGN_HASH *dnext; + struct _DIR_ASSIGN_HASH *dprior; + struct _DIR_ASSIGN_HASH *hnext; + struct _DIR_ASSIGN_HASH *hprior; + ULONG BlockNo; + ULONG DirOwner; + ULONG DirBlockNo; + BYTE FreeList[((IO_BLOCK_SIZE / 128) / 8)]; +} DIR_ASSIGN_HASH; + +typedef struct _DIR_ASSIGN_HASH_LIST +{ + DIR_ASSIGN_HASH *head; + DIR_ASSIGN_HASH *tail; +} DIR_ASSIGN_HASH_LIST; + +#define DEFAULT_HASH_SIZE 1024 + +#define NUMBER_OF_NAME_HASH_ENTRIES DEFAULT_HASH_SIZE +#define VOLUME_NAME_HASH_SIZE NUMBER_OF_NAME_HASH_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_DIR_NUMBER_ENTRIES DEFAULT_HASH_SIZE +#define DIR_NUMBER_HASH_SIZE NUMBER_OF_DIR_NUMBER_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_BLOCK_HASH_ENTRIES DEFAULT_HASH_SIZE +#define BLOCK_NUMBER_HASH_SIZE NUMBER_OF_BLOCK_HASH_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_LRU_HASH_ENTRIES DEFAULT_HASH_SIZE +#define BLOCK_LRU_HASH_SIZE NUMBER_OF_LRU_HASH_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_PARENT_ENTRIES DEFAULT_HASH_SIZE +#define PARENT_HASH_SIZE NUMBER_OF_PARENT_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_TRUSTEE_ENTRIES DEFAULT_HASH_SIZE +#define TRUSTEE_HASH_SIZE NUMBER_OF_TRUSTEE_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_QUOTA_ENTRIES DEFAULT_HASH_SIZE +#define USER_QUOTA_HASH_SIZE NUMBER_OF_QUOTA_ENTRIES * sizeof(HASH_LIST) + +#define NUMBER_OF_EXT_HASH_ENTRIES DEFAULT_HASH_SIZE +#define EXT_HASH_SIZE NUMBER_OF_EXT_HASH_ENTRIES * sizeof(EXT_HASH_LIST) + +#define NUMBER_OF_ASSIGN_BLOCK_ENTRIES DEFAULT_HASH_SIZE +#define ASSIGN_BLOCK_HASH_SIZE NUMBER_OF_ASSIGN_BLOCK_ENTRIES * sizeof(DIR_ASSIGN_HASH_LIST) + +#define NUMBER_OF_DIR_BLOCK_ENTRIES DEFAULT_HASH_SIZE +#define DIR_BLOCK_HASH_SIZE NUMBER_OF_DIR_BLOCK_ENTRIES * sizeof(DIR_BLOCK_HASH_LIST) + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwioctl.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwioctl.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwioctl.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,138 @@ +/*++ + +Copyright (c) 1989-1999 Microsoft Corporation +Copyright (c) 1998-1999 Jeff V. Merkey + +Module Name: + + NwIoctl.h + +Abstract: + + This module defines the data structures used to communicate the + Disk/Segment/Volume relationships of Netware volumes, Trustee Database + information, and NetWare Name Space Information from User Mode + to Kernel Mode. + + It is included by both the user mode MountVolume tool and the kernel + NwfsRo.sys driver. + +Authors: + + David Goebel (davidg@balder.com) 19-Jan-1999 + Jeff Merkey (jmerkey@utah-nac.org) 19-Jan-1999 + +--*/ + +#ifndef _NWIOCTL_ +#define _NWIOCTL_ + +// +// First define the name of the file system device. +// + +#define NWFS_DEVICE_NAME L"NwFsRo" +#define NWFS_DEVICE_NAME_W32 "\\\\.\\NwFsRo" + +// +// These are the current versions that must be in sync. +// + +#define NWFSRO_MAJOR_VERSION 2 +#define NWFSRO_MINOR_VERSION 0 + +// +// First define the Ioctl code to be used to transmit the information +// from user mode to kernel mode. Note that we need hooks for both +// IRP_MJ_DEVICE_CONTROL and IRP_MJ_FILE_SYSTEM_CONTROL as the former +// gets invoked on NT 4 and the later on NT 5. +// + +#define IOCTL_QUERY_ALL_DISKS CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, \ + 0xD414, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) +#define FSCTL_QUERY_ALL_DISKS IOCTL_QUERY_ALL_DISKS + +#define IOCTL_MOUNT_VOLUME CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, \ + 0xD415, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) +#define FSCTL_MOUNT_VOLUME IOCTL_MOUNT_VOLUME + +#define IOCTL_VOLUME_TRUSTEE_INFO CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, \ + 0xD416, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) +#define FSCTL_VOLUME_TRUSTEE_INFO IOCTL_VOLUME_TRUSTEE_INFO + +#define IOCTL_VOLUME_USER_RESTRICT CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, \ + 0xD417, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) +#define FSCTL_VOLUME_USER_RESTRICT IOCTL_VOLUME_USER_RESTRICT + +#define IOCTL_VOLUME_NAME_SPACE CTL_CODE(FILE_DEVICE_DISK_FILE_SYSTEM, \ + 0xD418, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) +#define FSCTL_VOLUME_NAME_SPACE IOCTL_VOLUME_NAME_SPACE + +// +// The following structues passed in to IOCTL_QUERY_ALL_DISKS +// + +typedef struct _DISK_HANDLES +{ + HANDLE Partition0Handle; // disk + HANDLE PartitionHandle; // partition +} DISK_HANDLES, *PDISK_HANDLES; + +typedef struct _DISK_POINTERS +{ + PVOID Partition0Pointer; // disk + PVOID PartitionPointer; // partition +} DISK_POINTERS, *PDISK_POINTERS; + +typedef struct _DISK_ARRAY +{ + // + // Version info so that the file system can detect a mis-match. + // + + USHORT MajorVersion; + USHORT MinorVersion; + + // + // The total size of the structure. Used for sanity checking when + // enumerating through the segment layout records. + // + + ULONG StructureSize; + + // + // Function code to enhace functionality for the future. Currently + // only two values are legal. + // + + ULONG FunctionCode; + ULONG PartitionCount; + + // + // If mounting a volume, here is the label + // + + UCHAR VolumeLabel[16]; + + union { + + DISK_HANDLES Handles[1]; + DISK_POINTERS Pointers[1]; + }; + +} DISK_ARRAY, *PDISK_ARRAY; + +#define NWFS_MOUNT_VOLUME 0x00000101 +#define NWFS_MOUNT_ALL_VOLUMES 0x00000102 + +#endif // _NWIOCTL_ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwpart.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwpart.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwpart.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwpart.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,228 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWPART.C +* DESCRIP : NWFS Netware Partition Module +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +ULONG segment_table_count; +segment_info_table segment_table[256]; +ULONG segment_mark_table[256]; +ULONG hotfix_table_count; +hotfix_info_table hotfix_table[256]; + +BYTE NwPartSignature[16] = { 0, 'N', 'w', '_', 'P', 'a', 'R', 't', 'I', + 't', 'I', 'o', 'N', 0, 0, 0 }; + +BYTE NetwareBootSector[512] = +{ + 0xFA, 0xEB, 0x74, 0x43, 0x4F, 0x50, 0x59, 0x52, + 0x49, 0x47, 0x48, 0x54, 0x20, 0x28, 0x43, 0x29, + 0x20, 0x32, 0x30, 0x30, 0x30, 0x20, 0x54, 0x52, + 0x47, 0x2C, 0x20, 0x49, 0x4E, 0x43, 0x20, 0x00, + 0x1A, 0x54, 0x52, 0x47, 0x00, 0x1A, 0x18, 0x49, + 0x4E, 0x56, 0x41, 0x4C, 0x49, 0x44, 0x20, 0x50, + 0x41, 0x52, 0x54, 0x49, 0x54, 0x49, 0x4F, 0x4E, + 0x20, 0x54, 0x41, 0x42, 0x4C, 0x45, 0x00, 0x4D, + 0x49, 0x53, 0x53, 0x49, 0x4E, 0x47, 0x20, 0x4F, + 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4E, 0x47, + 0x20, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4D, 0x00, + 0x45, 0x52, 0x52, 0x4F, 0x52, 0x20, 0x4C, 0x4F, + 0x41, 0x44, 0x49, 0x4E, 0x47, 0x20, 0x4F, 0x50, + 0x45, 0x52, 0x41, 0x54, 0x49, 0x4E, 0x47, 0x20, + 0x53, 0x59, 0x53, 0x54, 0x45, 0x4D, 0x00, 0x33, + 0xC0, 0x8E, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC, + 0x00, 0x7C, 0xFB, 0xBE, 0x00, 0x7C, 0xBF, 0x00, + 0x06, 0xB9, 0x00, 0x02, 0xFC, 0xF3, 0xA4, 0xEA, + 0x94, 0x06, 0x00, 0x00, 0xB9, 0x04, 0x00, 0xBE, + 0xBE, 0x07, 0x80, 0x3C, 0x80, 0x74, 0x16, 0x83, + 0xC6, 0x10, 0xE2, 0xF6, 0xBE, 0x27, 0x06, 0xAC, + 0x0A, 0xC0, 0x74, 0x06, 0xB4, 0x0E, 0xCD, 0x10, + 0xEB, 0xF5, 0xFB, 0xEB, 0xFE, 0x8B, 0xFE, 0x49, + 0x74, 0x0D, 0x83, 0xC6, 0x10, 0x80, 0x3C, 0x80, + 0x75, 0xF5, 0xBE, 0x27, 0x06, 0xEB, 0xE0, 0xBE, + 0x05, 0x00, 0x8B, 0x15, 0x8B, 0x4D, 0x02, 0xBB, + 0x00, 0x7C, 0xB8, 0x01, 0x02, 0xCD, 0x13, 0x73, + 0x0C, 0x33, 0xC0, 0xCD, 0x13, 0x4E, 0x75, 0xEF, + 0xBE, 0x58, 0x06, 0xEB, 0xC2, 0x59, 0x81, 0x3E, + 0xFE, 0x7D, 0x55, 0xAA, 0x74, 0x05, 0xBE, 0x3F, + 0x06, 0xEB, 0xB4, 0x8B, 0xF7, 0xEA, 0x00, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void SyncDisks(void) +{ +#if (LINUX_UTIL) + register ULONG j; + + for (j=0; j < MAX_DISKS; j++) + { + if (SystemDisk[j] && SystemDisk[j]->PhysicalDiskHandle) + SyncDevice((ULONG)SystemDisk[j]->PhysicalDiskHandle); + } +#endif +} + +BYTE *get_block_descrip(ULONG Type) +{ + switch(Type) + { + case FOUR_K_BLOCK: return "4K ClusterSize"; + case EIGHT_K_BLOCK: return "8K ClusterSize"; + case SIXTEEN_K_BLOCK: return "16K ClusterSize"; + case THIRTYTWO_K_BLOCK: return "32K ClusterSize"; + case SIXTYFOUR_K_BLOCK: return "64K ClusterSize"; + default: return "??? ClusterSize"; + } +} + +ULONG get_block_value(ULONG Type) +{ + switch(Type) + { + case FOUR_K_BLOCK: return 4096; + case EIGHT_K_BLOCK: return 8192; + case SIXTEEN_K_BLOCK: return 16384; + case THIRTYTWO_K_BLOCK: return 32768; + case SIXTYFOUR_K_BLOCK: return 65536; + default: return 0; + } +} + +// hotfix tables are laid out at 20 sector intervals +// starting at offset 20 (dec) from the start of a Netware partition +// mirroring tables follow the same layout rules, except these tables +// start at sector 21 (dec) from the start of the partition and continue +// at 20 sector intervals. There are four copies of these tables. +// +// The current layout of hotfixing is in fact a remnant of the days +// of legacy disk drives. In the early days of PC architecture devices, +// using this layout guaranteed that at least one copy of these tables +// would be recoverable because this addressing insured that multiple +// copies of the hot fix and mirroring tables would reside on separate +// spindles of an HDD device. Today, drives are all translated and +// sector:head:cylinder addressing is now logical rather than physical. +// Modern HDD devices also provide internal hot fix support for +// redirection of defective sectors. Hotfixing does, however, still +// provide an excellent mechanism for performing sector error +// redirection as an internal file system component for those systems +// with older or less sophisticated hardware, and may on some +// manufacturers hardware provide some benefit. With most modern +// disk devices, however, hotfixing just wastes disk space. +// + +void FreePartitionResources(void) +{ + register ULONG i; + extern void displayMemoryList(void); + extern void free_bh_list(void); + extern BYTE *LRUBlockHash; + extern ULONG LRUBlockHashLimit; + + for (i=0; i < MAX_VOLUMES; i++) + { + if (VolumeTable[i]) + NWFSFree(VolumeTable[i]); + VolumeTable[i] = 0; + } + + if (LRUBlockHash) + NWFSFree(LRUBlockHash); + LRUBlockHash = 0; + LRUBlockHashLimit = 0; + + FreeLRU(); + + if (ZeroBuffer) + NWFSFree(ZeroBuffer); + ZeroBuffer = 0; + + // release hash node free list + FreeHashNodes(); + +#if (LINUX_20 | LINUX_22 | LINUX_24) + // release IO buffer heads + free_bh_list(); +#endif + + if (MemoryAllocated != MemoryFreed) + { + NWFSPrint("nwfs: %d bytes of memory leaked!!! alloc-%d free-%d\n", + (int)(MemoryAllocated - MemoryFreed), + (int)MemoryAllocated, (int)MemoryFreed); + displayMemoryList(); + } + else + { +#if (VERBOSE) + NWFSPrint("nwfs: physical memory allocated-%d freed-%d inuse-%d\n", + (int)MemoryAllocated, (int)MemoryFreed, (int)MemoryInUse); +#endif + } + + if (PagedMemoryAllocated != PagedMemoryFreed) + { + NWFSPrint("nwfs: %d bytes of paged memory leaked!!! alloc-%d free-%d\n", + (int)(PagedMemoryAllocated - PagedMemoryFreed), + (int)PagedMemoryAllocated, (int)PagedMemoryFreed); + displayMemoryList(); + } + else + { +#if (VERBOSE) + NWFSPrint("nwfs: virtual memory allocated-%d freed-%d inuse-%d\n", + (int)PagedMemoryAllocated, (int)PagedMemoryFreed, + (int)PagedMemoryInUse); +#endif + } + return; + +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwproc.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwproc.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwproc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwproc.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,529 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWPROC.H +* DESCRIP : NWFS External Declarations +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#ifndef _NWFS_EXTERNS_ +#define _NWFS_EXTERNS_ + +extern ULONG MajorVersion; +extern ULONG MinorVersion; +extern ULONG BuildVersion; +extern ULONG exitFlag; +extern ULONG consoleHandle; +extern ULONG MaximumNumberOfVolumes; +extern ULONG NumberOfVolumes; +extern ULONG TotalDisks; +extern ULONG MaximumDisks; +extern ULONG TotalNWParts; +extern ULONG MaximumNWParts; +extern ULONG InstanceCounter; +extern ULONG LogicalBlockSize; +extern NWDISK *SystemDisk[MAX_DISKS]; +extern VOLUME *VolumeTable[MAX_VOLUMES]; +extern ULONG VolumeMountedTable[MAX_VOLUMES]; + +extern ULONG MemoryAllocated; +extern ULONG MemoryFreed; +extern ULONG MemoryInUse; +extern ULONG PagedMemoryAllocated; +extern ULONG PagedMemoryFreed; +extern ULONG PagedMemoryInUse; +extern BYTE *ZeroBuffer; +extern BYTE NwPartSignature[16]; +extern ULONG (*RemirrorProcessPtr)(ULONG); +extern ULONG cHandle; + +#if (LINUX_UTIL) +extern ULONG HasColor; +#endif + +extern ULONG HOTFIX_TRACK_OFFSET[MULTI_TRACK_COUNT]; +extern ULONG MIRROR_TRACK_OFFSET[MULTI_TRACK_COUNT]; +extern ULONG VOLTABLE_TRACK_OFFSET[MULTI_TRACK_COUNT]; + +extern ULONG DiskDevices[]; +extern MIRROR_LRU *VolumeLRUListHead; +extern MIRROR_LRU *VolumeLRUListTail; + +extern ASYNCH_IO *aio_free_head; +extern ASYNCH_IO *aio_free_tail; +extern ULONG aio_free_count; + +extern ULONG DataLRUActive; +extern ULONG JournalLRUActive; +extern ULONG FATLRUActive; +extern LRU_HANDLE DataLRU; +extern LRU_HANDLE JournalLRU; +extern LRU_HANDLE FATLRU; + +extern void InitNWFS(void); + +extern void NWLockNWVP(void); +extern void NWUnlockNWVP(void); +extern void NWLockHOTFIX(void); +extern void NWUnlockHOTFIX(void); +extern void NWFSVolumeScan(void); +extern void NWFSVolumeClose(void); +extern void NWFSRemirror(void); +extern void NWFSFlush(void); +extern void NWEditVolumes(void); + +extern void FreeWorkspace(VOLUME *volume, VOLUME_WORKSPACE *wk); +extern VOLUME_WORKSPACE *AllocateWorkspace(VOLUME *volume); +extern void FreeNSWorkspace(VOLUME *volume, VOLUME_WORKSPACE *wk); +extern VOLUME_WORKSPACE *AllocateNSWorkspace(VOLUME *volume); + +// CONSOLE.C + +extern void ClearScreen(ULONG context); +extern void WaitForKey(void); + +extern ULONG AllocateSemaphore(void *sema, ULONG value); +extern long WaitOnSemaphore(void *sema); +extern long SignalSemaphore(void *sema); + +extern ULONG SetPartitionTableGeometry(BYTE *hd, BYTE *sec, BYTE *cyl, + ULONG sector, ULONG diskHeads, + ULONG diskSectors); +extern ULONG SetPartitionTableValues(struct PartitionTableEntry *Part, + ULONG Type, ULONG StartingSector, + ULONG EndingSector, ULONG Flag, + ULONG diskHeads, ULONG diskSectors); +extern ULONG ValidatePartitionExtants(ULONG disk); + +extern BYTE *get_partition_type(ULONG PartitionType); +extern void GetNumberOfDisks(ULONG *disk_count); +extern ULONG GetDiskInfo(ULONG disk_number, DISK_INFO *disk_info); +extern ULONG GetPartitionInfo(ULONG disk_number, ULONG partition_number, + PARTITION_INFO *part_info); +extern ULONG SetPartitionInfo(ULONG disk_number, PARTITION_INFO *part); +extern ULONG NWAllocateUnpartitionedSpace(void); +extern void NWEditPartitions(void); + +extern ULONG ReadPhysicalVolumeCluster(VOLUME *volume, ULONG Cluster, BYTE *Buffer, + ULONG size, ULONG priority); +extern ULONG WritePhysicalVolumeCluster(VOLUME *volume, ULONG Cluster, BYTE *Buffer, + ULONG size, ULONG priority); +extern ULONG ZeroPhysicalVolumeCluster(VOLUME *volume, ULONG Cluster, ULONG priority); +extern ULONG ReadClusterWithOffset(VOLUME *volume, ULONG Cluster, ULONG offset, + BYTE *buf, ULONG size, ULONG as, + ULONG *retCode, ULONG priority); +extern ULONG WriteClusterWithOffset(VOLUME *volume, ULONG Cluster, ULONG offset, + BYTE *buf, ULONG size, ULONG as, + ULONG *retCode, ULONG priority); + +extern ULONG ReadAbsoluteVolumeCluster(VOLUME *volume, ULONG Cluster, + BYTE *Buffer); +extern ULONG WriteAbsoluteVolumeCluster(VOLUME *volume, ULONG Cluster, + BYTE *Buffer); + +extern ULONG FreeVolumeLRU(VOLUME *volume); +extern void NWLockLRU(ULONG whence); +extern void NWUnlockLRU(ULONG whence); +extern void NWLockSync(void); +extern void NWUnlockSync(void); +extern ULONG NWLockBuffer(LRU *lru); +extern void NWUnlockBuffer(LRU *lru); +extern void FreeLRUElement(LRU *lru); +extern LRU *AllocateLRUElement(VOLUME *volume, ULONG block, ULONG *ccode); +extern LRU *RemoveDirty(LRU *lru); +extern void InsertDirty(LRU *lru); +extern LRU *RemoveLRU(LRU_HANDLE *lru_handle, LRU *lru); +extern void InsertLRU(LRU_HANDLE *lru_handle, LRU *lru); +extern void InsertLRUTop(LRU_HANDLE *lru_handle, LRU *lru); +extern LRU *GetFreeLRU(void); +extern void PutFreeLRU(LRU *lru); +extern LRU *SearchHash(VOLUME *volume, ULONG block); +extern ULONG AddToHash(LRU *lru); +extern ULONG RemoveHash(LRU *lru); +extern ULONG InitializeLRU(LRU_HANDLE *lru_handle, BYTE *name, ULONG mode, + ULONG max, ULONG min, ULONG age); +extern ULONG FreeLRU(void); +extern ULONG FlushLRU(void); +extern ULONG FlushEligibleLRU(void); +extern ULONG FlushVolumeLRU(VOLUME *volume); +extern ULONG ReleaseLRU(LRU_HANDLE *lru_handle, LRU *lru); +extern ULONG ReleaseDirtyLRU(LRU_HANDLE *lru_handle, LRU *lru); + +extern LRU *ReadLRU(LRU_HANDLE *lru_handle, VOLUME *volume, ULONG block, + ULONG fill, ULONG ccount, ULONG readAhead, ULONG *mirror); +extern ULONG SyncLRUBlocks(VOLUME *volume, ULONG block, ULONG blocks); +extern ULONG PerformBlockReadAhead(LRU_HANDLE *lru_handle, VOLUME *volume, ULONG block, + ULONG blockReadAhead, ULONG ccount, + ULONG *mirror); + +extern MIRROR_LRU *RemoveFAT_LRU(VOLUME *volume, MIRROR_LRU *lru); +extern void InsertFAT_LRU(VOLUME *volume, MIRROR_LRU *lru); +extern void InsertFAT_LRUTop(VOLUME *volume, MIRROR_LRU *lru); +extern ULONG InitializeFAT_LRU(VOLUME *volume); +extern ULONG FreeFAT_LRU(VOLUME *volume); +extern ULONG FlushFAT_LRU(VOLUME *volume); +extern MIRROR_LRU *SearchFAT_LRU(VOLUME *volume, ULONG Cluster); +extern ULONG AddToFATHash(VOLUME *volume, MIRROR_LRU *lru); +extern ULONG RemoveFATHash(VOLUME *volume, MIRROR_LRU *lru); +extern void FreePartitionResources(void); +extern void RemoveDiskDevices(void); +extern void ScanDiskDevices(void); + + +// VOLUME.C + +extern void displayNetwareVolumes(void); +extern void ReportVolumes(void); +extern ULONG MountAllVolumes(void); +extern ULONG DismountAllVolumes(void); +extern ULONG DismountVolumeByHandle(VOLUME *volume); +extern ULONG MountVolumeByHandle(VOLUME *volume); +extern VOLUME *MountHandledVolume(BYTE *name); +extern ULONG DismountVolume(BYTE *name); +extern ULONG MountVolume(BYTE *name); +extern ULONG MountUtilityVolume(VOLUME *volume); +extern ULONG DismountUtilityVolume(VOLUME *volume); +extern ULONG MountRawVolume(VOLUME *volume); +extern ULONG DismountRawVolume(VOLUME *volume); +extern VOLUME *GetVolumeHandle(BYTE *VolumeName); +extern ULONG CreateRootDirectory(BYTE *Buffer, ULONG size, ULONG VolumeFlags, + ULONG ClusterSize); + +// HASH.C + +extern ULONG InsertNameSpaceElement(VOLUME *volume, HASH *hash); +extern HASH *RemoveNameSpaceElement(VOLUME *volume, HASH *hash); +extern HASH *AllocHashNode(void); +extern void FreeHashNode(HASH *hash); +extern void FreeHashNodes(void); +extern HASH *CreateHashNode(DOS *dos, ULONG DirNo); +extern BYTE *CreateNameField(DOS *dos, HASH *hash); +extern ULONG RemoveNameHash(VOLUME *volume, HASH *hash); +extern ULONG AddToNameHash(VOLUME *volume, HASH *hash); +extern ULONG RemoveDirectoryHash(VOLUME *volume, HASH *hash); +extern ULONG AddToDirectoryHash(VOLUME *volume, HASH *hash); +extern ULONG RemoveParentHash(VOLUME *volume, HASH *hash); +extern ULONG AddToParentHash(VOLUME *volume, HASH *hash); +extern ULONG RemoveMountHash(VOLUME *volume, HASH *hash); +extern ULONG AddToMountHash(VOLUME *volume, HASH *hash); +extern ULONG AddToDelMountHash(VOLUME *volume, HASH *hash); +extern ULONG RemoveDelMountHash(VOLUME *volume, HASH *hash); +extern ULONG RemoveDeletedHash(VOLUME *volume, HASH *hash); +extern ULONG AddToDeletedHash(VOLUME *volume, HASH *hash); +extern ULONG ProcessOrphans(VOLUME *volume); + +extern ULONG AddTrusteeToDirectoryHash(VOLUME *volume, THASH *name); +extern ULONG AddUserQuotaToDirectoryHash(VOLUME *volume, UHASH *name); +extern ULONG RemoveTrusteeFromDirectoryHash(VOLUME *volume, THASH *name); +extern ULONG RemoveUserQuotaFromDirectoryHash(VOLUME *volume, UHASH *name); +extern ULONG AddToTrusteeHash(VOLUME *volume, THASH *name); +extern ULONG AddToUserQuotaHash(VOLUME *volume, UHASH *name); +extern ULONG RemoveTrusteeHash(VOLUME *volume, THASH *name); +extern ULONG RemoveUserQuotaHash(VOLUME *volume, UHASH *name); +extern ULONG AddToExtHash(VOLUME *volume, EXTENDED_DIR_HASH *name); +extern ULONG RemoveExtHash(VOLUME *volume, EXTENDED_DIR_HASH *name); + +extern ULONG LinkVolumeNameSpaces(VOLUME *volume); + +extern ULONG HashDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo); +extern HASH *AllocHashDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo); +extern HASH *GetHashFromName(VOLUME *v, BYTE *s, ULONG len, ULONG ns, ULONG cd); +extern HASH *GetHashFromDirectoryNumber(VOLUME *v, ULONG d); +extern HASH *GetHashNameSpaceEntry(VOLUME *v, ULONG entry, ULONG NameSpace, + ULONG dir, HASH **DirHash); +extern ULONG GetHashCountFromDirectory(VOLUME *volume, ULONG Directory, ULONG *count); +extern HASH *GetHashFromNameUppercase(VOLUME *volume, BYTE *PathString, ULONG len, + ULONG NameSpace, ULONG CurrentDirectory); +extern ULONG NWFSStringHash(BYTE *v, ULONG len, ULONG M); + +extern ULONG get_directory_number(VOLUME *volume, const char *name, ULONG len, ULONG DirNo); +extern HASH *get_directory_hash(VOLUME *volume, const char *name, ULONG len, ULONG Parent); +extern HASH *get_directory_record(VOLUME *volume, ULONG ino); +extern HASH *get_subdirectory_record(VOLUME *volume, ULONG entry, + ULONG ino, HASH **dir); +extern ULONG get_parent_directory_number(VOLUME *volume, ULONG ino); +extern ULONG get_namespace_directory_number(VOLUME *, HASH *root, + ULONG NameSpace); +extern ULONG get_namespace_dir_record(VOLUME *volume, DOS *dos, HASH *hash, + ULONG NameSpace); +extern ULONG is_deleted(VOLUME *volume, HASH *hash); +extern ULONG is_deleted_file(VOLUME *volume, HASH *hash); +extern ULONG is_deleted_dir(VOLUME *volume, HASH *hash); + +// CLUSTER.C + +extern ULONG InitializeClusterFreeList(VOLUME *volume); +extern ULONG ExtendClusterFreeList(VOLUME *volume, ULONG Amount); +extern ULONG FreeClusterFreeList(VOLUME *volume); +extern ULONG GetFreeClusterValue(VOLUME *volume, ULONG Cluster); +extern ULONG SetFreeClusterValue(VOLUME *volume, ULONG Cluster, ULONG flag); +extern ULONG FindFreeCluster(VOLUME *volume, ULONG Cluster); +extern ULONG InitializeClusterAssignedList(VOLUME *volume); +extern ULONG ExtendClusterAssignedList(VOLUME *volume, ULONG Amount); +extern ULONG FreeClusterAssignedList(VOLUME *volume); +extern ULONG GetAssignedClusterValue(VOLUME *volume, ULONG Cluster); +extern ULONG SetAssignedClusterValue(VOLUME *volume, ULONG Cluster, ULONG flag); +extern ULONG FindAssignedCluster(VOLUME *volume, ULONG Cluster); + +// BIT.C + +extern BIT_BLOCK *AllocateBitBlock(ULONG BlockSize); +extern void FreeBitBlock(BIT_BLOCK *blk); +extern BIT_BLOCK *RemoveBitBlock(BIT_BLOCK_HEAD *bb, BIT_BLOCK *blk); +extern BIT_BLOCK *InsertBitBlock(BIT_BLOCK_HEAD *bb, BIT_BLOCK *blk); +extern ULONG GetBitBlockValue(BIT_BLOCK_HEAD *bb, ULONG Index); +extern ULONG SetBitBlockValue(BIT_BLOCK_HEAD *bb, ULONG Index, ULONG Value); +extern ULONG SetBitBlockValueWithRange(BIT_BLOCK_HEAD *bb, ULONG Index, + ULONG Value, ULONG Range); +extern ULONG CreateBitBlockList(BIT_BLOCK_HEAD *bb, ULONG Limit, + ULONG BlockSize, BYTE *Name); +extern ULONG FreeBitBlockList(BIT_BLOCK_HEAD *bb); +extern ULONG AdjustBitBlockList(BIT_BLOCK_HEAD *bb, ULONG NewLimit); +extern ULONG ScanBitBlockValueWithIndex(BIT_BLOCK_HEAD *bb, ULONG Value, + ULONG Index, ULONG Range); +extern ULONG ScanAndSetBitBlockValueWithIndex(BIT_BLOCK_HEAD *bb, ULONG Value, + ULONG Index, ULONG Range); +extern ULONG GetBitBlockLimit(BIT_BLOCK_HEAD *bb); +extern ULONG GetBitBlockBlockSize(BIT_BLOCK_HEAD *bb); +extern ULONG InitBitBlockList(BIT_BLOCK_HEAD *bb, ULONG value); + +// NWDIR.C + +extern ULONG AllocateDirectoryRecord(VOLUME *volume, ULONG Parent); +extern ULONG ReadDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo); +extern ULONG WriteDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo); +extern ULONG FreeDirectoryRecord(VOLUME *volume, DOS *dos, ULONG DirNo, ULONG Parent); +extern ULONG ReleaseDirectoryRecord(VOLUME *volume, ULONG DirNo, ULONG Parent); +extern ULONG PreAllocateFreeDirectoryRecords(VOLUME *volume); +extern ULONG PreAllocateEmptyDirectorySpace(VOLUME *volume); + +// NWEXT.C + +extern ULONG AllocateExtDirectoryRecords(VOLUME *volume, ULONG count); +extern ULONG ReadExtDirectoryRecords(VOLUME *volume, EXTENDED_DIR *, + BYTE *data, ULONG DirNo, ULONG count); +extern ULONG WriteExtDirectoryRecords(VOLUME *volume, EXTENDED_DIR *, + BYTE *data, ULONG DirNo, ULONG count); +extern ULONG FreeExtDirectoryRecords(VOLUME *volume, ULONG DirNo, ULONG count); +extern ULONG ReleaseExtDirectoryRecords(VOLUME *volume, ULONG DirNo, ULONG count); + +// SUBALLOC.C + +extern ULONG AllocateSuballocRecord(VOLUME *volume, ULONG Size, ULONG *retCode); +extern ULONG SetSuballocListValue(VOLUME *volume, ULONG cluster, ULONG Value); +extern ULONG GetSuballocListValue(VOLUME *volume, ULONG SAEntry); +extern ULONG FreeSuballocRecord(VOLUME *volume, ULONG SAEntry); +extern ULONG GetSuballocSize(VOLUME *volume, ULONG SAEntry); +extern ULONG MapSuballocNode(VOLUME *volume, SUBALLOC_MAP *map, long Cluster); +extern ULONG ReadSuballocRecord(VOLUME *volume, long offset, + ULONG cluster, BYTE *buf, long count, + ULONG as, ULONG *retCode); +extern ULONG WriteSuballocRecord(VOLUME *volume, long offset, + ULONG cluster, BYTE *buf, long count, + ULONG as, ULONG *retCode); +extern ULONG NWCreateSuballocRecords(VOLUME *volume); + +extern ULONG InitializeDirBlockHash(VOLUME *volume); +extern ULONG CreateDirBlockEntry(VOLUME *volume, ULONG cluster, ULONG mirror, ULONG index); +extern ULONG FreeDirBlockHash(VOLUME *volume); +extern ULONG AddToDirBlockHash(VOLUME *volume, DIR_BLOCK_HASH *dblock); +extern ULONG RemoveDirBlockHash(VOLUME *volume, DIR_BLOCK_HASH *dblock); + +extern ULONG InitializeDirAssignHash(VOLUME *volume); +extern ULONG CreateDirAssignEntry(VOLUME *volume, ULONG Parent, ULONG BlockNo, DOS *dos); +extern ULONG FreeDirAssignHash(VOLUME *volume); +extern ULONG AddToDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock); +extern ULONG RemoveDirAssignHash(VOLUME *volume, DIR_ASSIGN_HASH *dblock); + +extern FAT_ENTRY *GetFatEntry(VOLUME *volume, ULONG Cluster, FAT_ENTRY *fat); +extern FAT_ENTRY *GetFatEntryAndLRU(VOLUME *volume, ULONG Cluster, + MIRROR_LRU **lru, FAT_ENTRY *fat); +extern ULONG FlushFATBuffer(VOLUME *volume, MIRROR_LRU *lru, ULONG cluster); +extern ULONG WriteFATEntry(VOLUME *volume, MIRROR_LRU *lru, FAT_ENTRY *fat, + ULONG cluster); +extern ULONG NWUpdateFat(VOLUME *volume, FAT_ENTRY *FAT, MIRROR_LRU *lru, + ULONG index, ULONG value, ULONG cluster); + +// NWCREATE.C + +extern ULONG NWCreateDirectoryEntry(VOLUME *volume, BYTE *Name, ULONG Len, + ULONG Attributes, ULONG Parent, + ULONG Flag, ULONG Uid, ULONG Gid, + ULONG RDev, ULONG Mode, ULONG *retDirNo, + ULONG DataStream, ULONG DataStreamSize, + ULONG DataFork, ULONG DataForkSize, + const char *SymbolicLinkPath, ULONG SymbolPathLength); +extern ULONG NWDeleteDirectoryEntry(VOLUME *volume, DOS *dos, HASH *hash); +extern ULONG NWDeleteDirectoryEntryAndData(VOLUME *volume, DOS *dos, HASH *hash); +extern ULONG NWShadowDirectoryEntry(VOLUME *volume, DOS *dos, HASH *hash); +extern ULONG NWRenameEntry(VOLUME *volume, DOS *dos, HASH *hash, BYTE *Name, + ULONG Len, ULONG Parent); +extern ULONG NWValidDOSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag); +extern ULONG NWValidMACName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag); +extern ULONG NWValidNFSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag); +extern ULONG NWValidLONGName(VOLUME *volume, BYTE *Name, ULONG NameLength, + ULONG Parent, ULONG searchFlag); +extern ULONG NWSearchDOSName(VOLUME *volume, BYTE *Name, ULONG NameLength, + BYTE *retName, ULONG *retNameLength, ULONG Parent); +extern ULONG NWMangleDOSName(VOLUME *volume, BYTE *Name, ULONG NameLength, DOS *dos, ULONG Parent); +extern ULONG NWMangleMACName(VOLUME *volume, BYTE *Name, ULONG NameLength, MACINTOSH *mac, ULONG Parent); +extern ULONG NWMangleNFSName(VOLUME *volume, BYTE *Name, ULONG NameLength, NFS *nfs, ULONG Parent); +extern ULONG NWMangleLONGName(VOLUME *volume, BYTE *Name, ULONG NameLength, LONGNAME *longname, ULONG Parent); +extern ULONG NWCreateUniqueName(VOLUME *volume, ULONG Parent, BYTE *name, ULONG len, + BYTE *MangledName, BYTE *MangledNameLength, + ULONG OpFlag); +extern ULONG FreeHashRecords(VOLUME *volume, HASH **Entries, ULONG Count); +extern ULONG FreeDirectoryRecords(VOLUME *volume, ULONG *Entries, ULONG Parent, ULONG Count); +extern ULONG CreateDirectoryRecords(VOLUME *volume, ULONG *Entries, ULONG Parent, ULONG *NumRec); +extern ULONG InitializeVolumeDirectory(VOLUME *volume); + +extern ULONG NWReaderWriterLock(HASH *hash, ULONG which); +extern ULONG NWReaderWriterUnlock(HASH *hash, ULONG which); +extern ULONG NWLockFile(HASH *hash); +extern ULONG NWLockFileExclusive(HASH *hash); +extern void NWUnlockFile(HASH *hash); + +extern ULONG NWReadFile(VOLUME *volume, ULONG *Chain, ULONG Flags, ULONG FileSize, + ULONG offset, BYTE *buf, long count, long *Context, + ULONG *Index, ULONG *retCode, ULONG as, ULONG SAFlag, + ULONG Attributes, ULONG readAhead); + +extern ULONG NWWriteFile(VOLUME *volume, ULONG *Chain, ULONG Flags, + ULONG offset, BYTE *buf, long count, long *Context, + ULONG *Index, ULONG *retCode, ULONG as, ULONG SAFlag, + ULONG Attributes); + +extern ULONG RemoveNameSpaceLink(VOLUME *volume, HASH *name); +extern ULONG AllocateCluster(VOLUME *volume); +extern ULONG AllocateClusterSetIndex(VOLUME *volume, ULONG Index); +extern ULONG AllocateClusterSetIndexSetChain(VOLUME *volume, ULONG Index, ULONG Next); +extern ULONG FreeCluster(VOLUME *volume, long cluster); +extern ULONG FreeClusterNoFlush(VOLUME *volume, long cluster); +extern ULONG TruncateClusterChain(VOLUME *volume, ULONG *Chain, ULONG Index, + ULONG PrevChain, ULONG size, ULONG SAFlag, + ULONG Attributes); +extern ULONG SetClusterValue(VOLUME *volume, long cluster, ULONG Value); +extern ULONG SetClusterIndex(VOLUME *volume, long cluster, ULONG Index); +extern ULONG SetClusterValueAndIndex(VOLUME *volume, long cluster, ULONG Value, ULONG Index); +extern ULONG GetChainSize(VOLUME *volume, long ClusterChain); +extern ULONG AdjustAllocatedClusters(VOLUME *volume); +extern ULONG BuildChainAssignment(VOLUME *volume, ULONG Chain, ULONG SAFlag); +extern ULONG VerifyChainAssignment(VOLUME *volume, ULONG Chain, ULONG SAFlag); + +extern ULONG ReadDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG blocks, ULONG readAhead); +extern ULONG WriteDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG blocks, ULONG readAhead); +extern ULONG ZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, + ULONG blocks, ULONG readAhead); + +extern ULONG pReadDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG blocks, ULONG readAhead); +extern ULONG pWriteDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG blocks, ULONG readAhead); +extern ULONG pZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, + ULONG blocks, ULONG readAhead); + +extern ULONG aReadDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG blocks, ULONG readAhead, ASYNCH_IO *io); +extern ULONG aWriteDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector, + ULONG blocks, ULONG readAhead, ASYNCH_IO *io); +extern ULONG aZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, + ULONG blocks, ULONG readAhead, ASYNCH_IO *io); + +extern void SyncDevice(ULONG disk); +extern void SyncDisks(void); + +// +// OS Platform specific functions +// + +extern void NWFSSet(void *dest, ULONG value, ULONG size); +extern void NWFSCopy(void *dest, void *src, ULONG size); +extern void *NWFSScan(void *src, ULONG value, ULONG size); +extern int NWFSCompare(void *dest, void *src, ULONG size); +extern ULONG NWFSCopyToUserSpace(void *dest, void *src, ULONG size); +extern ULONG NWFSCopyFromUserSpace(void *dest, void *src, ULONG size); +extern ULONG NWFSSetUserSpace(void *src, ULONG value, ULONG size); +extern void *NWFSAlloc(ULONG size, TRACKING *Tag); +extern void *NWFSIOAlloc(ULONG size, TRACKING *Tag); +extern void *NWFSCacheAlloc(ULONG size, TRACKING *Tag); +extern void NWFSFree(void *p); +extern BYTE NWFSUpperCase(BYTE c); +extern BYTE NWFSLowerCase(BYTE c); +extern void FreePoolList(void); + +// +// page pool alloc routines for using virutal memory on Linux +// + +extern void *NWFSVMAlloc(ULONG size); +extern void NWFSVMFree(void *p); + +extern void NWLockDirectory(HASH *hash); +extern void NWUnlockDirectory(HASH *hash); +extern void NWLockFat(VOLUME *volume); +extern void NWUnlockFat(VOLUME *volume); + +extern ULONG NWFSGetSeconds(void); +extern ULONG NWFSGetSystemTime(void); +extern ULONG NWFSSystemToNetwareTime(ULONG SystemTime); +extern ULONG NWFSNetwareToSystemTime(ULONG NetwareTime); +extern ULONG MakeNWTime(ULONG second, ULONG minute, ULONG hour, ULONG day, ULONG month, ULONG year); +extern void GetNWTime(ULONG DateAndTime, ULONG *second, ULONG *minute, ULONG *hour, + ULONG *day, ULONG *month, ULONG *year); +extern ULONG MakeUnixTime(ULONG second, ULONG minute, ULONG hour, ULONG day, ULONG month, ULONG year); +extern void GetUnixTime(ULONG unixdate, ULONG *second, ULONG *minute, ULONG *hour, + ULONG *day, ULONG *month, ULONG *year); +extern ULONG NWFSGetSeconds(void); +extern ULONG NWFSGetSystemTime(void); +extern ULONG NWFSSystemToNetwareTime(ULONG SystemTime); +extern ULONG NWFSNetwareToSystemTime(ULONG NetwareTime); + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwstruct.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwstruct.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwstruct.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwstruct.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,637 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWSTRUCT.H +* DESCRIP : NWFS File System Structures +* DATE : January 20, 1999 +* +* +***************************************************************************/ + +#ifndef _NWFS_NWSTRUCT_ +#define _NWFS_NWSTRUCT_ + +// directory object attributes + +#define NW_SUBDIRECTORY_FILE 0x01 +#define NW_SYMBOLIC_FILE 0x02 +#define NW_HARD_LINKED_FILE 0x04 +#define NW_NAMED_FILE 0x08 +#define NW_DEVICE_FILE 0x10 + +typedef struct _NWDISK +{ + void *PhysicalDiskHandle; + + LONGLONG Cylinders; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + + struct PartitionTableEntry PartitionTable[4]; + void *PartitionContext[4]; + ULONG PartitionFlags[4]; + ULONG PartitionVersion[4]; // 1-Netware 3.x, 2-Netware 4.x/5.x + + LONGLONG driveSize; + ULONG DiskNumber; + ULONG ChangeStatus; + ULONG NumberOfPartitions; + +#if (LINUX_20 || LINUX_22 || LINUX_24) + struct inode inode; + struct file filp; + ULONG DeviceBlockSize; +#endif + WORD partitionSignature; + +} NWDISK; + +typedef struct _BIT_BLOCK +{ + struct _BIT_BLOCK *next; + struct _BIT_BLOCK *prior; + BYTE *BlockBuffer; + ULONG BlockIndex; +} BIT_BLOCK; + +typedef struct _BIT_BLOCK_HEAD +{ + BIT_BLOCK *Head; + BIT_BLOCK *Tail; + BYTE Name[16]; +#if (PROFILE_BIT_SEARCH) + ULONG bit_search_count; + ULONG skip_search_count; +#endif + ULONG BlockSize; + ULONG Count; + ULONG Limit; +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spinlock_t BB_spinlock; + ULONG BB_flags; +#else + struct semaphore BBSemaphore; +#endif +#endif + +} BIT_BLOCK_HEAD; + +// LRU Block states + +#define L_AVAIL 0x0000001 +#define L_FREE 0x0000002 +#define L_DATAVALID 0x0000004 +#define L_DIRTY 0x0000008 +#define L_FLUSHING 0x0000010 +#define L_LOADING 0x0000020 +#define L_UPTODATE 0x0000040 +#define L_MAPPED 0x0000080 +#define L_MODIFIED 0x0000100 + +// LRU List States + +#define QUEUE_LRU 0x0000001 +#define QUEUE_FREE 0x0000002 +#define QUEUE_DIRTY 0x0000004 +#define QUEUE_HASH 0x0000008 +#define QUEUE_ALL (QUEUE_LRU | QUEUE_FREE | QUEUE_DIRTY) + +#define ASYNCH_READ 0x1111 +#define ASYNCH_WRITE 0x2222 +#define ASYNCH_FILL 0x4444 +#define ASYNCH_TEST 0x8888 + +#define NWFS_FLUSH_ALL 1 + +#define ASIO_BAD_COMMAND -10 +#define ASIO_IO_ERROR -11 +#define ASIO_BAD_PARM -12 +#define ASIO_BAD_SIGNATURE -13 +#define ASIO_SUBMIT_IO 0xBEEFBEEF +#define ASIO_AIO_POST 0xCAFECAFE +#define ASIO_CALLBACK_POST 0xCAFEBEEF +#define ASIO_COMPLETED 0xDEEDBEEF +#define ASIO_SUBMIT_CB 0xFEEDBEEF + +#define ASIO_INTR_CALLBACK 0x01 +#define ASIO_SLEEP_CALLBACK 0x02 + +typedef struct _ASYNCH_IO +{ + struct _ASYNCH_IO *next; + struct _ASYNCH_IO *prior; + struct _ASYNCH_IO *hnext; + struct _ASYNCH_IO *hprior; + ULONG (*call_back_routine)(struct _ASYNCH_IO *); + ULONG call_back_parameter; + ULONG flags; + ULONG command; + ULONG disk; + ULONG sector_offset; + ULONG sector_count; + BYTE *buffer; + ULONG return_code; + ULONG ccode; + ULONG signature; + ULONG count; + ULONG complete; +#if (LINUX_22 | LINUX_24) + struct buffer_head *bh[8]; +#endif +} ASYNCH_IO; + +typedef struct _ASYNCH_IO_HEAD +{ + ASYNCH_IO *hash_head[16]; + ASYNCH_IO *hash_tail[16]; +} ASYNCH_IO_HEAD; + +typedef struct _ASYNCH_HASH_LIST +{ + ASYNCH_IO *head; + ASYNCH_IO *tail; +} ASYNCH_HASH_LIST; + + +typedef struct _MIRROR_LRU +{ + struct _MIRROR_LRU *next; + struct _MIRROR_LRU *prior; + struct _MIRROR_LRU *hashNext; + struct _MIRROR_LRU *hashPrior; + ULONG BlockIndex; + ULONG BlockState; + ULONG Cluster1; + ULONG Cluster2; + void *CacheBuffer; + ULONG ClusterSize; + ULONG ModLock; + +} MIRROR_LRU; + +typedef struct _LRU_HASH_LIST +{ + MIRROR_LRU *head; + MIRROR_LRU *tail; +} LRU_HASH_LIST; + +#define WRITE_THROUGH_LRU 1 +#define WRITE_BACK_LRU 2 + +typedef struct _LRU +{ + struct _LRU *listnext; + struct _LRU *listprior; + struct _LRU *next; + struct _LRU *prior; + struct _LRU *dnext; + struct _LRU *dprior; + struct _LRU *hashNext; + struct _LRU *hashPrior; + ULONG state; + ULONG owner; + ULONG block; + ULONG volnum; + ULONG nwvp_handle; + BYTE *buffer; + ULONG timestamp; + ULONG bad_bits; + ULONG io_signature; + +#if (LINUX_SLEEP) + struct semaphore Semaphore; +#endif + + ASYNCH_IO io[8]; + ULONG lba[8]; + ULONG disk[8]; + ULONG mirror_count; + ULONG mirrors_completed; + ULONG aio_ccode; + ULONG lock_count; + ULONG Waiters; + void *lru_handle; + ULONG AGING_INTERVAL; + +#if (LINUX_24) + struct page *page; +#endif + +} LRU; + +typedef struct _DATA_LRU_HASH_LIST +{ + LRU *head; + LRU *tail; +} DATA_LRU_HASH_LIST; + +typedef struct _VOLUME_WORKSPACE +{ + struct _VOLUME_WORKSPACE *next; + struct _VOLUME_WORKSPACE *prior; + BYTE Buffer[1]; +} VOLUME_WORKSPACE; + +typedef struct _VOLUME +{ + // base volume information + + ULONG VolumeNumber; + ULONG VolumeNameLength; + BYTE VolumeName[16]; + ULONG VolumeDisk; + ULONG VolumeClusters; + ULONG MountedVolumeClusters; + ULONG VolumeSectors; + ULONG VolumeFlags; // from ROOT directory entry + ULONG VolumeSuballocRoot; // from ROOT directory entry + ULONG ClusterSize; + ULONG BlockSize; + ULONG BlocksPerCluster; + ULONG SectorsPerCluster; + ULONG SectorsPerBlock; + ULONG VolumeStartLBA; + ULONG FirstFAT; + ULONG SecondFAT; + ULONG FirstDirectory; + ULONG SecondDirectory; + ULONG ExtDirectory1; + ULONG ExtDirectory2; + ULONG NumberOfFATEntries; + ULONG VolumeSerialNumber; + ULONG EndingDirCluster1; + ULONG EndingDirCluster2; + ULONG EndingDirIndex; + ULONG EndingBlockNo; + ULONG LastValidBlockNo; + ULONG MirrorFlag; + ULONG nwvp_handle; + ULONG ScanFlag; + ULONG DeletedDirNo; + ULONG InUseCount; + ULONG AutoRepair; + + ULONG volume_segments_ok_flag; + ULONG fat_mirror_ok_flag; + ULONG fat_table_ok_flag; + ULONG directory_table_ok_flag; + + ULONG DirectoryCount; + ULONG FreeDirectoryCount; + ULONG FreeDirectoryBlockCount; + + VOLUME_WORKSPACE *WKHead; + VOLUME_WORKSPACE *WKTail; + ULONG WKCount; + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spinlock_t WK_spinlock; + ULONG WK_flags; +#else + struct semaphore WKSemaphore; +#endif +#endif + + VOLUME_WORKSPACE *NSHead; + VOLUME_WORKSPACE *NSTail; + ULONG NSCount; + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spinlock_t NS_spinlock; + ULONG NS_flags; +#else + struct semaphore NSSemaphore; +#endif +#endif + + // these fields temporarily hold hash elements during mount + HASH *HashMountHead; + HASH *HashMountTail; + + // these fields temporarily hold deleted hash elements during mount + HASH *DelHashMountHead; + HASH *DelHashMountTail; + + // file allocation table LRU tables + + MIRROR_LRU *FATBlockHash; + ULONG FATBlockHashLimit; + MIRROR_LRU *FATListHead; + MIRROR_LRU *FATListTail; + ULONG FATListBlocks; + ULONG MinimumFATBlocks; + ULONG MaximumFATBlocks; + + // logical directory block hash + + DIR_BLOCK_HASH *DirBlockHash; + ULONG DirBlockHashLimit; + ULONG DirListBlocks; + + // directory record assignment hash + + DIR_ASSIGN_HASH *DirAssignHash; + ULONG DirAssignHashLimit; + ULONG DirAssignBlocks; + + // segment table + + ULONG SegmentClusterStart[MAX_SEGMENTS]; + ULONG SegmentClusterSize[MAX_SEGMENTS]; + ULONG LastAllocatedIndex[MAX_SEGMENTS]; + ULONG AllocSegment; + ULONG MountedNumberOfSegments; + ULONG NumberOfSegments; + ULONG CurrentSegments; + ULONG VolumePresent; + + // bit block free tables + + BIT_BLOCK_HEAD FreeBlockList; + BIT_BLOCK_HEAD *ExtDirList; + ULONG ExtDirTotalBlocks; + ULONG ExtDirSearchIndex; + BIT_BLOCK_HEAD AssignedBlockList; + + // volume name space information + + ULONG NameSpaceCount; + ULONG NameSpaceID[MAX_NAMESPACES]; + ULONG NameSpaceDefault; + + // name hash tables + + void *VolumeNameHash[MAX_NAMESPACES]; + ULONG VolumeNameHashLimit[MAX_NAMESPACES]; + + // directory hash tables + + void *DirectoryNumberHash; + ULONG DirectoryNumberHashLimit; + + // parent hash tables + + void *ParentHash; + ULONG ParentHashLimit; + + // extended directory hash tables + + void *ExtDirHash; + ULONG ExtDirHashLimit; + + // trustee hash tables + + void *TrusteeHash; + ULONG TrusteeHashLimit; + + // user restriction tables + + void *UserQuotaHash; + ULONG UserQuotaHashLimit; + + // volume suballocation tables + + ULONG SuballocListCount; + ULONG SuballocCount; + ULONG SuballocCurrentCount; + ULONG SuballocChainComplete; + ULONG SuballocChainFlag[MAX_SUBALLOC_NODES]; + ULONG SuballocDirNo[MAX_SUBALLOC_NODES]; + SUBALLOC_DIR *SuballocChain[MAX_SUBALLOC_NODES]; + BIT_BLOCK_HEAD *FreeSuballoc[128]; + ULONG SuballocTotalBlocks[128]; + ULONG SuballocAssignedBlocks[128]; + ULONG SuballocTurboFATCluster[128]; + ULONG SuballocTurboFATIndex[128]; + ULONG SuballocSearchIndex[128]; + +#if (LINUX_SLEEP) + struct semaphore SuballocSemaphore[128]; +#endif + + // volume stats + + ULONG VolumeAllocatedClusters; + ULONG VolumeFreeClusters; + + // salvageable file system + + ULONG MountTime; + ULONG FileSeed; + ULONG dblock_sequence; + DIR_BLOCK_HASH *dblock_head; + DIR_BLOCK_HASH *dblock_tail; + + // synch primitives + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spinlock_t NameHash_spinlock; + spinlock_t DirHash_spinlock; + spinlock_t ParentHash_spinlock; + spinlock_t TrusteeHash_spinlock; + spinlock_t QuotaHash_spinlock; + spinlock_t ExtHash_spinlock; + spinlock_t NameSpace_spinlock; + + ULONG NameHash_flags; + ULONG DirHash_flags; + ULONG ParentHash_flags; + ULONG TrusteeHash_flags; + ULONG QuotaHash_flags; + ULONG ExtHash_flags; + ULONG NameSpace_flags; +#else + struct semaphore NameHashSemaphore; + struct semaphore DirHashSemaphore; + struct semaphore ParentHashSemaphore; + struct semaphore TrusteeHashSemaphore; + struct semaphore QuotaHashSemaphore; + struct semaphore ExtHashSemaphore; + struct semaphore NameSpaceSemaphore; +#endif + + struct semaphore FatSemaphore; + struct semaphore VolumeSemaphore; + struct semaphore ExtSemaphore; + struct semaphore DirBlockSemaphore; + struct semaphore DirAssignSemaphore; +#endif + + ULONG gid; + ULONG uid; + ULONG mode; + +} VOLUME; + +typedef struct _CACHE_AIO +{ + struct _CACHE_AIO *next; + struct _CACHE_AIO *prior; + struct _CACHE_AIO *dnext; + struct _CACHE_AIO *dprior; + struct _CACHE_AIO *head; + ULONG state; + ULONG block; + ULONG fblock; + ULONG vblock; + ULONG blocks; + ULONG cache_lock; + ULONG owner; + BYTE *buffer; + VOLUME *volume; + HASH *hash; + ULONG bad_bits; + ULONG io_signature; + + ASYNCH_IO io[8]; + ULONG lba[8]; + ULONG disk[8]; + ULONG mirror_count; + ULONG mirrors_completed; + ULONG aio_ccode; +#if (LINUX_22 | LINUX_24) + struct page *page; + +#if (LINUX_SLEEP) + struct semaphore cache_aio_semaphore; +#endif + +#endif + struct _CACHE_AIO *table[1]; + +} CACHE_AIO; + +typedef struct _DISK_INFO +{ + ULONG disk_number; + ULONG partition_count; + ULONG total_sectors; + ULONG cylinder_size; + + ULONG track_size; + ULONG bytes_per_sector; + ULONG filler1; + ULONG filler2; +} DISK_INFO; + +typedef struct _PARTITION_INFO +{ + ULONG disk_number; + ULONG partition_number; + ULONG total_sectors; + ULONG cylinder_size; + ULONG partition_type; + ULONG boot_flag; + ULONG sector_offset; + ULONG sector_count; +} PARTITION_INFO; + +typedef struct _LRU_HANDLE +{ + ULONG LRUMode; + BYTE *LRUName; + LRU *LRUListHead; + LRU *LRUListTail; + ULONG MinimumLRUBlocks; + ULONG MaximumLRUBlocks; + ULONG LocalLRUBlocks; + ULONG AGING_INTERVAL; + + ULONG dirty; + ULONG loading; + ULONG flushing; + ULONG locked; + ULONG valid; + ULONG uptodate; + ULONG total; + ULONG free; + +} LRU_HANDLE; + +typedef struct segment_table_def +{ + ULONG lpart_handle; + ULONG segment_offset; + ULONG segment_count; + ULONG free_flag; + ULONG segment_number; + ULONG total_segments; + BYTE VolumeName[20]; + ULONG disk; +} segment_info_table; + +typedef struct hotfix_table_def +{ + ULONG lpart_handle; + ULONG rpart_handle; + ULONG segment_count; + ULONG mirror_count; + + ULONG insynch_flag; + ULONG hotfix_block_count; + ULONG logical_block_count; + ULONG physical_block_count; + + ULONG active_flag; + ULONG group_number; +} hotfix_info_table; + +#define TYPE_SIGNATURE 0x000000165 + +typedef struct _NETWARE_PART_SIG +{ + BYTE NetwareSignature[16]; + ULONG PartitionType; + ULONG PartitionSize; + ULONG CreationDateAndTime; +} PART_SIG; + + +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvfs.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvfs.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvfs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvfs.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,536 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWVFS.C +* DESCRIP : NWFS VFS Module for Linux +* DATE : November 16, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +extern void DisplayLRUInfo(LRU_HANDLE *lru_handle); + +#if (DEBUG_LRU_AIO) +ULONG delay_counter = 0; + +ULONG get_aio_count(ASYNCH_IO *io) +{ + register ULONG i = 0; + + while (io) + { + i++; + io = io->next; + } + return i; +} + +void displayNWFSState(void) +{ + extern BYTE *dumpRecord(BYTE *, ULONG); + extern void displayMemoryInfo(void); + + NWFSPrint("\n"); + displayMemoryInfo(); +} + +#endif + +#if (PROFILE_AIO) +extern ULONG seconds; +#endif + +struct task_struct *lru_task; +extern ULONG lru_active; +extern ULONG lru_state; +extern ULONG lru_signal; +NWFSInitSemaphore(lru_sem); + +ULONG callback_active = 0; +ULONG exit_callback = 0; +struct task_struct *callback_task = 0; +extern struct semaphore callback_semaphore; +extern void process_callback(void); + +int nwfs_callback(void *notused) +{ + sprintf(current->comm, "nwfs-callback"); + daemonize(); + callback_task = current; + + callback_active++; + while (!exit_callback) + { + down(&callback_semaphore); + + if (exit_callback) + break; + + process_callback(); + } + callback_active--; + return 0; +} + +ULONG remirror_active; +ULONG flush_active; +ULONG asynch_io_active[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +ULONG exit_remirror; +ULONG exit_flush; +ULONG exit_asynch_io[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +ULONG asynch_signal[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +ULONG asynch_active[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +ULONG asynch_threads = 0; + +NWFSInitSemaphore(mirror_sem); +NWFSInitSemaphore(asynch_io_sem0); +NWFSInitSemaphore(asynch_io_sem1); +NWFSInitSemaphore(asynch_io_sem2); +NWFSInitSemaphore(asynch_io_sem3); +NWFSInitSemaphore(asynch_io_sem4); +NWFSInitSemaphore(asynch_io_sem5); +NWFSInitSemaphore(asynch_io_sem6); +NWFSInitSemaphore(asynch_io_sem7); + +struct semaphore *sem_table[8]={ + &asynch_io_sem0, &asynch_io_sem1, &asynch_io_sem2, &asynch_io_sem3, + &asynch_io_sem4, &asynch_io_sem5, &asynch_io_sem6, &asynch_io_sem7 +}; + +struct task_struct *remirror_task = 0; +struct task_struct *asynch_io_task[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +struct timer_list flush_timer = { { NULL, NULL }, 0, }; + +extern ULONG nwvp_remirror_poll(void); +extern void nwvp_quiese_remirroring(void); +extern void process_asynch_io(ULONG disk); +extern void process_sync_io(ULONG disk); +extern ULONG asynch_io_pending(ULONG disk); + +int count = 0; + +void NWFSStartRemirror(void) +{ + if (remirror_task != current) + SignalSemaphore(&mirror_sem); +} + +void NWFSFlush(void) +{ + if (lru_task != current) + SignalSemaphore(&lru_sem); +} + +void RunAsynchIOQueue(ULONG disk) +{ + register int i = (disk % 8); + + if (!asynch_threads) + { + asynch_active[i] = TRUE; + process_sync_io(i); + asynch_active[i] = 0; + asynch_signal[i] = 0; + } + +#if (DO_ASYNCH_IO) + if (asynch_io_task[i] != current) + { + if (!asynch_signal[i]) + { + if (!asynch_active[i]) + { + asynch_signal[i] = TRUE; + SignalSemaphore(sem_table[i]); + } + } + } +#endif +} + +int nwfs_mirror(void *notused) +{ + register ULONG ccode; +#if (DO_ASYNCH_IO) + register int i; +#endif + + sprintf(current->comm, "nwfs-remirror"); + daemonize(); + remirror_task = current; + + remirror_active++; + while (!exit_remirror) + { + ccode = down_interruptible(&mirror_sem); + if (ccode == -EINTR) + { + NWFSPrint("Shutting Down REMIRRORING Process ... "); + exit_remirror = TRUE; + + nwvp_quiese_remirroring(); + while (nwvp_remirror_poll() == 0); + + NWFSPrint("done\n"); + + NWFSPrint("Shutting Down LRU Timer ... "); + del_timer(&flush_timer); + NWFSPrint("done\n"); + + NWFSPrint("Shutting Down LRU Process ... "); + exit_flush = TRUE; + while (flush_active) + { + NWFSFlush(); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("done\n"); + +#if (DO_ASYNCH_IO) + NWFSPrint("Shutting Down ASYNCH_CALLBACK Process ... "); + exit_callback = TRUE; + while (callback_active) + { + SignalSemaphore(&callback_semaphore); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("done\n"); + + + NWFSPrint("Shutting Down ASYNCH_IO Processes [ "); + for (i=0; i < 8; i++) + { + exit_asynch_io[i] = TRUE; + while (asynch_io_active[i]) + { + RunAsynchIOQueue(i); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("%d ", (int)i); + } + NWFSPrint("]\n"); +#endif + break; + } + + if (exit_remirror) + { + nwvp_quiese_remirroring(); + while (nwvp_remirror_poll() == 0); + break; + } + + while (nwvp_remirror_poll() == 0) + { + if (exit_remirror) + { + nwvp_quiese_remirroring(); + while (nwvp_remirror_poll() == 0); + break; + } + } + } + remirror_active--; + return 0; + +} + +int nwfs_flush(void *notused) +{ + sprintf(current->comm, "nwfs-flush"); + daemonize(); + lru_task = current; + + flush_active++; + while (!exit_flush) + { + down(&lru_sem); + + if (exit_flush) + break; + + if (lru_signal) + { + if (!lru_active) + FlushEligibleLRU(); + lru_signal = 0; + } + } + flush_active--; + return 0; + +} + +int nwfs_asynch_io_process(void *id) +{ + register int i = (int)id; + + sprintf(current->comm, "nwfs-async%d", (int)i); + daemonize(); + asynch_io_task[i] = current; + + asynch_io_active[i]++; + asynch_threads++; + while (!exit_asynch_io[i]) + { + if (!asynch_io_pending(i)) + down(sem_table[i]); + + if (exit_asynch_io[i]) + break; + +#if (DO_ASYNCH_IO) + if (asynch_signal[i]) + { + if (!asynch_active[i]) + { + asynch_active[i] = TRUE; + process_asynch_io(i); + asynch_active[i] = 0; + } + asynch_signal[i] = 0; + } +#endif + } + asynch_threads--; + asynch_io_active[i]--; + return 0; + +} + +void LRUTimer(void) +{ + flush_timer.data = 0; + flush_timer.expires = jiffies + HZ; // second delay + flush_timer.function = (void (*)(ULONG))LRUTimer; + add_timer(&flush_timer); + +#if (PROFILE_AIO) + seconds++; +#endif + + if (lru_task != current) + { + if (!lru_signal) + { + if (!lru_active) + { + lru_signal = TRUE; + NWFSFlush(); + } + } + } + +#if (DEBUG_LRU_AIO) + if (delay_counter++ > 60) + { + delay_counter = 0; + displayNWFSState(); + } +#endif + + return; +} + +struct super_operations nwfs_sops = +{ + read_inode: nwfs_read_inode, // read inode + write_inode: nwfs_write_inode, // write inode + put_inode: nwfs_put_inode, // put inode + delete_inode: nwfs_delete_inode, // delete inode + put_super: nwfs_put_super, // put superblock + statfs: nwfs_statfs, // stat filesystem + remount_fs: nwfs_remount, // remount filesystem +}; + +static DECLARE_FSTYPE(nwfs_fs_type, "nwfs", nwfs_read_super, 0); + +static int __init init_nwfs_fs(void) +{ + register int status; +#if (DO_ASYNCH_IO) + register int i; +#endif + + NWFSPrint("NetWare File System NWFS v%d.%02d.%02d Copyright(c) %d Jeff V. Merkey\n", + (int)MAJOR_VERSION, (int)MINOR_VERSION, (int)BUILD_VERSION, + (int)BUILD_YEAR); + + if ((status = register_filesystem(&nwfs_fs_type)) == 0) + NWFSPrint("nwfs: initialized successfully\n"); + + InitNWFS(); + + remirror_active = 0; + flush_active = 0; + + exit_remirror = 0; + exit_flush = 0; + + NWFSPrint("starting REMIRROR process ...\n"); + kernel_thread(nwfs_mirror, NULL, 0); + + NWFSPrint("starting LRU process ...\n"); + kernel_thread(nwfs_flush, NULL, 0); + +#if (DO_ASYNCH_IO) + NWFSPrint("starting ASYNCH_CALLBACK process ...\n"); + kernel_thread(nwfs_callback, NULL, 0); + + NWFSPrint("starting ASYNCH_IO processes [ "); + for (i=0; i < 8; i++) + { + kernel_thread(nwfs_asynch_io_process, (void *)i, 0); + NWFSPrint("%d ", (int)i); + } + NWFSPrint("]\n"); +#endif + + NWFSPrint("starting LRU Timer ...\n"); + init_timer(&flush_timer); + flush_timer.data = 0; + flush_timer.expires = jiffies + HZ; // second delay + flush_timer.function = (void (*)(ULONG))LRUTimer; + add_timer(&flush_timer); + + NWFSVolumeScan(); + ReportVolumes(); + + return status; +} + +static void __exit exit_nwfs_fs(void) +{ + register int err; +#if (DO_ASYNCH_IO) + register int i; +#endif + extern void displayMemoryList(void); + + err = unregister_filesystem(&nwfs_fs_type); + if (err) + { + NWFSPrint("nwfs: filesystem in use. unload failed\n"); + return; + } + + DismountAllVolumes(); + + NWFSPrint("Shutting Down LRU Timer ... "); + del_timer(&flush_timer); + NWFSPrint("done\n"); + + NWFSPrint("Shutting Down REMIRRORING Process ... "); + exit_remirror = TRUE; + while (remirror_active) + { + NWFSStartRemirror(); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("done\n"); + + NWFSPrint("Shutting Down LRU Process ... "); + exit_flush = TRUE; + while (flush_active) + { + NWFSFlush(); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("done\n"); + +#if (DO_ASYNCH_IO) + NWFSPrint("Shutting Down ASYNCH_CALLBACK Process ... "); + exit_callback = TRUE; + while (callback_active) + { + SignalSemaphore(&callback_semaphore); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("done\n"); + + NWFSPrint("Shutting Down ASYNCH_IO Processes [ "); + for (i=0; i < 8; i++) + { + exit_asynch_io[i] = TRUE; + while (asynch_io_active[i]) + { + RunAsynchIOQueue(i); +#if (LINUX_SLEEP) + schedule(); +#endif + } + NWFSPrint("%d ", (int)i); + } + NWFSPrint("]\n"); +#endif + + + NWFSVolumeClose(); + RemoveDiskDevices(); + FreePartitionResources(); + +} + +module_init(init_nwfs_fs) +module_exit(exit_nwfs_fs) +MODULE_LICENSE("GPL"); + + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvfs.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvfs.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvfs.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,110 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : NWVFS.H +* DESCRIP : NWFS Linux Virtual File System Definitions +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#ifndef _NWFS_VFS_ +#define _NWFS_VFS_ + +#define NWFS_REPORT_VOLUMES 25 +#define NWFS_LINUX_FS_ID 0x777 +#define LINUX_512_SHIFT 9 +#define LINUX_1024_SHIFT 10 +#define LINUX_2048_SHIFT 11 +#define LINUX_4096_SHIFT 12 + +extern struct vm_operations_struct nwfs_file_mmap; +extern struct file_operations nwfs_file_operations; +extern struct inode_operations nwfs_file_inode_operations; +extern struct file_operations nwfs_dir_operations; +extern struct inode_operations nwfs_dir_inode_operations; +extern struct file_system_type nwfs_type; +extern struct super_operations nwfs_sops; +extern struct file_operations nwfs_symlink_operations; +extern struct inode_operations nwfs_symlink_inode_operations; + +extern struct super_block *nwfs_read_super(struct super_block *sb, void *data, int silent); +extern void nwfs_put_super(struct super_block *sb); +extern void nwfs_put_inode(struct inode *inode); +extern void nwfs_read_inode(struct inode *inode); +extern int nwfs_remount(struct super_block *sb, int *flags, char *data); + +extern ULONG nwfs_file_mmap_nopage(struct vm_area_struct *area, ULONG address, int no_share); +extern int nwfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern void nwfs_truncate(struct inode *inode); + +extern void nwfs_write_inode(struct inode *inode, int wait); +extern int nwfs_notify_change(struct dentry *dentry, struct iattr *attr); +extern int nwfs_statfs(struct super_block *sb, struct statfs *buf); +extern void nwfs_delete_inode(struct inode *inode); +extern int nwfs_dir_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); +extern int nwfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir); +extern ssize_t nwfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos); +extern int nwfs_file_read(struct file *file, char *buf, size_t count, loff_t *ppos); +extern int nwfs_file_read_kernel(struct file *file, char *buf, size_t count, loff_t *ppos); +extern int nwfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos); +extern int nwfs_fsync(struct file *file, struct dentry *dentry, int datasync); +extern int nwfs_mmap(struct file *file, struct vm_area_struct *vma); +extern int nwfs_symlink(struct inode *inode, struct dentry *dentry, const char *path); +extern int nwfs_link(struct dentry *olddentry, struct inode *dir, struct dentry *dentry); +extern int nwfs_create(struct inode *inode, struct dentry *dentry, int mode); +extern int nwfs_unlink(struct inode *inode, struct dentry *dentry); +extern int nwfs_mkdir(struct inode *inode, struct dentry *dentry, int mode); +extern int nwfs_rmdir(struct inode *inode, struct dentry *dentry); +extern int nwfs_mknod(struct inode *inode, struct dentry *dentry, int mode, int rdev); +extern int nwfs_rename(struct inode *oldNode, struct dentry *old_dentry, + struct inode *newNode, struct dentry *new_dentry); +extern struct dentry *nwfs_dir_lookup(struct inode *dir, struct dentry *dentry); +extern int nwfs_readlink(struct dentry *dentry, char *buffer, int bufsiz); +extern struct dentry *nwfs_follow_link(struct dentry *dentry, struct dentry *base, + unsigned int follow); + + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvp.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvp.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvp.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,6094 @@ +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* AUTHORS : Darren Major and Jeff V. Merkey +* FILE : NWVP.C +* DESCRIP : NetWare Virtual Partition +* DATE : August 1, 1999 +* +***************************************************************************/ + +#include "globals.h" + +#if (LINUX_20 | LINUX_22 | LINUX_24) + +ULONG nwvp_auto_remirror_flag = 1; +ULONG nwvp_remirror_message_flag = 1; + +#else + +ULONG nwvp_auto_remirror_flag = 0; +ULONG nwvp_remirror_message_flag = 0; + +#endif + +ULONG nwvp_remirror_delay = 8; +ULONG handle_instance = 7; +nwvp_remirror_control *nwvp_remirror_control_list_head = 0; +void (*poll_routine)(void) = 0; +ULONG nwvp_remirror_poll(void); +BYTE *zero_block_buffer = 0; +BYTE *bit_bucket_buffer = 0; +BYTE *remirror_buffer1 = 0; +BYTE *remirror_buffer2 = 0; + +ULONG cluster_size_table[] = { 0xFFFFFFFF, 0x00000003, 0x00000004, 0xFFFFFFFF, + 0x00000005, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000006, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000007}; + +ULONG cluster_block_table[] = {0, 0, 0, 1, 2, 4, 8, 16}; + + +ULONG raw_partition_table_count = 0; +nwvp_lpart *raw_partition_table[MAX_PARTITIONS]; +ULONG logical_partition_table_count = 0; +nwvp_lpart *logical_partition_table[MAX_PARTITIONS]; +ULONG virtual_partition_table_count = 0; +nwvp_vpartition *virtual_partition_table[MAX_VOLUMES]; +ULONG unique_id = 0x55500000; + +ULONG log_table[1024]; +ULONG log_index = 0; + +void nwvp_log( + ULONG event_type, + ULONG handle, + ULONG parameter0, + ULONG parameter1) +{ + log_table[log_index + 0] = event_type; + log_table[log_index + 1] = handle; + log_table[log_index + 2] = parameter0; + log_table[log_index + 3] = parameter1; + log_index = (log_index + 4) & 0x3FF; +} + +ULONG nwvp_create_new_id(void) +{ + return(nwvp_get_date_and_time() + unique_id ++); +} + +ULONG nwvp_init_flag = 0; + +void nwvp_init() +{ + nwvp_io_alloc((void **) &zero_block_buffer, 4096); + nwvp_io_alloc((void **) &bit_bucket_buffer, 4096); + nwvp_io_alloc((void **) &remirror_buffer1, 4096); + nwvp_io_alloc((void **) &remirror_buffer2, 4096); + nwvp_memset(zero_block_buffer, 0, 4096); + nwvp_init_flag = 1; +} + +void nwvp_uninit() +{ + if (nwvp_init_flag != 0) + { + if (zero_block_buffer != 0) // initialize zero buffer + nwvp_io_free(zero_block_buffer); + zero_block_buffer = 0; + if (bit_bucket_buffer != 0) // initialize zero buffer + nwvp_io_free(bit_bucket_buffer); + bit_bucket_buffer = 0; + if (remirror_buffer1 != 0) // initialize zero buffer + nwvp_io_free(remirror_buffer1); + remirror_buffer1 = 0; + if (remirror_buffer2 != 0) // initialize zero buffer + nwvp_io_free(remirror_buffer2); + remirror_buffer2 = 0; + } + nwvp_init_flag = 0; +} + + +ULONG fat_block_check( + ULONG *fat_block, + ULONG *check_sum, + ULONG max_index, + ULONG max_link) +{ + ULONG i, j; + ULONG zero_flag = 0; + + *check_sum = 0; + + for (i=0; i < 4096/4; i+= 2) + { + *check_sum += fat_block[i] + fat_block[i+1]; + if (fat_block[i] >=max_index) + return(-1); + if (fat_block[i+1] == 0) + { + if (fat_block[i] != 0) + return(-2); + } + else + { + zero_flag = 1; + if (fat_block[i+1] != 0xFFFFFFFF) + { + if ((fat_block[i+1] & 0x80000000) == 0) + { + if (fat_block[i+1] >= max_link) + return(-3); + } + for (j=i+2; j < (4096/4); j+=2) + { + if (fat_block[j+1] == fat_block[i+1]) + return(-4); + } + } + } + } + return((zero_flag == 0) ? -5 : 0); +} + + +struct entry_info_def +{ + ULONG index1; + ULONG index2; + ULONG link1; + ULONG link2; + ULONG bits; +}; + +struct fblock_info_def +{ + ULONG *fat_block1; + ULONG *fat_block2; + ULONG block1_errors; + ULONG block2_errors; + nwvp_lpart *lpart; + ULONG block_number; + ULONG filler[2]; +}; + + + +ULONG nwvp_fat_table_fix( + nwvp_vpartition *vpartition, + nwvp_fat_fix_info *fix_info, + ULONG fix_flag) +{ + ULONG i, j; + ULONG index, link; + ULONG block_number; + ULONG *fat_block1; + ULONG *fat_block2; + ULONG current_segment; + ULONG check_sum1; + ULONG check_sum2; + ULONG data_valid; + ULONG gap_count_down; + ULONG ending_fat_block_number; + ULONG cluster_fat_block_count; + nwvp_lpart *lpart; + struct fblock_info_def *fblock_info; + struct fblock_info_def *test_info; + ULONG *master_fix_table; + + cluster_fat_block_count = (vpartition->cluster_count + 511) / 512; + cluster_fat_block_count += (vpartition->blocks_per_cluster - 1); + cluster_fat_block_count &= ~(vpartition->blocks_per_cluster - 1); + + nwvp_memset(fix_info, 0, sizeof(nwvp_fat_fix_info)); + fix_info->total_fat_blocks = cluster_fat_block_count; + fix_info->total_entries = cluster_fat_block_count * 512; + + nwvp_alloc((void **) &master_fix_table, ((cluster_fat_block_count + 0x7F) / 0x80) * 4); + nwvp_memset(master_fix_table, 0, ((cluster_fat_block_count + 0x7F) / 0x80) * 4); + + for (i=0; i> 7], 4096); + nwvp_memset((void *) master_fix_table[i >> 7], 0, 4096); + } + + + gap_count_down = 0x40; + current_segment = 0; + block_number = vpartition->segments[current_segment].partition_block_offset; + lpart = vpartition->segments[current_segment].lpart_link; + + for (i=0; iblocks_per_cluster) == 0) + { + ending_fat_block_number = (vpartition->segments[current_segment].relative_cluster_offset + + (vpartition->segments[current_segment].segment_block_count / vpartition->blocks_per_cluster) + 511) / 512; + while (i >= ending_fat_block_number) + { + current_segment ++; + block_number = vpartition->segments[current_segment].partition_block_offset; + lpart = vpartition->segments[current_segment].lpart_link; + gap_count_down = 0x40; + ending_fat_block_number = (vpartition->segments[current_segment].relative_cluster_offset + + (vpartition->segments[current_segment].segment_block_count / vpartition->blocks_per_cluster) + 511) / 512; + } + } + + fblock_info =(struct fblock_info_def *) master_fix_table[i >> 7]; + fblock_info += i & 0x7F; + fblock_info->lpart = lpart; + fblock_info->block_number = block_number; + + gap_count_down --; + if (gap_count_down == 0) + { + gap_count_down = 0x40; + block_number += 0x40; + } + } + + nwvp_alloc((void **) &fat_block1, 4096); + nwvp_alloc((void **) &fat_block2, 4096); + + for (i=0; i> 7]; + fblock_info += i & 0x7F; + lpart = fblock_info->lpart; + block_number = fblock_info->block_number; + + data_valid = 0; + check_sum1 = 0xFFFFFFFF; + check_sum2 = 0xFFFFFFFF; + if (inwvp_lpartition_block_read(lpart, block_number, 1, (BYTE *) fat_block1) == 0) + { + if ((fat_block_check(fat_block1, &check_sum1, 0x01000000, vpartition->cluster_count) == 0) || + (nwvp_memcomp(fat_block1, zero_block_buffer, 4096) == 0)) + data_valid |= 0x01; + } + + if (inwvp_lpartition_block_read(lpart, block_number + 0x40, 1, (BYTE *) fat_block2) == 0) + { + if ((fat_block_check(fat_block2, &check_sum2, 0x01000000, vpartition->cluster_count) == 0) || + (nwvp_memcomp(fat_block2, zero_block_buffer, 4096) == 0)) + data_valid |= 0x02; + } + + switch(data_valid) + { + case 0: + nwvp_memset(fat_block1, 0, 4096); + fblock_info->fat_block1 = fat_block1; + fblock_info->fat_block2 = fat_block1; + nwvp_alloc((void **) &fat_block1, 4096); + fix_info->total_missing_blocks ++; + break; + case 1: + fblock_info->fat_block1 = fat_block1; + fblock_info->fat_block2 = fat_block1; + nwvp_alloc((void **) &fat_block1, 4096); + fix_info->total_valid_single_blocks ++; + break; + case 2: + fblock_info->fat_block1 = fat_block2; + fblock_info->fat_block2 = fat_block2; + nwvp_alloc((void **) &fat_block2, 4096); + fix_info->total_valid_single_blocks ++; + break; + case 3: + if (nwvp_memcomp(fat_block1, fat_block2, 4096) == 0) + { + fblock_info->fat_block1 = fat_block1; + fblock_info->fat_block2 = fat_block1; + nwvp_alloc((void **) &fat_block1, 4096); + fix_info->total_valid_mirror_blocks ++; + } + else + { + fblock_info->fat_block1 = fat_block1; + fblock_info->fat_block2 = fat_block2; + nwvp_alloc((void **) &fat_block1, 4096); + nwvp_alloc((void **) &fat_block2, 4096); + fix_info->total_mismatch_blocks ++; + } + } + } + + nwvp_free(fat_block1); + nwvp_free(fat_block2); + + if (fix_flag != 0) + { + for (i=0; i> 7]; + fblock_info += i & 0x7F; + + for (j=0; j<512; j++) + { + if (fblock_info->fat_block1 != fblock_info->fat_block2) + { + index = fblock_info->fat_block1[j * 2]; + if ((link = fblock_info->fat_block1[(j * 2) + 1]) != 0) + { + if ((link & 0x80000000) == 0) + { + test_info = (struct fblock_info_def *) master_fix_table[link >> (7 + 9)]; + test_info += (link >> 9) & 0x7F; + if ((test_info->fat_block1[(link % 512) * 2] <= index) && + (test_info->fat_block2[(link % 512) * 2] <= index)) + fblock_info->block1_errors ++; + } + } + + index = fblock_info->fat_block2[j * 2]; + if ((link = fblock_info->fat_block2[(j * 2) + 1]) != 0) + { + if ((link & 0x80000000) == 0) + { + test_info = (struct fblock_info_def *) master_fix_table[link >> (7 + 9)]; + test_info += (link >> 9) & 0x7F; + if ((test_info->fat_block1[(link % 512) * 2] <= index) && + (test_info->fat_block2[(link % 512) * 2] <= index)) + fblock_info->block2_errors ++; + } + } + + } + else + { + index = fblock_info->fat_block1[j * 2]; + if ((link = fblock_info->fat_block1[(j * 2) + 1]) != 0) + { + if ((link & 0x80000000) == 0) + { + test_info = (struct fblock_info_def *) master_fix_table[link >> (7 + 9)]; + test_info += (link >> 9) & 0x7F; + if (test_info->fat_block1 != test_info->fat_block2) + { + if (test_info->fat_block1[(link % 512) * 2] <= index) + test_info->block1_errors ++; + if (test_info->fat_block2[(link % 512) * 2] <= index) + test_info->block2_errors ++; + } + } + } + } + } + } + + + for (i=0; i> 7]; + fblock_info += i & 0x7F; + lpart = fblock_info->lpart; + block_number = fblock_info->block_number; + if (fblock_info->block1_errors <= fblock_info->block2_errors) + { + inwvp_lpartition_block_write(lpart, block_number, 1, (BYTE *) fblock_info->fat_block1); + inwvp_lpartition_block_write(lpart, block_number + 0x40, 1, (BYTE *) fblock_info->fat_block1); + } + else + { + inwvp_lpartition_block_write(lpart, block_number, 1, (BYTE *) fblock_info->fat_block2); + inwvp_lpartition_block_write(lpart, block_number + 0x40, 1, (BYTE *) fblock_info->fat_block2); + } + } + vpartition->volume_valid_flag = 0; + } + + for (i=0; i> 7]; + fblock_info += i & 0x7F; + if (fblock_info->fat_block2 != fblock_info->fat_block1) + nwvp_free(fblock_info->fat_block2); + nwvp_free(fblock_info->fat_block1); + } + + if (fix_info->total_fat_blocks == fix_info->total_valid_mirror_blocks) + vpartition->volume_valid_flag = 0; + + for (i=0; i> 7]); + nwvp_free((void *) master_fix_table); + return(0); +} + + +ULONG nwvp_vpartition_validate( + nwvp_vpartition **new_vpartition, + VOLUME_TABLE_ENTRY *ventry) +{ + ULONG j; + nwvp_vpartition *vpartition; + + for (j=0; jVolumeName[0], &vpartition->volume_name[0], 16) == 0) && + (ventry->LastVolumeSegment == (vpartition->segment_count - 1)) && + (((ventry->VolumeSignature >> 8) & 0xFF) == vpartition->segment_count) && + (cluster_block_table[ventry->VolumeSignature & 0xFF] == vpartition->blocks_per_cluster) && + (ventry->VolumeClusters == vpartition->cluster_count) && + (ventry->FirstFAT == vpartition->FAT1) && + (ventry->SecondFAT == vpartition->FAT2) && + (ventry->FirstDirectory == vpartition->Directory1) && + (ventry->SecondDirectory == vpartition->Directory2)) + { + *new_vpartition = vpartition; + return(0); + } + } + } + return(-1); +} + + + +ULONG nwvp_segmentation_remove_specific( + nwvp_lpart *lpart, + ULONG segment_index) +{ + ULONG i; + + for (i=segment_index; i<=lpart->segment_sector->NumberOfTableEntries; i++) + { + nwvp_memmove(&lpart->segment_sector->VolumeEntry[i], &lpart->segment_sector->VolumeEntry[i+1], sizeof(VOLUME_TABLE_ENTRY)); + vpartition_update_entry_index(lpart, lpart->segment_sector->VolumeEntry[i+1].VolumeName, i+1, i); + } + lpart->segment_sector->NumberOfTableEntries --; + nwvp_segmentation_sectors_flush(lpart); + return(0); +} + +ULONG nwvp_segmentation_remove( + nwvp_lpart *lpart) +{ + ULONG i, j, k; + nwvp_vpartition *vpartition; + + for (j=0; jsegment_count; i++) + { + if (vpartition->segments[i].lpart_link == lpart) + { + if (vpartition->open_flag != 0) + inwvp_vpartition_close(vpartition); + vpartition->volume_valid_flag = 0xFFFFFFFF; + vpartition->segments[i].lpart_link = 0; + vpartition->segments[i].segment_block_count = 0; + vpartition->segments[i].partition_block_offset = 0; + vpartition->segments[i].relative_cluster_offset = 0; + vpartition->segments[i].volume_entry_index = 0; + for (k=0; ksegment_count; k++) + { + if (vpartition->segments[k].lpart_link != 0) + break; + } + if (k == vpartition->segment_count) + { + virtual_partition_table[vpartition->vpartition_handle & 0x0000FFFF] = 0; + nwvp_free(vpartition); + } + break; + } + } + } + } + return(0); +} + +ULONG nwvp_segmentation_add( + nwvp_lpart *lpart) +{ + ULONG i, k; + ULONG index; + ULONG valid_flag; + ULONG found_flag; + nwvp_vpartition *vpartition; + + if ((lpart->segment_sector->VolumeTableSignature[0] == 'N') && + (lpart->segment_sector->VolumeTableSignature[1] == 'e') && + (lpart->segment_sector->VolumeTableSignature[2] == 't') && + (lpart->segment_sector->VolumeTableSignature[3] == 'W') && + (lpart->segment_sector->VolumeTableSignature[4] == 'a') && + (lpart->segment_sector->VolumeTableSignature[5] == 'r') && + (lpart->segment_sector->VolumeTableSignature[6] == 'e') && + (lpart->segment_sector->VolumeTableSignature[7] == ' ') && + (lpart->segment_sector->VolumeTableSignature[8] == 'V') && + (lpart->segment_sector->VolumeTableSignature[9] == 'o') && + (lpart->segment_sector->VolumeTableSignature[10] == 'l') && + (lpart->segment_sector->VolumeTableSignature[11] == 'u') && + (lpart->segment_sector->VolumeTableSignature[12] == 'm') && + (lpart->segment_sector->VolumeTableSignature[13] == 'e') && + (lpart->segment_sector->VolumeTableSignature[14] == 's') && + (lpart->segment_sector->VolumeTableSignature[15] == 0)) + { + for (i=0; isegment_sector->NumberOfTableEntries; i++) + { + found_flag = 0; + if (nwvp_vpartition_validate(&vpartition, &lpart->segment_sector->VolumeEntry[i]) == 0) + { + valid_flag = 0xFFFFFFFF; + index = (lpart->segment_sector->VolumeEntry[i].VolumeSignature >> 16) & 0xFF; + + if (vpartition->segments[index].lpart_link != 0) + { + valid_flag = 0; + } + if ((index > 0) && (vpartition->segments[index-1].lpart_link != 0)) + { + if (((vpartition->segments[index-1].relative_cluster_offset * vpartition->blocks_per_cluster) + vpartition->segments[index-1].segment_block_count) != + (lpart->segment_sector->VolumeEntry[i].SegmentClusterStart * vpartition->blocks_per_cluster)) + { + valid_flag = 0; + } + } + if ((index < (vpartition->segment_count - 1)) && (vpartition->segments[index+1].lpart_link != 0)) + { + if ((vpartition->segments[index+1].relative_cluster_offset * vpartition->blocks_per_cluster) != + ((lpart->segment_sector->VolumeEntry[i].SegmentClusterStart * vpartition->blocks_per_cluster) + + ((lpart->segment_sector->VolumeEntry[i].SegmentSectors / (lpart->sectors_per_block * vpartition->blocks_per_cluster)) * vpartition->blocks_per_cluster))) + { + valid_flag = 0; + } + } + + if (valid_flag != 0) + { + if (lpart->mirror_link != lpart) + vpartition->mirror_flag = 0xFFFFFFFF; + vpartition->segments[index].lpart_link = lpart; + vpartition->segments[index].segment_block_count = (lpart->segment_sector->VolumeEntry[i].SegmentSectors / (lpart->sectors_per_block * vpartition->blocks_per_cluster)) * vpartition->blocks_per_cluster; + vpartition->segments[index].partition_block_offset = lpart->segment_sector->VolumeEntry[i].VolumeRoot / lpart->sectors_per_block; + vpartition->segments[index].relative_cluster_offset = lpart->segment_sector->VolumeEntry[i].SegmentClusterStart; + vpartition->segments[index].volume_entry_index = i; + found_flag = 1; + for (k=0; ksegment_count; k++) + { + if (vpartition->segments[k].lpart_link == 0) + break; + } + if (k == vpartition->segment_count) + { + vpartition->volume_valid_flag = 0x00000000; + } + } + } + if (found_flag == 0) + { + nwvp_alloc((void **) &vpartition, sizeof(nwvp_vpartition)); + nwvp_memset(vpartition, 0, sizeof(nwvp_vpartition)); + vpartition->volume_valid_flag = 0xFFFFFFFF; + + for (k=0; k= MAX_VOLUMES) + { + nwvp_free(vpartition); + return(-1); + } + if (k == virtual_partition_table_count) + { + virtual_partition_table_count ++; + } + if (lpart->mirror_link != lpart) + vpartition->mirror_flag = 0xFFFFFFFF; + virtual_partition_table[k] = vpartition; + vpartition->vpartition_handle = (handle_instance ++ << 16) + k; + index = (lpart->segment_sector->VolumeEntry[i].VolumeSignature >> 16) & 0xFF; + vpartition->segment_count = (lpart->segment_sector->VolumeEntry[i].VolumeSignature >> 8) & 0xFF; + vpartition->cluster_count = lpart->segment_sector->VolumeEntry[i].VolumeClusters; + nwvp_memmove(&vpartition->volume_name[0], &lpart->segment_sector->VolumeEntry[i].VolumeName[0], 16); + vpartition->FAT1 = lpart->segment_sector->VolumeEntry[i].FirstFAT; + vpartition->FAT2 = lpart->segment_sector->VolumeEntry[i].SecondFAT; + vpartition->Directory1 = lpart->segment_sector->VolumeEntry[i].FirstDirectory; + vpartition->Directory2 = lpart->segment_sector->VolumeEntry[i].SecondDirectory; + vpartition->blocks_per_cluster = cluster_block_table[lpart->segment_sector->VolumeEntry[i].VolumeSignature & 0xFF]; + vpartition->segments[index].lpart_link = lpart; + vpartition->segments[index].segment_block_count = (lpart->segment_sector->VolumeEntry[i].SegmentSectors / (lpart->sectors_per_block * vpartition->blocks_per_cluster)) * vpartition->blocks_per_cluster; + vpartition->segments[index].partition_block_offset = lpart->segment_sector->VolumeEntry[i].VolumeRoot / lpart->sectors_per_block; + vpartition->segments[index].relative_cluster_offset = lpart->segment_sector->VolumeEntry[i].SegmentClusterStart; + vpartition->segments[index].volume_entry_index = i; + if (vpartition->segment_count == 1) + { + vpartition->volume_valid_flag = 0x00000000; + } + } + } + } + else + { + nwvp_memset(lpart->segment_sector, 0, 512); + lpart->segment_sector->VolumeTableSignature[0] = 'N'; + lpart->segment_sector->VolumeTableSignature[1] = 'e'; + lpart->segment_sector->VolumeTableSignature[2] = 't'; + lpart->segment_sector->VolumeTableSignature[3] = 'W'; + lpart->segment_sector->VolumeTableSignature[4] = 'a'; + lpart->segment_sector->VolumeTableSignature[5] = 'r'; + lpart->segment_sector->VolumeTableSignature[6] = 'e'; + lpart->segment_sector->VolumeTableSignature[7] = ' '; + lpart->segment_sector->VolumeTableSignature[8] = 'V'; + lpart->segment_sector->VolumeTableSignature[9] = 'o'; + lpart->segment_sector->VolumeTableSignature[10] = 'l'; + lpart->segment_sector->VolumeTableSignature[11] = 'u'; + lpart->segment_sector->VolumeTableSignature[12] = 'm'; + lpart->segment_sector->VolumeTableSignature[13] = 'e'; + lpart->segment_sector->VolumeTableSignature[14] = 's'; + lpart->segment_sector->VolumeTableSignature[15] = 0; + } + return(0); +} + +ULONG nwvp_segmentation_sectors_flush( + nwvp_lpart *lpart) +{ + ULONG i; + ULONG error_count = 0; + BYTE *temp_buffer; + + lpart->segment_sector->VolumeTableSignature[0] = 'N'; + lpart->segment_sector->VolumeTableSignature[1] = 'e'; + lpart->segment_sector->VolumeTableSignature[2] = 't'; + lpart->segment_sector->VolumeTableSignature[3] = 'W'; + lpart->segment_sector->VolumeTableSignature[4] = 'a'; + lpart->segment_sector->VolumeTableSignature[5] = 'r'; + lpart->segment_sector->VolumeTableSignature[6] = 'e'; + lpart->segment_sector->VolumeTableSignature[7] = ' '; + lpart->segment_sector->VolumeTableSignature[8] = 'V'; + lpart->segment_sector->VolumeTableSignature[9] = 'o'; + lpart->segment_sector->VolumeTableSignature[10] = 'l'; + lpart->segment_sector->VolumeTableSignature[11] = 'u'; + lpart->segment_sector->VolumeTableSignature[12] = 'm'; + lpart->segment_sector->VolumeTableSignature[13] = 'e'; + lpart->segment_sector->VolumeTableSignature[14] = 's'; + lpart->segment_sector->VolumeTableSignature[15] = 0; + nwvp_io_alloc((void **) &temp_buffer, 4096); + nwvp_memset(temp_buffer, 0, 4096); + for (i=4; i<=16; i+= 4) + { + if (inwvp_lpartition_block_read( + lpart, + i, + 1, + (BYTE *) temp_buffer) == 0) + { + nwvp_memmove(temp_buffer, lpart->segment_sector, 512); + if (inwvp_lpartition_block_write( + lpart, + i, + 1, + (BYTE *) temp_buffer) != 0) + error_count ++; + } + else + error_count ++; + } + nwvp_io_free(temp_buffer); + return(error_count); +} + +ULONG nwvp_segmentation_sector_validate( + VOLUME_TABLE *seg_sector) +{ + if ((seg_sector->VolumeTableSignature[0] == 'N') && + (seg_sector->VolumeTableSignature[1] == 'e') && + (seg_sector->VolumeTableSignature[2] == 't') && + (seg_sector->VolumeTableSignature[3] == 'W') && + (seg_sector->VolumeTableSignature[4] == 'a') && + (seg_sector->VolumeTableSignature[5] == 'r') && + (seg_sector->VolumeTableSignature[6] == 'e') && + (seg_sector->VolumeTableSignature[7] == ' ') && + (seg_sector->VolumeTableSignature[8] == 'V') && + (seg_sector->VolumeTableSignature[9] == 'o') && + (seg_sector->VolumeTableSignature[10] == 'l') && + (seg_sector->VolumeTableSignature[11] == 'u') && + (seg_sector->VolumeTableSignature[12] == 'm') && + (seg_sector->VolumeTableSignature[13] == 'e') && + (seg_sector->VolumeTableSignature[14] == 's')) + { + return(0); + } + return(-1); +} + +ULONG nwvp_segmentation_sectors_load( + nwvp_lpart *lpart) +{ + ULONG i; + BYTE *temp_buffer; + ULONG valid_flag = 0; + ULONG invalid_count = 0; + + nwvp_io_alloc((void **) &temp_buffer, 4096); + nwvp_memset(temp_buffer, 0, 4096); + if (lpart->segment_sector == 0) + nwvp_alloc((void **) &lpart->segment_sector, 512); + for (i=0; i<4; i++) + { + if (inwvp_lpartition_block_read( + lpart, + (4 + (i * 4)), + 1, + (BYTE *) temp_buffer) == 0) + { + if (valid_flag == 0) + { + if (nwvp_segmentation_sector_validate((VOLUME_TABLE * ) temp_buffer) == 0) + valid_flag = 1; + nwvp_memmove(lpart->segment_sector, temp_buffer, 512); + } + else + { + if (nwvp_memcomp(lpart->segment_sector, temp_buffer, 512) != 0) + invalid_count ++; + } + } + else + invalid_count ++; + } + nwvp_io_free(temp_buffer); + if (valid_flag != 0) + { + if (invalid_count != 0) + nwvp_segmentation_sectors_flush(lpart); + return(0); + } + return(-1); +} + +ULONG nwvp_master_sectors_flush( + nwvp_lpart *lpart) +{ + ULONG i; + BYTE *temp_buffer; + + if ((lpart->mirror_status & MIRROR_READ_ONLY_BIT) == 0) + { + nwvp_io_alloc((void **) &temp_buffer, 4096); + if (nwvp_part_read( + lpart->rpart_handle, + 0x20, + 8, + temp_buffer) == 0) + { + nwvp_memmove(&temp_buffer[0], lpart->hotfix.sector, 512); + nwvp_memmove(&temp_buffer[512], lpart->netware_mirror_sector, 512); + nwvp_memmove(&temp_buffer[1024], lpart->mirror_sector, 512); + for (i=0x20; i<0x81; i+= 0x20) + { + if (nwvp_part_write( + lpart->rpart_handle, + i, + 8, + temp_buffer) != 0) + { + } + } + } + nwvp_io_free(temp_buffer); + } + return(0); +} + + +ULONG nwvp_netware_mirror_update( + nwvp_lpart *lpart, + ULONG flush_flag) +{ + ULONG i, j; + nwvp_lpart *temp; + + nwvp_memset(lpart->netware_mirror_sector, 0, 512); + + lpart->netware_mirror_sector->MirrorStamp[0] = 'M'; + lpart->netware_mirror_sector->MirrorStamp[1] = 'I'; + lpart->netware_mirror_sector->MirrorStamp[2] = 'R'; + lpart->netware_mirror_sector->MirrorStamp[3] = 'R'; + lpart->netware_mirror_sector->MirrorStamp[4] = 'O'; + lpart->netware_mirror_sector->MirrorStamp[5] = 'R'; + lpart->netware_mirror_sector->MirrorStamp[6] = '0'; + lpart->netware_mirror_sector->MirrorStamp[7] = '0'; + lpart->netware_mirror_sector->PartitionID = lpart->mirror_partition_id; + lpart->netware_mirror_sector->Reserved1 = 0x0703f808;; + lpart->netware_mirror_sector->MirrorStatus = NETWARE_5_BASE_BIT; + lpart->netware_mirror_sector->MirrorFlags = NETWARE_IN_SYNCH_INSTANCE; + if (((lpart->primary_link->mirror_status & MIRROR_GROUP_OPEN_BIT) != 0) || + ((lpart->primary_link->mirror_status & MIRROR_GROUP_CHECK_BIT) != 0)) + lpart->netware_mirror_sector->MirrorFlags |= NETWARE_INUSE_BIT; + lpart->netware_mirror_sector->MirrorTotalSectors = lpart->hotfix.sector->HotFixTotalSectors; + lpart->netware_mirror_sector->MirrorGroupID = lpart->mirror_group_id; + + for (i=0, j=0; i<30; i++) + { + if ((lpart->mirror_sector->log[i].partition_id != 0) && + (lpart->mirror_sector->log[i].status != NWVP_MIRROR_STATUS_REMOVED) && + (lpart->mirror_sector->log[i].status != NWVP_MIRROR_STATUS_BAD)) + { +#if (DEBUG_MIRROR_CONTROL) +NWFSPrint("flush_flag = %d lpart = %x i = %d status = %x \n", + (int) flush_flag, (unsigned) lpart, + (int)i, (unsigned)lpart->mirror_sector->log[i].status); +#endif + + lpart->netware_mirror_sector->MirrorMemberID[j] = lpart->mirror_sector->log[i].partition_id; + temp = lpart; + do + { + if (temp->mirror_partition_id == lpart->mirror_sector->log[i].partition_id) + { + if (temp->remirror_section != 0) + { +#if (DEBUG_MIRROR_CONTROL) +NWFSPrint("out of synch guy \n"); +#endif + lpart->netware_mirror_sector->MirrorStatus |= 1 << j; + } + } + temp = temp->mirror_link; + } while (temp != lpart); + j++; + } + } + + temp = lpart; + do + { + temp = temp->mirror_link; + } while (temp != lpart); + if (flush_flag != 0) + nwvp_master_sectors_flush(lpart); + return(0); +} + +ULONG nwvp_segment_sectors_zap( + nwvp_lpart *lpart) +{ + nwvp_part_write(lpart->rpart_handle, (lpart->hotfix.block_count * lpart->sectors_per_block) + 0x20, lpart->sectors_per_block, zero_block_buffer); + nwvp_part_write(lpart->rpart_handle, (lpart->hotfix.block_count * lpart->sectors_per_block) + 0x40, lpart->sectors_per_block, zero_block_buffer); + nwvp_part_write(lpart->rpart_handle, (lpart->hotfix.block_count * lpart->sectors_per_block) + 0x60, lpart->sectors_per_block, zero_block_buffer); + nwvp_part_write(lpart->rpart_handle, (lpart->hotfix.block_count * lpart->sectors_per_block) + 0x80, lpart->sectors_per_block, zero_block_buffer); + return(0); +} + +ULONG nwvp_hotfix_sectors_zap( + nwvp_lpart *lpart) +{ + nwvp_part_write(lpart->rpart_handle, 0x20, lpart->sectors_per_block, zero_block_buffer); + nwvp_part_write(lpart->rpart_handle, 0x40, lpart->sectors_per_block, zero_block_buffer); + nwvp_part_write(lpart->rpart_handle, 0x60, lpart->sectors_per_block, zero_block_buffer); + nwvp_part_write(lpart->rpart_handle, 0x80, lpart->sectors_per_block, zero_block_buffer); + return(0); +} + +ULONG nwvp_hotfix_tables_flush( + nwvp_lpart *lpart, + ULONG table_index) +{ + ULONG error_count = 0; + ULONG index; + ULONG *table_entry; + ULONG current_index; + ULONG master_flush_flag = 0; + ULONG *data_buffer = 0; + + if ((lpart->mirror_status & MIRROR_READ_ONLY_BIT) != 0) + return(0); + + current_index = table_index >> 10; + while (error_count < 5) + { + if (nwvp_part_write( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[current_index].HotFix1, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.hotfix_table[current_index]) == 0) + { + if (nwvp_part_write( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[current_index].HotFix2, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.hotfix_table[current_index]) == 0) + { + if (nwvp_part_write( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[current_index].BadBlock1, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.bad_bit_table[current_index]) == 0) + { + if (nwvp_part_write( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[current_index].BadBlock2, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.bad_bit_table[current_index]) == 0) + { + if (data_buffer != 0) + nwvp_free(data_buffer); + if (master_flush_flag != 0) + nwvp_master_sectors_flush(lpart); + return(0); + } + table_entry = &lpart->hotfix.sector->HotFixTable[current_index].BadBlock2; + } + else + { + table_entry = &lpart->hotfix.sector->HotFixTable[current_index].BadBlock1; + } + } + else + { + table_entry = &lpart->hotfix.sector->HotFixTable[current_index].HotFix2; + } + } + else + { + table_entry = &lpart->hotfix.sector->HotFixTable[current_index].HotFix1; + } + + error_count ++; + if (data_buffer == 0) + nwvp_io_alloc((void **) &data_buffer, 4096); + + if (nwvp_part_read(lpart->rpart_handle, 0, lpart->sectors_per_block, (BYTE *) data_buffer) != 0) + break; + + for (index = 0; index < lpart->hotfix.block_count; index ++) + { + if (lpart->hotfix.hotfix_table[index >> 10][index & 0x3FF] == 0) + { + lpart->hotfix.hotfix_table[index >> 10][index & 0x3FF] = 0xFFFFFFFF; + lpart->hotfix.bad_bit_table[index >> 10][index & 0x3FF] = 0xFFFFFFFF; + *table_entry = index * lpart->sectors_per_block; + master_flush_flag = 1; + break; + } + } + + if (index == lpart->hotfix.block_count) + break; + } + nwvp_log(NWLOG_DEVICE_OFFLINE, lpart->lpartition_handle, lpart->rpart_handle, 0); + lpart->rpart_handle = 0xFFFFFFFF; + lpart->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + if (nwvp_mirror_group_update(lpart->primary_link) != 0) + { + nwvp_mirror_group_delete(lpart->primary_link); + } + if (data_buffer != 0) + nwvp_io_free(data_buffer); + return(-1); +} + +ULONG nwvp_hotfix_tables_load( + nwvp_lpart *lpart) +{ + ULONG i; + + for (i=0; i<((lpart->hotfix.block_count + 0x3FF) >> 10); i++) + { + if (nwvp_part_read( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[i].HotFix1, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.hotfix_table[i]) != 0) + { + return(-1); + } + if (nwvp_part_read( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[i].HotFix2, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.hotfix_table[i]) != 0) + { + return(-1); + } + if (nwvp_part_read( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[i].BadBlock1, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.bad_bit_table[i]) != 0) + { + return(-1); + } + if (nwvp_part_read( + lpart->rpart_handle, + lpart->hotfix.sector->HotFixTable[i].BadBlock2, + lpart->sectors_per_block, + (BYTE *) lpart->hotfix.bad_bit_table[i]) != 0) + { + return(-1); + } + } + return(0); +} + +ULONG nwvp_hotfix_tables_alloc( + nwvp_lpart *lpart) +{ + ULONG i; + if (lpart->hotfix.hotfix_table == 0) + { + nwvp_alloc((void **) &lpart->hotfix.hotfix_table, ((lpart->hotfix.block_count + 0x3FF) >> 10) * 4); + nwvp_memset(lpart->hotfix.hotfix_table, 0, ((lpart->hotfix.block_count + 0x3FF) >> 10) * 4); + } + if (lpart->hotfix.bad_bit_table == 0) + { + nwvp_alloc((void **) &lpart->hotfix.bad_bit_table, ((lpart->hotfix.block_count + 0x3FF) >> 10) * 4); + nwvp_memset(lpart->hotfix.bad_bit_table, 0, ((lpart->hotfix.block_count + 0x3FF) >> 10) * 4); + } + if (lpart->hotfix.bit_table == 0) + { + nwvp_alloc((void **) &lpart->hotfix.bit_table, ((lpart->logical_block_count + 0x7FFF) >> 15) * 4); + nwvp_memset(lpart->hotfix.bit_table, 0, ((lpart->logical_block_count + 0x7FFF) >> 15) * 4); + } + if (lpart->hotfix.sector == 0) + { + nwvp_alloc((void **) &lpart->hotfix.sector, 512); + nwvp_memset(lpart->hotfix.sector, 0, 512); + } + + if (lpart->segment_sector == 0) + { + nwvp_alloc((void **) &lpart->segment_sector, 512); + nwvp_memset(lpart->segment_sector, 0, 512); + } + for (i=0; ihotfix.block_count; i+= 0x400) + { + if (lpart->hotfix.hotfix_table[i >> 10] == 0) + { + nwvp_io_alloc((void **) &(lpart->hotfix.hotfix_table[i >> 10]), 4096); + nwvp_memset(lpart->hotfix.hotfix_table[i >> 10], 0, 4096); + } + if (lpart->hotfix.bad_bit_table[i >> 10] == 0) + { + nwvp_io_alloc((void **) &(lpart->hotfix.bad_bit_table[i >> 10]), 4096); + nwvp_memset(lpart->hotfix.bad_bit_table[i >> 10], 0, 4096); + } + } + for (i=0; ilogical_block_count; i+= 0x8000) + { + if (lpart->hotfix.bit_table[i >> 15] == 0) + { + nwvp_io_alloc((void **) &lpart->hotfix.bit_table[i >> 15], 4096); + nwvp_memset(lpart->hotfix.bit_table[i >> 15], 0, 4096); + } + } + return(0); +} + +ULONG nwvp_hotfix_tables_free( + nwvp_lpart *lpart) +{ + ULONG i; + if (lpart->hotfix.hotfix_table != 0) + { + for (i=0; ihotfix.block_count; i+= 0x400) + { + if (lpart->hotfix.hotfix_table[i >> 10] != 0) + nwvp_io_free(lpart->hotfix.hotfix_table[i >> 10]); + } + nwvp_free(lpart->hotfix.hotfix_table); + lpart->hotfix.hotfix_table = 0; + } + + if (lpart->hotfix.bad_bit_table != 0) + { + for (i=0; ihotfix.block_count; i+= 0x400) + { + if (lpart->hotfix.bad_bit_table[i >> 10] != 0) + nwvp_io_free(lpart->hotfix.bad_bit_table[i >> 10]); + } + nwvp_free(lpart->hotfix.bad_bit_table); + lpart->hotfix.bad_bit_table = 0; + } + + if (lpart->hotfix.bit_table != 0) + { + for (i=0; ilogical_block_count; i+= 0x8000) + { + nwvp_io_free(lpart->hotfix.bit_table[i >> 15]); + } + nwvp_free(lpart->hotfix.bit_table); + lpart->hotfix.bit_table = 0; + } + + if (lpart->hotfix.sector != 0) + { + nwvp_free(lpart->hotfix.sector); + lpart->hotfix.sector = 0; + } + + if (lpart->segment_sector != 0) + { + nwvp_free(lpart->segment_sector); + lpart->segment_sector = 0; + } + return(0); +} + +ULONG nwvp_hotfix_destroy( + nwvp_lpart *lpart) +{ + ULONG i; + BYTE *temp_buffer; + + nwvp_io_alloc((void **) &temp_buffer, 4096); + nwvp_memset(temp_buffer, 0, 4096); + + lpart->remirror_section = 0xFFFFFFFF; + lpart->lpartition_handle = 0xFFFFFFFF; + lpart->mirror_partition_id = 0xFFFFFFFe; + lpart->mirror_group_id = 0xFFFFFFFd; + + nwvp_hotfix_tables_free(lpart); + nwvp_memset(lpart->netware_mirror_sector, 0, 512); + nwvp_memset(lpart->mirror_sector, 0, 512); + for (i=0x20; i<0x81; i+= 0x20) + { + nwvp_part_write( + lpart->rpart_handle, + i, + 8, + temp_buffer); + } + nwvp_io_free(temp_buffer); + return(0); +} + +ULONG nwvp_hotfix_and_mirror_validate( + BYTE *buffer, + ULONG capacity) +{ + HOTFIX *hf_sector; + MIRROR *mr_sector; + + hf_sector = (HOTFIX *) &buffer[0]; + mr_sector = (MIRROR *) &buffer[512]; + if ((nwvp_memcomp(&hf_sector->HotFixStamp[0], "HOTFIX00", 8) == 0) && + (nwvp_memcomp(&mr_sector->MirrorStamp[0], "MIRROR00", 8) == 0)) + { + if ((hf_sector->HotFixTotalSectors + hf_sector->HotFixSize) <= capacity) + { + return(0); + } + } + return(-1); +} + +ULONG nwvp_hotfix_scan( + nwvp_lpart *lpart) +{ + ULONG i; + ULONG block_number; + ULONG *table; + BYTE *table_buffer; + HOTFIX *hf_sector; + + nwvp_io_alloc((void **) &table_buffer, 4096); + hf_sector = (HOTFIX *) &table_buffer[0]; + if (nwvp_part_read(lpart->rpart_handle, + 4 * lpart->sectors_per_block, + lpart->sectors_per_block, + (BYTE *) hf_sector) == 0) + { + if (nwvp_hotfix_and_mirror_validate(table_buffer, lpart->physical_block_count * lpart->sectors_per_block) == 0) + { + lpart->logical_block_count = hf_sector->HotFixTotalSectors / lpart->sectors_per_block; + lpart->hotfix.block_count = hf_sector->HotFixSize / lpart->sectors_per_block; + nwvp_hotfix_tables_alloc(lpart); + nwvp_memmove(lpart->hotfix.sector, &table_buffer[0], 512); + if ((lpart->primary_link->mirror_status & MIRROR_GROUP_ESTABLISHED_BIT) == 0) + { + nwvp_memmove(lpart->netware_mirror_sector, &table_buffer[512], 512); + nwvp_memmove(lpart->mirror_sector, &table_buffer[1024], 512); + } + nwvp_hotfix_tables_load(lpart); + for (i=0; ihotfix.block_count; i++) + { + if ((table = lpart->hotfix.hotfix_table[i >> 10]) != 0) + { + if ((table[i & 0x3FF] != 0) && (table[i & 0x3FF] != 0xFFFFFFFF)) + { + block_number = table[i & 0x3FF] / 8; + lpart->hotfix.bit_table[block_number >> 15][(block_number >> 5) & 0x3FF] |= (1 << (block_number & 0x1F)); + } + } + } + nwvp_io_free(table_buffer); + return(0); + } + } + nwvp_io_free(table_buffer); + return(0); +} + +ULONG nwvp_hotfix_create( + nwvp_lpart *lpart, + ULONG logical_block_count) +{ + ULONG i, j, index; + + lpart->logical_block_count = logical_block_count; + if ((lpart->hotfix.block_count = lpart->physical_block_count - logical_block_count) > 0x4000) + lpart->hotfix.block_count = 0x4000; + nwvp_hotfix_tables_alloc(lpart); + lpart->hotfix.sector->HotFixStamp[0] = 'H'; + lpart->hotfix.sector->HotFixStamp[1] = 'O'; + lpart->hotfix.sector->HotFixStamp[2] = 'T'; + lpart->hotfix.sector->HotFixStamp[3] = 'F'; + lpart->hotfix.sector->HotFixStamp[4] = 'I'; + lpart->hotfix.sector->HotFixStamp[5] = 'X'; + lpart->hotfix.sector->HotFixStamp[6] = '0'; + lpart->hotfix.sector->HotFixStamp[7] = '0'; + + lpart->hotfix.sector->PartitionID = nwvp_create_new_id(); + lpart->hotfix.sector->HotFixFlags = 0x00010000; + lpart->hotfix.sector->HotFixDateStamp = 0x0703f808; + lpart->hotfix.sector->HotFixTotalSectors = lpart->logical_block_count * lpart->sectors_per_block; + lpart->hotfix.sector->HotFixSize = lpart->hotfix.block_count * lpart->sectors_per_block; + + for (i=0; i<20; i++) + { + lpart->hotfix.hotfix_table[0][i] = 0xFFFFFFFF; + lpart->hotfix.bad_bit_table[0][i] = 0xFFFFFFFF; + } + for (i=0; ihotfix.block_count; i+= 0x400) + { + index = 20 + ((i >> 10) << 5); + for (j=0; j<4; j++, index+=8) + { + lpart->hotfix.hotfix_table[index >> 10][index & 0x3FF] = 0xFFFFFFFF; + lpart->hotfix.bad_bit_table[index >> 10][index & 0x3FF] = 0xFFFFFFFF; + } + lpart->hotfix.sector->HotFixTable[i >> 10].HotFix1 = (index - 0x20) * 8; + lpart->hotfix.sector->HotFixTable[i >> 10].BadBlock1 = (index - 0x18) * 8; + lpart->hotfix.sector->HotFixTable[i >> 10].HotFix2 = (index - 0x10) * 8; + lpart->hotfix.sector->HotFixTable[i >> 10].BadBlock2 = (index - 0x08) * 8; + nwvp_hotfix_tables_flush(lpart, i); + } + + nwvp_memmove(&lpart->mirror_sector->nwvp_mirror_stamp[0], "NWVP MIRROR 0001", 16); + lpart->mirror_sector->mirror_id = nwvp_create_new_id(); + lpart->mirror_sector->time_stamp = nwvp_get_date_and_time(); + lpart->mirror_sector->log[0].partition_id = lpart->hotfix.sector->PartitionID; + lpart->mirror_link = lpart; + lpart->primary_link = lpart; + lpart->mirror_status = MIRROR_PRESENT_BIT | MIRROR_INSYNCH_BIT; + lpart->mirror_partition_id = lpart->hotfix.sector->PartitionID; + lpart->mirror_group_id = lpart->mirror_sector->mirror_id; + nwvp_segment_sectors_zap(lpart); + nwvp_netware_mirror_update(lpart, 0); + nwvp_master_sectors_flush(lpart); + return(0); +} + +ULONG nwvp_hotfix_block_lookup( + nwvp_lpart *lpart, + ULONG block_number, + ULONG *relative_block_number, + ULONG *bad_bits) +{ + ULONG i; + ULONG *table; + + for (i=0; ihotfix.block_count; i++) + { + if ((table = lpart->hotfix.hotfix_table[i >> 10]) != 0) + { + if (table[i & 0x3FF] == (block_number * 8)) + { + *relative_block_number = i; + *bad_bits = lpart->hotfix.bad_bit_table[i >> 10][i & 0x3FF]; + return(0); + } + } + } + return(-1); +} + + +ULONG nwvp_hotfix_block( + nwvp_lpart *original_part, + ULONG original_block_number, + BYTE *original_buffer, + ULONG *original_bad_bits, + ULONG control_flag) +{ + ULONG i; + ULONG index; + ULONG error_count; + ULONG data_found_flag; + ULONG multi_sector_count; + ULONG bytes; + ULONG bad_bits = 0; + ULONG relative_block_number = 0; + nwvp_lpart *lpart; + + lpart = original_part; + NWLockHOTFIX(); + +// +// retry original operation to prevent concurrent access of a single +// block to cause multiple hotfixes. +// + + bad_bits = (control_flag == NWVP_HOTFIX_FORCE_BAD) ? 0xFFFFFFFF : 0; + + if ((control_flag == NWVP_HOTFIX_READ) || (control_flag == NWVP_HOTFIX_FORCE_BAD)) + { + if (lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] & (1 << (original_block_number & 0x1F))) + nwvp_hotfix_block_lookup(lpart, original_block_number, &relative_block_number, &bad_bits); + else + relative_block_number = original_block_number + lpart->hotfix.block_count; + + if (nwvp_part_read( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + lpart->sectors_per_block, + original_buffer) == 0) + { + *original_bad_bits = bad_bits; + NWUnlockHOTFIX(); + return(0); + } + } + if (control_flag == NWVP_HOTFIX_WRITE) + { + if (lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] & (1 << (original_block_number & 0x1F))) + nwvp_hotfix_block_lookup(lpart, original_block_number, &relative_block_number, &bad_bits); + else + relative_block_number = original_block_number + lpart->hotfix.block_count; + if (nwvp_part_write( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + lpart->sectors_per_block, + original_buffer) == 0) + { + *original_bad_bits |= bad_bits; + NWUnlockHOTFIX(); + return(0); + } + } + +// +// try to read from block 0, to detect device failure +// + if ((control_flag == NWVP_HOTFIX_READ) || (control_flag == NWVP_HOTFIX_WRITE)) + { + if (nwvp_part_read( + lpart->rpart_handle, + 0, + lpart->sectors_per_block, + bit_bucket_buffer) != 0) + { + nwvp_log(NWLOG_DEVICE_OFFLINE, lpart->lpartition_handle, lpart->rpart_handle, 0); + lpart->rpart_handle = 0xFFFFFFFF; + lpart->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + if (nwvp_mirror_group_update(lpart->primary_link) != 0) + { + nwvp_mirror_group_delete(lpart->primary_link); + } + NWUnlockHOTFIX(); + return(-1); + } + } +// +// try to recover data on read operation from mirrors +// + if ((control_flag == NWVP_HOTFIX_READ) || (control_flag == NWVP_HOTFIX_FORCE)) + { + lpart = original_part->mirror_link; + data_found_flag = 0; + while (lpart != original_part) + { + if ((((lpart->mirror_status & MIRROR_INSYNCH_BIT) != 0) && + ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0)) || + (lpart->remirror_section < (original_block_number >> 10))) + { + bad_bits = 0; + if (lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] & (1 << (original_block_number & 0x1F))) + nwvp_hotfix_block_lookup(lpart, original_block_number, &relative_block_number, &bad_bits); + else + relative_block_number = original_block_number + lpart->hotfix.block_count; + if (bad_bits == 0) + { + if (nwvp_part_read( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + lpart->sectors_per_block, + original_buffer) == 0) + { + data_found_flag = 1; + break; + } + } + } + lpart = lpart->mirror_link; + } + if (data_found_flag == 0) + { +// +// otherwise retry one sector at a time. +// + bad_bits = 0; + if (lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] & (1 << (original_block_number & 0x1F))) + nwvp_hotfix_block_lookup(lpart, original_block_number, &relative_block_number, &bad_bits); + else + relative_block_number = original_block_number + lpart->hotfix.block_count; + multi_sector_count = LogicalBlockSize / 512; + for (bytes = 0, i=0; i<8; i+=multi_sector_count, bytes += (512 * multi_sector_count)) + { + if (nwvp_part_read( + lpart->rpart_handle, + (relative_block_number * lpart->sectors_per_block) + i, + multi_sector_count, + &original_buffer[bytes]) != 0) + { + bad_bits |= (~(0xFFFFFFFF << multi_sector_count)) << i; + } + } + } + } + +// +// now that we have the data and the bad bits, we can hotfix +// +// first locate a free entry in the table; +// + + lpart = original_part; + index = 0; + relative_block_number = 0xFFFFFFFF; + if (lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] & (1 << (original_block_number & 0x1F))) + { + nwvp_hotfix_block_lookup(original_part, original_block_number, &relative_block_number, &bad_bits); + index = relative_block_number; + lpart->hotfix.hotfix_table[relative_block_number >> 10][relative_block_number & 0x3FF] = 0xFFFFFFFF; + lpart->hotfix.bad_bit_table[relative_block_number >> 10][relative_block_number & 0x3FF] = 0xFFFFFFFF; + } + +// +// write the data to the new location and flush tables +// + + for (error_count = 0; (index < lpart->hotfix.block_count) && (error_count < 5); index ++) + { + if (lpart->hotfix.hotfix_table[index >> 10][index & 0x3FF] == 0) + { + if (((lpart->mirror_status & MIRROR_READ_ONLY_BIT) != 0) || + (nwvp_part_write( + original_part->rpart_handle, + (index * original_part->sectors_per_block), + original_part->sectors_per_block, + &original_buffer[0]) == 0)) + { + lpart->hotfix.hotfix_table[index >> 10][index & 0x3FF] = original_block_number * original_part->sectors_per_block; + lpart->hotfix.bad_bit_table[index >> 10][index & 0x3FF] = bad_bits; + lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] |= (1 << (original_block_number & 0x1F)); + if ((relative_block_number != 0xFFFFFFFF) && ((relative_block_number & 0xFFFFFC00) != (index & 0xFFFFFC00))) + nwvp_hotfix_tables_flush(lpart, relative_block_number); + if (nwvp_hotfix_tables_flush(lpart, index) == 0) + { + *original_bad_bits = bad_bits; + NWUnlockHOTFIX(); + return(0); + } + + nwvp_log(NWLOG_DEVICE_OFFLINE, lpart->lpartition_handle, lpart->rpart_handle, 0); + lpart->rpart_handle = 0xFFFFFFFF; + lpart->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + if (nwvp_mirror_group_update(lpart->primary_link) != 0) + { + nwvp_mirror_group_delete(lpart->primary_link); + } + break; + } + error_count ++; + } + } + NWUnlockHOTFIX(); + return(-1); +} + +ULONG nwvp_hotfix_update_bad_bits( + nwvp_lpart *original_part, + ULONG original_block_number, + ULONG original_bad_bits) +{ + ULONG bad_bits = 0; + ULONG relative_block_number = 0; + nwvp_lpart *lpart; + + lpart = original_part; + + if (lpart->hotfix.bit_table[original_block_number >> 15][(original_block_number >> 5) & 0x3FF] & (1 << (original_block_number & 0x1F))) + { + nwvp_hotfix_block_lookup(original_part, original_block_number, &relative_block_number, &bad_bits); + lpart->hotfix.bad_bit_table[relative_block_number >> 10][relative_block_number & 0x3FF] = original_bad_bits; + return(nwvp_hotfix_tables_flush(lpart, relative_block_number)); + } + return(-1); +} + +ULONG nwvp_stop_remirror( + nwvp_lpart *lpart) +{ + nwvp_remirror_control *control; + + if ((lpart->mirror_status & MIRROR_GROUP_REMIRRORING_BIT) != 0) + { + if ((control = nwvp_remirror_control_list_head) != 0) + { + + do + { + if (control->lpart_handle == lpart->lpartition_handle) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint("quiesing control %08X\n", (int) control); +#endif + control->abort_flag = 0xFFFFFFFF; + nwvp_log(NWLOG_REMIRROR_STOP, lpart->lpartition_handle, 0, 0); + if (nwvp_remirror_message_flag != 0) + NWFSPrint("Partition %d Remirroring Stopped\n", (int) (lpart->lpartition_handle & 0x0000FFFF)); + return(0); + } + control = control->next_link; + } while (control != nwvp_remirror_control_list_head); + } + } + nwvp_log(NWLOG_REMIRROR_STOP_ERROR, lpart->lpartition_handle, 0, 0); + return(-1); +} + +ULONG nwvp_start_remirror( + nwvp_lpart *lpart) +{ +#if (LINUX_20 | LINUX_22 | LINUX_24) + extern void NWFSStartRemirror(void); +#endif + nwvp_lpart *temp; + nwvp_remirror_control *control, *head; + + nwvp_alloc((void **) &control, sizeof(nwvp_remirror_control)); +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" Allocated remirror control structure %08X\n", (int) control); +#endif + + if (((lpart->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0) && + ((lpart->mirror_status & MIRROR_GROUP_READ_ONLY_BIT) == 0)) + { + if ((lpart->mirror_status & MIRROR_GROUP_REMIRRORING_BIT) == 0) + { + lpart->mirror_status |= MIRROR_GROUP_REMIRRORING_BIT; + nwvp_mirror_group_open(lpart); + + temp = lpart; + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (temp->remirror_section == 0xFFFFFFFF) + temp->remirror_section = (lpart->logical_block_count >> 10) + 1; + temp->mirror_status |= MIRROR_REMIRRORING_BIT; + } + temp = temp->mirror_link; + } while (temp != lpart); + + nwvp_memset(control, 0, sizeof(nwvp_remirror_control)); + control->lpart_handle = lpart->lpartition_handle; + control->section = (lpart->logical_block_count >> 10); + control->original_section = control->section; + control->state = NWVP_VALIDATE_PHASE; + if ((head = nwvp_remirror_control_list_head) == 0) + { + control->next_link = control; + control->last_link = control; + nwvp_remirror_control_list_head = control; + } + else + { + control->last_link = head->last_link; + control->next_link = head; + head->last_link->next_link = control; + head->last_link = control; + } + nwvp_log(NWLOG_REMIRROR_START, lpart->lpartition_handle, 0, 0); + if (nwvp_remirror_message_flag != 0) + { + if (lpart->mirror_status & MIRROR_INSYNCH_BIT) + NWFSPrint("Partition %d Improperly Shutdown, Validating Mirrors.\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + else + NWFSPrint("Partition %d Remirroring Start\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + } + +#if (LINUX_20 | LINUX_22 | LINUX_24) + NWFSStartRemirror(); +#else + NWUnlockREMIRROR(); +#endif + return(0); + } + } +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" Allocated remirror return %08X\n", (int) control); +#endif + nwvp_free(control); + nwvp_log(NWLOG_REMIRROR_START_ERROR, lpart->lpartition_handle, 0, 0); + return(-1); +} + +void nwvp_quiese_remirroring(void) +{ + ULONG i; + + NWLockNWVP(); + for (i=0; iremirror_section = 0xFFFFFFFF; + temp->lpartition_handle = lpart->lpartition_handle; + temp->mirror_partition_id = partition_id; + temp->mirror_group_id = group_id; + temp->primary_link = lpart; + temp->mirror_link = lpart->mirror_link; + lpart->mirror_link = temp; + temp->mirror_sector_index = mirror_sector_index; + + for (j=0; jrpartition_handle = ((handle_instance ++) << 16) + j; + break; + } + } + if ((j == raw_partition_table_count) && (j < MAX_PARTITIONS)) + { + raw_partition_table[j] = temp; + temp->rpartition_handle = ((handle_instance ++) << 16) + j; + raw_partition_table_count ++; + return(0); + } + return(-1); +} + +void nwvp_mirror_group_establish( + nwvp_lpart *lpart, + ULONG hard_activate_flag) +{ + ULONG i; + ULONG mirror_count; + ULONG found_flag; + ULONG modify_check_flag = 0; + ULONG complete_flag = 1; + ULONG active_flag = 0; + ULONG NetWareFlag = 0; + ULONG open_flag = 0; + ULONG part_index; + ULONG base_instance; + ULONG remirror_flag = 0; + nwvp_lpart *temp; + nwvp_lpart *temp2; + nwvp_mirror_sector base_sector; + + part_index = lpart->lpartition_handle & 0x0000FFFF; + if ((lpart->primary_link->mirror_status & MIRROR_GROUP_ESTABLISHED_BIT) != 0) + { + if ((lpart->mirror_status & MIRROR_NEW_BIT) != 0) + { + lpart->mirror_status &= ~MIRROR_NEW_BIT; + lpart->mirror_status |= MIRROR_PRESENT_BIT; + nwvp_memmove(lpart->mirror_sector, lpart->primary_link->mirror_sector, 512); + nwvp_netware_mirror_update(lpart, 1); + } + else + { + lpart->mirror_status |= MIRROR_PRESENT_BIT; + nwvp_memmove(lpart->mirror_sector, lpart->primary_link->mirror_sector, 512); + nwvp_netware_mirror_update(lpart, 1); + } + temp = lpart->primary_link; + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if ((temp->mirror_status & MIRROR_INSYNCH_BIT) != 0) + active_flag = 1; + else + remirror_flag = 1; + } + temp = temp->mirror_link; + } while (temp != lpart->primary_link); + + if (((lpart->primary_link->mirror_status & MIRROR_GROUP_ACTIVE_BIT) == 0) && + (active_flag != 0)) + { + temp->mirror_status |= MIRROR_GROUP_ACTIVE_BIT | MIRROR_GROUP_ESTABLISHED_BIT; + nwvp_segmentation_sectors_load(temp); + nwvp_segmentation_add(temp); + } + + if ((lpart->primary_link->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0) + { + if ((remirror_flag != 0) && (nwvp_auto_remirror_flag != 0)) + nwvp_start_remirror(logical_partition_table[part_index]); + } + return; + } + + if ((lpart->mirror_status & MIRROR_NEW_BIT) != 0) + { + lpart->mirror_status &= ~MIRROR_NEW_BIT; + lpart->mirror_status |= MIRROR_PRESENT_BIT; + } + +// +// find out if the group is complete; +// + + temp = lpart->primary_link; + do + { + if ((nwvp_memcomp(&temp->mirror_sector->nwvp_mirror_stamp[0], "NWVP MIRROR 0001", 16) != 0) || + (temp->netware_mirror_sector->MirrorGroupID != temp->mirror_sector->mirror_id) || + (((temp->netware_mirror_sector->MirrorFlags & 0xFFFF0000) != NETWARE_IN_SYNCH_INSTANCE) && + ((temp->netware_mirror_sector->MirrorFlags & 0xFFFF0000) != NETWARE_OUT_OF_SYNCH_INSTANCE))) + NetWareFlag = 1; + + for (i=0; i<8; i++) + { + if (temp->netware_mirror_sector->MirrorMemberID[i] == 0) + break; + found_flag = 0; + temp2 = lpart->primary_link; + do + { + if (temp->netware_mirror_sector->MirrorMemberID[i] == temp2->mirror_partition_id) + { + found_flag = 1; + break; + } + temp2 = temp2->mirror_link; + } while (temp2 != lpart->primary_link); + if (found_flag == 0) + { + complete_flag = 0; + } + } + temp = temp->mirror_link; + } while (temp != logical_partition_table[part_index]); + +// +// +// + + if ((complete_flag != 0) && (lpart->mirror_link == lpart)) + { + nwvp_log(NWLOG_DEVICE_INSYNCH, lpart->lpartition_handle, lpart->rpart_handle, 0); + lpart->mirror_status |= MIRROR_INSYNCH_BIT; + lpart->primary_link = lpart; + lpart->mirror_count = 1; + lpart->remirror_section = 0; + active_flag = 1; + if ((lpart->mirror_status & MIRROR_READ_ONLY_BIT) != 0) + lpart->mirror_status |= MIRROR_GROUP_READ_ONLY_BIT; + } + else + { + if ((hard_activate_flag != 0) || (complete_flag != 0)) + { +// +// here is where we establish the mirror and synch state of all members +// + if (NetWareFlag == 0) + { + temp = logical_partition_table[part_index]; + base_instance = 0; + do + { + if (temp->mirror_sector->time_stamp > base_instance) + { + base_instance = temp->mirror_sector->time_stamp; + nwvp_memmove(&base_sector, temp->mirror_sector, 512); + } + temp = temp->mirror_link; + } while (temp != lpart->primary_link); + } + else + { + nwvp_memset(&base_sector, 0, 512); + nwvp_memmove(&base_sector.nwvp_mirror_stamp[0], "NWVP MIRROR 0001", 16); + temp = logical_partition_table[part_index]; + active_flag = 0; + temp2 = 0; + base_instance = 0; + do + { + if (temp->netware_mirror_sector->MirrorGroupID > base_instance) + { + base_instance = temp->netware_mirror_sector->MirrorGroupID; + temp2 = temp; + } + temp = temp->mirror_link; + } while (temp != lpart->primary_link); + + base_sector.mirror_id = temp2->netware_mirror_sector->MirrorGroupID; + for (i=0; i<8; i++) + { + if (temp2->netware_mirror_sector->MirrorMemberID[i] == 0) + break; + temp2->mirror_count = 0; + + base_sector.log[i].partition_id = temp2->netware_mirror_sector->MirrorMemberID[i]; + base_sector.log[i].time_stamp = 0; + base_sector.log[i].remirror_section = 0; + if ((temp2->netware_mirror_sector->MirrorStatus & (1 << i)) != 0) + base_sector.log[i].remirror_section = 0xFFFFFFFF; + base_sector.log[i].status = NWVP_MIRROR_STATUS_CLOSED; + if ((temp2->netware_mirror_sector->MirrorFlags & NETWARE_INUSE_BIT) != 0) + base_sector.log[i].status = NWVP_MIRROR_STATUS_OPENED; + } + } + +// +// set mirror index and look for absent partitions +// + mirror_count = 0; + for (i=0; i<30; i++) + { + if ((base_sector.log[i].partition_id != 0) && + (base_sector.log[i].status != NWVP_MIRROR_STATUS_REMOVED)) + { + mirror_count ++; + temp = logical_partition_table[part_index]; + if ((base_sector.log[i].status == NWVP_MIRROR_STATUS_OPENED) || + (base_sector.log[i].status == NWVP_MIRROR_STATUS_CHECK)) + { + base_sector.log[i].status = NWVP_MIRROR_STATUS_CHECK; + open_flag = 1; + } + found_flag = 0; + do + { + if (temp->mirror_partition_id == base_sector.log[i].partition_id) + { + temp->remirror_section = base_sector.log[i].remirror_section; + temp->mirror_sector_index = i; + found_flag = 1; + break; + } + temp = temp->mirror_link; + } while (temp != lpart->primary_link); + if (found_flag == 0) + { +// +// create any absent partitions +// + nwvp_mirror_create_entry(logical_partition_table[part_index], i, base_sector.log[i].partition_id, base_sector.mirror_id); + if (base_sector.log[i].remirror_section != 0xFFFFFFFF) + modify_check_flag = 1; + } + } + } +// +// bases upon the previous evaluation, set correctly set the mirror state of each partition +// + + temp = logical_partition_table[part_index]; + do + { + if ((temp->remirror_section = base_sector.log[temp->mirror_sector_index].remirror_section) == 0) + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + nwvp_log(NWLOG_DEVICE_INSYNCH, temp->lpartition_handle, temp->rpart_handle, 0); + temp->mirror_status |= MIRROR_INSYNCH_BIT; + if (open_flag > 0) + { + temp->mirror_status |= MIRROR_GROUP_CHECK_BIT; + if (open_flag != 1) + temp->remirror_section = 0xFFFFFFFF; + open_flag ++; + } + active_flag = 1; + } + } + else + { + nwvp_log(NWLOG_DEVICE_OUT_OF_SYNCH, temp->lpartition_handle, temp->rpart_handle, 0); + } + temp->mirror_count = mirror_count; + temp = temp->mirror_link; + } while (temp != logical_partition_table[part_index]); + +// +// if a valid partition exist flush established tables +// + if (active_flag != 0) + { + base_sector.time_stamp = nwvp_get_date_and_time(); + temp = logical_partition_table[part_index]; + do + { + if (temp->mirror_sector != 0) + { + nwvp_memmove(temp->mirror_sector, &base_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + temp = temp->mirror_link; + } while (temp != logical_partition_table[part_index]); + + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if ((temp->mirror_status & MIRROR_READ_ONLY_BIT) != 0) + logical_partition_table[part_index]->mirror_status |= MIRROR_GROUP_READ_ONLY_BIT; + if (temp->remirror_section != 0) + remirror_flag = 1; + nwvp_netware_mirror_update(temp, 1); + } + temp = temp->mirror_link; + } while (temp != logical_partition_table[part_index]); + + } + } + } +// +// evaluate logical partition for volume segments +// + if (active_flag != 0) + { + if (modify_check_flag != 0) + temp->mirror_status |= MIRROR_GROUP_MODIFY_CHECK_BIT; + + temp->mirror_status |= MIRROR_GROUP_ACTIVE_BIT | MIRROR_GROUP_ESTABLISHED_BIT; + nwvp_segmentation_sectors_load(temp); + nwvp_segmentation_add(temp); + + if ((remirror_flag != 0) && (nwvp_auto_remirror_flag != 0)) + nwvp_start_remirror(logical_partition_table[part_index]); + } +} + +ULONG nwvp_mirror_group_modify_check( + nwvp_lpart *lpart) +{ + ULONG found_flag = 0; + nwvp_lpart *temp; + + if ((lpart->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0) + { + if ((lpart->mirror_status & MIRROR_GROUP_MODIFY_CHECK_BIT) != 0) + { + temp = lpart; + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) == 0) + { + lpart->mirror_sector->log[temp->mirror_sector_index].remirror_section = 0xFFFFFFFF; + nwvp_log(NWLOG_DEVICE_OUT_OF_SYNCH, temp->lpartition_handle, temp->rpart_handle, temp->remirror_section); + temp->remirror_section = 0xFFFFFFFF; + temp->mirror_status &= ~MIRROR_INSYNCH_BIT; + found_flag = 1; + } + temp = temp->mirror_link; + } while (temp != lpart); + + if (found_flag != 0) + { + lpart->mirror_sector->time_stamp = nwvp_get_date_and_time(); + temp = lpart; + do + { + if ((temp->mirror_sector != 0) && (lpart != temp)) + { + nwvp_memmove(temp->mirror_sector, lpart->mirror_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + temp = temp->mirror_link; + } while (temp != lpart); + + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_netware_mirror_update(temp, 1); + temp = temp->mirror_link; + } while (temp != lpart); + } + } + lpart->mirror_status &= ~MIRROR_GROUP_MODIFY_CHECK_BIT; + return(0); + } + lpart->mirror_status &= ~MIRROR_GROUP_MODIFY_CHECK_BIT; + return(-1); +} + +ULONG nwvp_mirror_group_remirror_check( + nwvp_lpart *lpart, + ULONG section, + ULONG *reset_flag) +{ + ULONG alive_count = 0; + nwvp_lpart *temp; + + temp = lpart; + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if ((temp->mirror_status & MIRROR_REMIRRORING_BIT) == 0) + { + if (temp->remirror_section == 0xFFFFFFFF) + temp->remirror_section = (lpart->logical_block_count >> 10) + 1; + temp->mirror_status |= MIRROR_REMIRRORING_BIT; + nwvp_log(NWLOG_REMIRROR_RESET1, lpart->lpartition_handle, temp->rpart_handle, section); + *reset_flag = 0xFFFFFFFF; + return(0); + } + alive_count ++; + if (temp->remirror_section >= section + 1) + { + if (temp->remirror_section != (section + 1)) + { + nwvp_log(NWLOG_REMIRROR_RESET2, lpart->lpartition_handle, temp->rpart_handle, section); + *reset_flag = 0xFFFFFFFF; + return(0); + } + } + } + temp = temp->mirror_link; + } while (temp != lpart); + return((alive_count > 1) ? 0 : 0xFFFFFFFF); +} + +ULONG nwvp_mirror_group_remirror_update( + ULONG lpart_handle, + ULONG section, + ULONG *reset_flag) +{ + nwvp_lpart *lpart; + nwvp_lpart *temp; + + *reset_flag = 0; + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle)) + { + temp = lpart; + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (temp->remirror_section >= section + 1) + { + if (temp->remirror_section != (section + 1)) + { + *reset_flag = 0xFFFFFFFF; + nwvp_log(NWLOG_REMIRROR_RESET3, lpart->lpartition_handle, temp->rpart_handle, section); + NWUnlockNWVP(); + if (nwvp_remirror_message_flag != 0) + { + if (lpart->mirror_status & MIRROR_INSYNCH_BIT) + NWFSPrint("Partition %d Validate Reset\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + else + NWFSPrint("Partition %d Remirroring Reset\n", + (int)(lpart->lpartition_handle & 0x0000FFFF)); + } + return(0); + } + temp->remirror_section = section; + lpart->mirror_sector->log[temp->mirror_sector_index].remirror_section = section; + } + } + temp = temp->mirror_link; + } while (temp != lpart); + if (section == 0) + { + temp = lpart; + do + { + if (((temp->mirror_status & MIRROR_INSYNCH_BIT) == 0) && ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0)) + { + nwvp_log(NWLOG_DEVICE_INSYNCH, temp->lpartition_handle, temp->rpart_handle, 0); + temp->mirror_status |= MIRROR_INSYNCH_BIT; + temp->remirror_section = section; + lpart->mirror_sector->log[temp->mirror_sector_index].remirror_section = section; + lpart->mirror_sector->log[temp->mirror_sector_index].status = NWVP_MIRROR_STATUS_CLOSED; + if ((lpart->mirror_status & MIRROR_GROUP_OPEN_BIT) != 0) + lpart->mirror_sector->log[temp->mirror_sector_index].status = NWVP_MIRROR_STATUS_OPENED; + } + temp = temp->mirror_link; + } while (temp != lpart); + + lpart->mirror_sector->time_stamp = nwvp_get_date_and_time(); + temp = lpart; + do + { + if (temp->mirror_sector != 0) + { + nwvp_memmove(temp->mirror_sector, lpart->mirror_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + temp = temp->mirror_link; + } while (temp != lpart); + + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_netware_mirror_update(temp, 1); + temp = temp->mirror_link; + } while (temp != lpart); + if (nwvp_remirror_message_flag != 0) + { + if (lpart->mirror_status & MIRROR_INSYNCH_BIT) + NWFSPrint("Partition %d Validate (100%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + else + NWFSPrint("Partition %d Remirroring (100%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + } + } + else + { + + if (nwvp_remirror_message_flag != 0) + { + if ((((lpart->logical_block_count >> 10) / 4) * 3) == section) + { + if (lpart->mirror_status & MIRROR_INSYNCH_BIT) + NWFSPrint("Partition %d Validate (25%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + else + NWFSPrint("Partition %d Remirroring (25%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + } + else + if ((((lpart->logical_block_count >> 10) / 4) * 2) == section) + { + if (lpart->mirror_status & MIRROR_INSYNCH_BIT) + NWFSPrint("Partition %d Validate (50%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + else + NWFSPrint("Partition %d Remirroring (50%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + } + else + if ((((lpart->logical_block_count >> 10) / 4) * 1) == section) + { + if (lpart->mirror_status & MIRROR_INSYNCH_BIT) + NWFSPrint("Partition %d Validate (75%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + else + NWFSPrint("Partition %d Remirroring (75%% Complete)\n", + (int) (lpart->lpartition_handle & 0x0000FFFF)); + } + } + } + } + } + NWUnlockNWVP(); + return(0); +} + +ULONG nwvp_mirror_group_add( + nwvp_lpart *lpart) +{ + ULONG j; + nwvp_lpart *base_part; + + for (j=0; jmirror_group_id == lpart->mirror_group_id) + { + lpart->lpartition_handle = base_part->lpartition_handle; + lpart->primary_link = base_part; + lpart->mirror_link = base_part->mirror_link; + lpart->mirror_count = base_part->mirror_count; + base_part->mirror_link = lpart; + nwvp_mirror_group_establish(base_part, 0); + return(0); + } + } + } + + for (j=0; jlpartition_handle = (handle_instance ++ << 16) + j; + logical_partition_table[j] = lpart; + break; + } + } + if (j >= MAX_PARTITIONS) + return(0); + if (j == logical_partition_table_count) + { + lpart->lpartition_handle = (handle_instance ++ << 16) + j; + logical_partition_table[j] = lpart; + logical_partition_table_count ++; + } + lpart->primary_link = lpart; + lpart->mirror_link = lpart; + lpart->mirror_count = 1; + return(0); +} + +void nwvp_mirror_group_delete( + nwvp_lpart *member) +{ + nwvp_lpart *temp; + + while ((temp = member->mirror_link) != member) + { + member->mirror_link = temp->mirror_link; + nwvp_hotfix_tables_free(temp); + if (temp->mirror_sector != 0) + { + nwvp_free(temp->mirror_sector); + temp->mirror_sector = 0; + } + if (temp->netware_mirror_sector != 0) + { + nwvp_free(temp->netware_mirror_sector); + temp->netware_mirror_sector = 0; + } + raw_partition_table[temp->rpartition_handle & 0x0000FFFF] = 0; + nwvp_free(temp); + } + nwvp_hotfix_tables_free(temp); + if (temp->mirror_sector != 0) + { + nwvp_free(temp->mirror_sector); + temp->mirror_sector = 0; + } + if (temp->netware_mirror_sector != 0) + { + nwvp_free(temp->netware_mirror_sector); + temp->netware_mirror_sector = 0; + } + raw_partition_table[temp->rpartition_handle & 0x0000FFFF] = 0; + logical_partition_table[temp->lpartition_handle & 0x0000FFFF] = 0; + nwvp_free(temp); +} + +ULONG nwvp_mirror_group_update( + nwvp_lpart *member) +{ + ULONG present_flag = 1; + ULONG found_flag = 0; + nwvp_lpart *temp; + nwvp_lpart *temp2; + + temp = member->primary_link; + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if ((temp->mirror_status & MIRROR_INSYNCH_BIT) != 0) + { + if (temp->remirror_section == 0) + found_flag = 0xFFFFFFFF; + else + { + if (found_flag == 0) + { + temp2 = temp; + do + { + if (((temp2->mirror_status & MIRROR_INSYNCH_BIT) != 0) && + (temp2->remirror_section == 0)) + { + found_flag = 0xFFFFFFFF; + break; + } + temp2 = temp2->mirror_link; + } while (temp2 != member->primary_link); + if (found_flag == 0) + { + temp->remirror_section = 0; + found_flag = 0xFFFFFFFF; + } + } + } + } + present_flag = 0; + } + else + { + member->primary_link->mirror_status |= MIRROR_GROUP_MODIFY_CHECK_BIT; + } + temp = temp->mirror_link; + } while (temp != member->primary_link); + + if (found_flag == 0) + { + if ((member->primary_link->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0) + { + member->primary_link->mirror_status &= ~MIRROR_GROUP_ACTIVE_BIT; + nwvp_segmentation_remove(temp); + } + } + return(present_flag); +} + + +ULONG nwvp_mirror_member_add( + nwvp_lpart *mpart, + nwvp_lpart *new_part) +{ + ULONG i; + ULONG remirror_flag = 0; + nwvp_lpart *temp; + nwvp_mirror_sector base_sector; + + nwvp_memmove(&base_sector, mpart->mirror_sector, 512); + + for (i=0; i<30; i++) + { + if (base_sector.log[i].partition_id == 0) + break; + } + if (i != 30) + { + base_sector.log[i].partition_id = new_part->mirror_partition_id; + base_sector.log[i].status = NWVP_MIRROR_STATUS_CLOSED; + if ((mpart->mirror_status & MIRROR_GROUP_CHECK_BIT) != 0) + base_sector.log[i].status = NWVP_MIRROR_STATUS_CHECK; + if ((mpart->mirror_status & MIRROR_GROUP_OPEN_BIT) != 0) + base_sector.log[i].status = NWVP_MIRROR_STATUS_OPENED; + new_part->mirror_sector_index = i; + if (i >= mpart->mirror_count) + mpart->mirror_count = i+1; + new_part->mirror_link = mpart->mirror_link; + new_part->mirror_group_id = mpart->mirror_group_id; + mpart->mirror_link = new_part; + new_part->primary_link = mpart; + if (mpart->segment_sector->NumberOfTableEntries == 0) + { + nwvp_log(NWLOG_DEVICE_INSYNCH, new_part->lpartition_handle, new_part->rpart_handle, 0); + new_part->mirror_status |= MIRROR_INSYNCH_BIT; + base_sector.log[i].remirror_section = 0; + } + else + { + nwvp_log(NWLOG_DEVICE_OUT_OF_SYNCH, new_part->lpartition_handle, new_part->rpart_handle, 0); + new_part->mirror_status &= ~MIRROR_INSYNCH_BIT; + base_sector.log[i].remirror_section = 0xFFFFFFFF; + remirror_flag = 1; + } + base_sector.time_stamp = nwvp_get_date_and_time(); + temp = mpart; + do + { + temp->mirror_count = mpart->mirror_count; + if (temp->mirror_sector != 0) + { + nwvp_memmove(temp->mirror_sector, &base_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + temp = temp->mirror_link; + } while (temp != mpart); + + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_netware_mirror_update(temp, 1); + temp = temp->mirror_link; + } while (temp != mpart); + + if ((remirror_flag != 0) && (nwvp_auto_remirror_flag != 0)) + { + nwvp_start_remirror(mpart); + } + + return(0); + } + return(-1); +} + +void nwvp_mirror_partition_destroy( + nwvp_lpart *del_part, + nwvp_lpart **new_primary) +{ + nwvp_lpart *temp; + nwvp_lpart *primary_part; + + if ((primary_part = del_part->primary_link) == del_part) + { + primary_part = del_part->mirror_link; + temp = del_part->mirror_link; + while (1) + { + temp->primary_link = primary_part; + if (temp->mirror_link == del_part) + { + temp->mirror_link = primary_part; + break; + } + temp = temp->mirror_link; + } + primary_part->mirror_count = del_part->mirror_count; + primary_part->mirror_status |= del_part->mirror_status & 0xFFFF0000; + logical_partition_table[primary_part->lpartition_handle & 0x0000FFFF] = primary_part; + nwvp_memmove(primary_part->segment_sector, del_part->segment_sector, 512); + vpartition_update_lpartition(del_part, primary_part); + } + else + { + temp = primary_part; + while (temp->mirror_link != del_part) + temp = temp->mirror_link; + temp->mirror_link = del_part->mirror_link; + } + nwvp_hotfix_tables_free(del_part); + if (del_part->mirror_sector != 0) + { + nwvp_free(del_part->mirror_sector); + del_part->mirror_sector = 0; + } + if (del_part->netware_mirror_sector != 0) + { + nwvp_free(del_part->netware_mirror_sector); + del_part->netware_mirror_sector = 0; + } + nwvp_free(del_part); + *new_primary = primary_part; +} + +ULONG nwvp_mirror_member_delete( + nwvp_lpart *del_part) +{ + ULONG i; + ULONG base_index; + nwvp_lpart *temp, *primary_part; + nwvp_mirror_sector base_sector; + + primary_part = del_part->primary_link; + nwvp_memmove(&base_sector, primary_part->mirror_sector, 512); + + for (i=0; imirror_count; i++) + { + if (base_sector.log[i].partition_id == del_part->mirror_partition_id) + { + base_index = i; + for (; i<30; i++) + { + nwvp_memmove(&base_sector.log[i], &base_sector.log[i+1], 16); + if (base_sector.log[i+1].partition_id == 0) + break; + } + primary_part->mirror_count --; + + if ((del_part->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_hotfix_sectors_zap(del_part); + else + { + for (i=30; i>0; i++) + { + if (base_sector.log[i-1].partition_id == 0) + { + del_part->mirror_sector_index = i-1; + base_sector.log[i-1].partition_id = del_part->mirror_partition_id; + base_sector.log[i-1].status = NWVP_MIRROR_STATUS_REMOVED; + break; + } + } + } + + del_part->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + del_part->mirror_status |= MIRROR_DELETED_BIT; + del_part->rpart_handle = 0xFFFFFFFD; + raw_partition_table[del_part->rpartition_handle & 0x0000FFFF] = 0; + if ((primary_part->mirror_status & MIRROR_GROUP_OPEN_BIT) == 0) + { + nwvp_mirror_partition_destroy(del_part, &primary_part); + } + base_sector.time_stamp = nwvp_get_date_and_time(); + temp = primary_part; + do + { + temp->mirror_count = primary_part->mirror_count; + if (temp->mirror_sector != 0) + { + nwvp_memmove(temp->mirror_sector, &base_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + if (temp->mirror_sector_index > base_index) + temp->mirror_sector_index --; + temp = temp->mirror_link; + } while (temp != primary_part); + + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_netware_mirror_update(temp, 1); + temp = temp->mirror_link; + } while (temp != primary_part); + + if (nwvp_mirror_group_update(temp) != 0) + { + nwvp_mirror_group_delete(temp); + } + return(0); + } + } + return(-1); +} + +ULONG nwvp_mirror_group_open( + nwvp_lpart *lpart) +{ + ULONG i; + ULONG time_stamp; + nwvp_lpart *temp; + + if ((lpart->mirror_status & MIRROR_GROUP_ESTABLISHED_BIT) == 0) + nwvp_mirror_group_establish(lpart, 1); + + if ((lpart->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0) + { + if (lpart->open_count == 0) + { + time_stamp = nwvp_get_date_and_time(); + lpart->mirror_sector->time_stamp = time_stamp; + for (i=0; imirror_count; i++) + { + if (lpart->mirror_sector->log[i].partition_id != 0) + { + lpart->mirror_sector->log[i].time_stamp = time_stamp; + lpart->mirror_sector->log[i].status = NWVP_MIRROR_STATUS_OPENED; + } + } + temp = lpart; + lpart->mirror_status |= MIRROR_GROUP_OPEN_BIT; + do + { + if ((temp != lpart) && (temp->mirror_sector != 0)) + { + nwvp_memmove(temp->mirror_sector, lpart->mirror_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + temp = temp->mirror_link; + } while (temp != lpart); + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_netware_mirror_update(temp, 1); + temp = temp->mirror_link; + } while (temp != lpart); + } + lpart->open_count ++; + return(0); + } + return(-1); +} + +ULONG nwvp_mirror_group_close( + nwvp_lpart *lpart) +{ + ULONG i; + ULONG time_stamp; + ULONG done_flag; + nwvp_lpart *temp; + +#if (DEBUG_MIRROR_CONTROL) +NWFSPrint(" MIRROR GROUP CLOSE \n"); +#endif + if (lpart->open_count > 0) + { + lpart->open_count --; + if (lpart->open_count == 0) + { + time_stamp = nwvp_get_date_and_time(); + lpart->mirror_sector->time_stamp = time_stamp; +#if (DEBUG_MIRROR_CONTROL) +NWFSPrint(" UPDATING MIRRORS \n"); +#endif + for (i=0; i < lpart->mirror_count; i++) + { + if (lpart->mirror_sector->log[i].partition_id != 0) + { + lpart->mirror_sector->log[i].time_stamp = time_stamp; + lpart->mirror_sector->log[i].status = NWVP_MIRROR_STATUS_CLOSED; + if ((lpart->mirror_status & MIRROR_GROUP_CHECK_BIT) != 0) + { +#if (DEBUG_MIRROR_CONTROL) +NWFSPrint(" RESETTING CHECK \n"); +#endif + lpart->mirror_sector->log[i].status = NWVP_MIRROR_STATUS_CHECK; + } + } + } + + lpart->mirror_status &= ~MIRROR_GROUP_OPEN_BIT; + done_flag = 0xFFFFFFFF; + while (done_flag != 0) + { + done_flag = 0; + temp = lpart; + do + { + if ((temp->mirror_status & MIRROR_DELETED_BIT) != 0) + { + nwvp_mirror_partition_destroy(temp, &lpart); + done_flag = 0xFFFFFFFF; + break; + } + temp = temp->mirror_link; + } while (temp != lpart); + } + + temp = lpart; + do + { + if ((temp != lpart) && (temp->mirror_sector != 0)) + { + nwvp_memmove(temp->mirror_sector, lpart->mirror_sector, 512); + temp->mirror_sector->table_index = temp->mirror_sector_index; + } + temp = temp->mirror_link; + } while (temp != lpart); + + do + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + nwvp_netware_mirror_update(temp, 1); + temp = temp->mirror_link; + } while (temp != lpart); + + } + return(0); + } + return(-1); +} + + +ULONG nwvp_rpartition_sector_read( + ULONG rpart_handle, + ULONG sector_number, + ULONG sector_count, + BYTE *data_buffer) +{ + ULONG ccode; + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((lpartition = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (lpartition->rpartition_handle == rpart_handle)) + { + ccode = nwvp_part_read(lpartition->rpart_handle, sector_number, sector_count, data_buffer); + NWUnlockNWVP(); + return(ccode); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_rpartition_sector_write( + ULONG rpart_handle, + ULONG sector_number, + ULONG sector_count, + BYTE *data_buffer) +{ + ULONG ccode; + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((lpartition = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (lpartition->rpartition_handle == rpart_handle)) + { + if ((lpartition->mirror_status & MIRROR_READ_ONLY_BIT) == 0) + { + ccode = nwvp_part_write(lpartition->rpart_handle, sector_number, sector_count, data_buffer); + NWUnlockNWVP(); + return(ccode); + } + } + } + NWUnlockNWVP(); + return(-1); +} + + + +ULONG nwvp_lpartition_activate( + ULONG lpart_handle) +{ + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpartition = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpartition->lpartition_handle == lpart_handle)) + { + nwvp_mirror_group_establish(lpartition, 1); + NWUnlockNWVP(); + return(0); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG inwvp_lpartition_specific_read( + nwvp_lpart *lpart, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i; + ULONG bad_bits; + ULONG error_flag = 0; + ULONG relative_block_number; + ULONG hotfixed_flag = 0; + + for (i=0; ihotfix.bit_table[(block_number + i) >> 15][((block_number + i) >> 5) & 0x3FF] & (1 << ((block_number + i) & 0x1F))) + { + hotfixed_flag = 1; + break; + } + } + + relative_block_number = block_number + lpart->hotfix.block_count; + if (hotfixed_flag == 0) + { + if (nwvp_part_read( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + block_count * lpart->sectors_per_block, + data_buffer) == 0) + return(0); + } + + for (i=0; ihotfix.bit_table[(block_number + i) >> 15][((block_number + i) >> 5) & 0x3FF] & (1 << ((block_number + i) & 0x1F))) + nwvp_hotfix_block_lookup(lpart, block_number + i, &relative_block_number, &bad_bits); + else + relative_block_number = block_number + i + lpart->hotfix.block_count; + error_flag |= bad_bits; + if (nwvp_part_read( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + lpart->sectors_per_block, + &data_buffer[4096 * i]) != 0) + { + bad_bits = 0; + if (nwvp_hotfix_block(lpart, block_number + i, &data_buffer[4096 * i], &bad_bits, NWVP_HOTFIX_READ) == 0) + error_flag |= bad_bits; + else + error_flag |= 0xFFFF0000; + } + } + return(error_flag); +} + + +ULONG inwvp_lpartition_block_read( + nwvp_lpart *original_part, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i, count; + nwvp_lpart *lpart; + + + count = (original_part->read_round_robin ++) & 0x3; + for (i=0; i< count; i++) + original_part = original_part->mirror_link; + + lpart = original_part; + do + { + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (((lpart->mirror_status & MIRROR_INSYNCH_BIT) != 0) || + (lpart->remirror_section < (block_number >> 10))) + { + if (inwvp_lpartition_specific_read(lpart, block_number, block_count, data_buffer) == 0) + return(0); + } + } + lpart = lpart->mirror_link; + } while (lpart != original_part); + return(-1); +} + + +ULONG nwvp_lpartition_block_read( + ULONG lpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG ccode; + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpartition = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpartition->lpartition_handle == lpart_handle)) + { + ccode = inwvp_lpartition_block_read(lpartition, block_number, block_count, data_buffer); + NWUnlockNWVP(); + return(ccode); + + } + } + NWUnlockNWVP(); + return(-1); +} + + +ULONG inwvp_lpartition_bad_bit_update( + nwvp_lpart *original_part, + ULONG block_number, + ULONG new_bad_bits) +{ + ULONG success_count = 0; + nwvp_lpart *lpart = original_part; + + if ((lpart->mirror_status & MIRROR_GROUP_READ_ONLY_BIT) != 0) + return(-1); + + do + { + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (nwvp_hotfix_update_bad_bits(lpart, block_number, new_bad_bits) == 0) + success_count ++; + } + lpart = lpart->mirror_link; + } while (lpart != original_part); + + return((success_count == 0) ? -1 : 0); +} + + +ULONG inwvp_lpartition_specific_write( + nwvp_lpart *lpart, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i; + ULONG error_flag = 0; + ULONG bad_bits; + ULONG relative_block_number; + ULONG hotfixed_flag; + + if ((lpart->primary_link->mirror_status & MIRROR_GROUP_MODIFY_CHECK_BIT) != 0) + if (nwvp_mirror_group_modify_check(lpart->primary_link) != 0) + return(-1); + + hotfixed_flag = 0; + for (i=0; ihotfix.bit_table[(block_number + i) >> 15][((block_number + i) >> 5) & 0x3FF] & (1 << ((block_number + i) & 0x1F))) + { + hotfixed_flag = 1; + break; + } + } + + relative_block_number = block_number + lpart->hotfix.block_count; + if (hotfixed_flag == 0) + { + if (nwvp_part_write( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + block_count * lpart->sectors_per_block, + data_buffer) == 0) + return(0); + else + hotfixed_flag = 1; + } + + if (hotfixed_flag != 0) + { + error_flag = 0; + for (i=0; ihotfix.bit_table[(block_number + i) >> 15][((block_number + i) >> 5) & 0x3FF] & (1 << ((block_number + i) & 0x1F))) + nwvp_hotfix_block_lookup(lpart, block_number + i, &relative_block_number, &bad_bits); + else + relative_block_number = block_number + i + lpart->hotfix.block_count; + + if (nwvp_part_write( + lpart->rpart_handle, + relative_block_number * lpart->sectors_per_block, + lpart->sectors_per_block, + &data_buffer[4096 * i]) != 0) + { + if (nwvp_hotfix_block(lpart, block_number + i, &data_buffer[4096 * i], &bad_bits, NWVP_HOTFIX_WRITE) != 0) + error_flag ++; + } + else + { + if (bad_bits != 0) + { + if (nwvp_hotfix_update_bad_bits(lpart, block_number + i, 0) != 0) + error_flag ++; + } + } + } + } + return(error_flag); +} + +ULONG inwvp_lpartition_block_write( + nwvp_lpart *original_part, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG success_count = 0; + nwvp_lpart *lpart = original_part; + + if ((lpart->mirror_status & MIRROR_GROUP_READ_ONLY_BIT) != 0) + return(-1); + + do + { + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (inwvp_lpartition_specific_write(lpart, block_number, block_count, data_buffer) == 0) + success_count ++; + } + lpart = lpart->mirror_link; + } while (lpart != original_part); + + return((success_count == 0) ? -1 : 0); +} + +ULONG nwvp_lpartition_block_write( + ULONG lpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG ccode; + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpartition = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpartition->lpartition_handle == lpart_handle)) + { + ccode = inwvp_lpartition_block_write(lpartition, block_number, block_count, data_buffer); + NWUnlockNWVP(); + return(ccode); + } + } + NWUnlockNWVP(); + return(-1); +} + + +ULONG inwvp_lpartition_block_hotfix( + nwvp_lpart *original_part, + ULONG block_number, + BYTE *data_buffer) +{ + ULONG success_count = 0; + ULONG bad_bits; + nwvp_lpart *lpart = original_part; + + do + { + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (nwvp_hotfix_block(lpart, block_number, data_buffer, &bad_bits, NWVP_HOTFIX_FORCE) == 0) + success_count ++; + } + lpart = lpart->mirror_link; + } while (lpart != original_part); + + return((success_count == 0) ? -1 : 0); +} + + +ULONG nwvp_vpartition_sub_block_read( + ULONG vpart_handle, + ULONG block_number, + ULONG block_offset, + ULONG data_size, + BYTE *data_buffer, + ULONG as) +{ + ULONG i; + ULONG relative_block; + BYTE *temp_buffer; + nwvp_vpartition *vpartition; + + if ((block_offset + data_size) > 4096) + { + NWFSPrint("AHA you dirty dog!!!! passed bad read size!!!\n"); + return -1; + } + + if (nwvp_io_alloc((void **) &temp_buffer, 4096) == 0) + { + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + if (inwvp_lpartition_block_read( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + 1, + temp_buffer) == 0) + { + if (as) + nwvp_memmove(data_buffer, + &temp_buffer[block_offset], data_size); + else + { + if (NWFSCopyToUserSpace(data_buffer, + &temp_buffer[block_offset], data_size)) + { + nwvp_io_free(temp_buffer); + return (-1); + } + } + nwvp_io_free(temp_buffer); + return(0); + } + break; + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + nwvp_io_free(temp_buffer); + } + return(-1); +} + +ULONG inwvp_vpartition_block_read( + nwvp_vpartition *vpartition, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i; + ULONG relative_block; + + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + return (inwvp_lpartition_block_read( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + block_count, + data_buffer)); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + return(-1); +} + +ULONG nwvp_vpartition_map_asynch_read( + ULONG vpart_handle, + ULONG block_number, + ULONG *map_entry_count, + nwvp_asynch_map *map) +{ + ULONG i; + ULONG disk_id; + ULONG disk_offset; + ULONG relative_block; + ULONG hotfix_block; + ULONG map_index = 0; + nwvp_vpartition *vpartition; + nwvp_lpart *lpart; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + lpart = vpartition->segments[i].lpart_link; + do + { + if (((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) && + ((lpart->mirror_status & MIRROR_INSYNCH_BIT) != 0)) + { + if (lpart->hotfix.bit_table[relative_block >> 15][(relative_block >> 5) & 0x3FF] & (1 << (relative_block & 0x1F))) + { + nwvp_part_map_to_physical(lpart->rpart_handle, &disk_id, &disk_offset, 0); + nwvp_hotfix_block_lookup(lpart, relative_block, &hotfix_block, &map[map_index].bad_bits); + map[map_index].sector_offset = (hotfix_block * 8) + disk_offset; + map[map_index].disk_id = disk_id; + map_index ++; + } + else + { + nwvp_part_map_to_physical(lpart->rpart_handle, &disk_id, &disk_offset, 0); + map[map_index].bad_bits = 0; + map[map_index].sector_offset = ((relative_block + lpart->hotfix.block_count + vpartition->segments[i].partition_block_offset) * 8) + disk_offset; + map[map_index].disk_id = disk_id; + map_index ++; + } + } + lpart = lpart->mirror_link; + } while (lpart != vpartition->segments[i].lpart_link); + *map_entry_count = map_index; + return(0); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + return(-1); +} + + +ULONG nwvp_vpartition_block_read( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i; + ULONG relative_block; + ULONG ccode; + nwvp_vpartition *vpartition; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + ccode = inwvp_lpartition_block_read( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + block_count, + data_buffer); + return(ccode); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + return(-1); +} + +ULONG nwvp_vpartition_sub_block_write( + ULONG vpart_handle, + ULONG block_number, + ULONG block_offset, + ULONG data_size, + BYTE *data_buffer, + ULONG as) +{ + ULONG i; + ULONG relative_block; + BYTE *temp_buffer; + nwvp_vpartition *vpartition; + if ((block_offset + data_size) > 4096) + { + NWFSPrint("AHA you dirty dog!!!! passed bad write size!!!\n"); + return -1; + } + + if (nwvp_io_alloc((void **) &temp_buffer, 4096) == 0) + { + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + if (inwvp_lpartition_block_read( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + 1, + temp_buffer) == 0) + { + if (as) + nwvp_memmove(&temp_buffer[block_offset], + data_buffer, data_size); + else + { + if (NWFSCopyFromUserSpace(&temp_buffer[block_offset], + data_buffer, data_size)) + { + nwvp_io_free(temp_buffer); + return (-1); + } + } + if (inwvp_lpartition_block_write( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + 1, + temp_buffer) == 0) + { + nwvp_io_free(temp_buffer); + return(0); + } + } + break; + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + nwvp_io_free(temp_buffer); + } + return(-1); +} + +ULONG inwvp_vpartition_block_write( + nwvp_vpartition *vpartition, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i; + ULONG relative_block; + + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + return (inwvp_lpartition_block_write( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + block_count, + data_buffer)); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + return(0x33000011); +} + +ULONG nwvp_vpartition_map_asynch_write( + ULONG vpart_handle, + ULONG block_number, + ULONG *map_entry_count, + nwvp_asynch_map *map) +{ + ULONG i; + ULONG disk_id; + ULONG disk_offset; + ULONG relative_block; + ULONG hotfix_block; + ULONG map_index = 0; + nwvp_vpartition *vpartition; + nwvp_lpart *lpart; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + lpart = vpartition->segments[i].lpart_link; + do + { + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (lpart->hotfix.bit_table[relative_block >> 15][(relative_block >> 5) & 0x3FF] & (1 << (relative_block & 0x1F))) + { + nwvp_part_map_to_physical(lpart->rpart_handle, &disk_id, &disk_offset, 0); + nwvp_hotfix_block_lookup(lpart, relative_block, &hotfix_block, &map[map_index].bad_bits); + map[map_index].sector_offset = (hotfix_block * 8) + disk_offset; + map[map_index].disk_id = disk_id; + map_index ++; + } + else + { + nwvp_part_map_to_physical(lpart->rpart_handle, &disk_id, &disk_offset, 0); + map[map_index].bad_bits = 0; + map[map_index].sector_offset = ((relative_block + lpart->hotfix.block_count + vpartition->segments[i].partition_block_offset) * 8) + disk_offset; + map[map_index].disk_id = disk_id; + map_index ++; + } + } + lpart = lpart->mirror_link; + } while (lpart != vpartition->segments[i].lpart_link); + *map_entry_count = map_index; + return(0); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + return(0x22000011); + } + return(0x22000022); + } + return(0x22000033); + } + return(0x22000044); +} + + +ULONG nwvp_vpartition_bad_bit_update( + ULONG vpart_handle, + ULONG block_number, + ULONG new_bad_bits) +{ + ULONG i; + ULONG relative_block; + ULONG ccode; + nwvp_vpartition *vpartition; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + ccode = inwvp_lpartition_bad_bit_update( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + new_bad_bits); + + return(ccode); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + return(0x11000011); + } + return(0x11000022); + } + return(0x11000033); + } + return(0x11000044); +} +ULONG nwvp_vpartition_block_write( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer) +{ + ULONG i; + ULONG relative_block; + ULONG ccode; + nwvp_vpartition *vpartition; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + ccode = inwvp_lpartition_block_write( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + block_count, + data_buffer); + + return(ccode); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + return(0x11000011); + } + return(0x11000022); + } + return(0x11000033); + } + return(0x11000044); +} + +ULONG inwvp_vpartition_block_hotfix( + nwvp_vpartition *vpartition, + ULONG block_number, + BYTE *data_buffer) +{ + ULONG i; + ULONG relative_block; + + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + return (inwvp_lpartition_block_hotfix( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + data_buffer)); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + return(-1); +} + +ULONG nwvp_vpartition_block_hotfix( + ULONG vpart_handle, + ULONG block_number, + BYTE *data_buffer) +{ + ULONG i; + ULONG relative_block; + ULONG ccode; + nwvp_vpartition *vpartition; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + ccode = inwvp_lpartition_block_hotfix( + vpartition->segments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset, + data_buffer); + +// NWUnlockNWVP(); + return(ccode); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + return(-1); +} + +ULONG nwvp_vpartition_block_zero( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count) +{ + ULONG i, j; + ULONG relative_block; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = block_number; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + for (j=0; jsegments[i].lpart_link, + relative_block + vpartition->segments[i].partition_block_offset + j, + 1, + zero_block_buffer) != 0) + { + return(-1); + } + } + NWUnlockNWVP(); + return(0); + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_rpartition_scan( + nwvp_payload *payload) +{ + ULONG index; + ULONG object_count; + nwvp_rpartition_scan_info *info; + nwvp_lpart *lpart; + + NWLockNWVP(); + object_count = (payload->payload_object_size_buffer_size & 0x000FFFFF) / 16; + info = (nwvp_rpartition_scan_info *) payload->payload_buffer; + index = payload->payload_index; + payload->payload_object_count = 0; + for (; indexrpart_handle = lpart->rpartition_handle; + info->lpart_handle = lpart->lpartition_handle; + info->physical_block_count = ((lpart->mirror_status & MIRROR_PRESENT_BIT) == 0) ? 0 :lpart->physical_block_count; + info->partition_type = ((lpart->mirror_status & MIRROR_PRESENT_BIT) == 0) ? 0 : lpart->partition_type; + info ++; + payload->payload_object_count ++; + + if (payload->payload_object_count >= object_count) + { + index ++; + for (; indexpayload_index = index; + NWUnlockNWVP(); + return(0); + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); + } + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); +} + +ULONG nwvp_rpartition_map_rpart_handle( + ULONG *rpart_handle, + ULONG physical_handle) +{ + ULONG i; + nwvp_lpart *lpart; + + for (i=0; irpart_handle == physical_handle) + { + *rpart_handle = lpart->rpartition_handle; + return(0); + } + } + } + return(-1); +} + +ULONG nwvp_rpartition_return_info( + ULONG rpart_handle, + nwvp_rpartition_info *rpart_info) +{ + nwvp_lpart *lpart; + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((lpart = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (lpart->rpartition_handle == rpart_handle)) + { + nwvp_memset(rpart_info, 0, sizeof(nwvp_rpartition_info)); + rpart_info->rpart_handle = rpart_handle; + rpart_info->lpart_handle = lpart->lpartition_handle; + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + rpart_info->physical_block_count = ((lpart->mirror_status & MIRROR_PRESENT_BIT) == 0) ? 0 :lpart->physical_block_count; + rpart_info->partition_type = ((lpart->mirror_status & MIRROR_PRESENT_BIT) == 0) ? 0 : lpart->partition_type; + rpart_info->physical_handle = ((lpart->mirror_status & MIRROR_PRESENT_BIT) == 0) ? 0 : lpart->rpart_handle; + rpart_info->status = (lpart->mirror_status & 0x0000FFFF) | (lpart->primary_link->mirror_status & 0xFFFF0000); + nwvp_part_map_to_physical(lpart->rpart_handle, &rpart_info->physical_disk_number, &rpart_info->partition_offset, &rpart_info->partition_number); + } + return(0); + } + } + return(-1); +} + +ULONG nwvp_lpartition_scan( + nwvp_payload *payload) +{ + ULONG index; + ULONG temp_section; + ULONG object_count; + ULONG percent; + nwvp_lpartition_scan_info *info; + nwvp_lpart *lpart; + nwvp_lpart *temp; + + NWLockNWVP(); + object_count = (payload->payload_object_size_buffer_size & 0x000FFFFF) / 16; + info = (nwvp_lpartition_scan_info *) payload->payload_buffer; + index = payload->payload_index; + payload->payload_object_count = 0; + for (; indexlpart_handle = lpart->lpartition_handle; + info->logical_block_count = lpart->logical_block_count; + info->open_flag = (lpart->mirror_status & MIRROR_GROUP_OPEN_BIT) ? 0xFFFFFFFF : 0; + temp_section = 0; + info->mirror_status = 0; + temp = lpart; + do + { + info->mirror_status += 1; + if (temp->mirror_status & MIRROR_PRESENT_BIT) + { + info->mirror_status += 0x100; + if (temp->remirror_section > temp_section) + { + if (temp->remirror_section < (temp->logical_block_count >> 10)) + temp_section = temp->remirror_section; + else + temp_section = temp->logical_block_count >> 10; + } + } + if (temp->mirror_status & MIRROR_INSYNCH_BIT) + info->mirror_status += 0x10000; + temp = temp->mirror_link; + } while (temp != lpart); + percent = 50; + if ((temp->logical_block_count >> 10) > 0) + percent = ((((temp->logical_block_count >> 10) - temp_section) * 100) / (temp->logical_block_count >> 10)); + + info->mirror_status += ((percent == 100) && (temp_section != 0)) ? 99 << 24 : percent << 24; + + info ++; + payload->payload_object_count ++; + + if (payload->payload_object_count >= object_count) + { + for (; indexlpartition_handle != 0xFFFFFFFF) + { + payload->payload_index = index + 1; + NWUnlockNWVP(); + return(0); + } + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); + } + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); +} + +ULONG nwvp_lpartition_return_info( + ULONG lpart_handle, + nwvp_lpartition_info *lpart_info) +{ + nwvp_lpart *lpart, *temp; + + nwvp_memset(lpart_info, 0, sizeof(nwvp_lpartition_info)); + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle)) + { + lpart_info->lpartition_handle = lpart->lpartition_handle; + lpart_info->lpartition_type = lpart->lpartition_type; + lpart_info->segment_count = (lpart->segment_sector == 0) ? 0 : lpart->segment_sector->NumberOfTableEntries; + lpart_info->mirror_count = lpart->mirror_count; + lpart_info->logical_block_count = lpart->logical_block_count; + lpart_info->lpartition_status = lpart->mirror_status; + lpart_info->open_count = lpart->open_count; + temp = lpart; + do + { + lpart_info->m[temp->mirror_sector_index].rpart_handle = temp->rpartition_handle; + lpart_info->m[temp->mirror_sector_index].hotfix_block_count = temp->physical_block_count - temp->logical_block_count; + lpart_info->m[temp->mirror_sector_index].status = temp->mirror_status; + temp = temp->mirror_link; + } while (temp != lpart); + NWUnlockNWVP(); + return(0); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_lpartition_return_space_info( + ULONG lpart_handle, + nwvp_payload *payload) +{ + ULONG index1; + ULONG index2; + ULONG sindex; + ULONG current_blocks; + ULONG object_count; + nwvp_lpartition_space_return_info *info; + nwvp_lpart *lpart; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle) && + ((lpart->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0)) + { + object_count = (payload->payload_object_size_buffer_size & 0x000FFFFF) / 16; + info = (nwvp_lpartition_space_return_info *) payload->payload_buffer; + sindex = payload->payload_index; + index1 = 0; + index2 = 0; + payload->payload_object_count = 0; + current_blocks = 0x14; + while (current_blocks < lpart->logical_block_count) + { + if ((lpart->segment_sector != 0) && + (index1 < lpart->segment_sector->NumberOfTableEntries)) + { + if ((lpart->segment_sector->VolumeEntry[index1].VolumeRoot / lpart->sectors_per_block) == current_blocks) + { + if (index2 == sindex) + { + info->lpart_handle = lpart->lpartition_handle; + info->segment_offset = lpart->segment_sector->VolumeEntry[index1].VolumeRoot / lpart->sectors_per_block; + info->segment_count = lpart->segment_sector->VolumeEntry[index1].SegmentSectors / lpart->sectors_per_block; + info->status_bits = INUSE_BIT; + if (lpart->mirror_link != lpart) + info->status_bits |= MIRROR_BIT; + info ++; + sindex ++; + + payload->payload_object_count ++; + if (payload->payload_object_count >= object_count) + { + payload->payload_index = sindex; + NWUnlockNWVP(); + return(0); + } + } + current_blocks = (lpart->segment_sector->VolumeEntry[index1].VolumeRoot + lpart->segment_sector->VolumeEntry[index1].SegmentSectors) / lpart->sectors_per_block; + index2 ++; + index1 ++; + } + else + { + if (index2 == sindex) + { + info->lpart_handle = lpart->lpartition_handle; + info->segment_offset = current_blocks; + info->segment_count = (lpart->segment_sector->VolumeEntry[index1].VolumeRoot / lpart->sectors_per_block) - current_blocks; + info->status_bits = 0; + if (lpart->mirror_link != lpart) + info->status_bits |= MIRROR_BIT; + info ++; + sindex ++; + + payload->payload_object_count ++; + if (payload->payload_object_count >= object_count) + { + payload->payload_index = sindex; + NWUnlockNWVP(); + return(0); + } + } + current_blocks = lpart->segment_sector->VolumeEntry[index1].VolumeRoot / lpart->sectors_per_block; + index2 ++; + } + } + else + { + if (index2 == sindex) + { + if ((info->segment_count = (lpart->logical_block_count - current_blocks)) != 0) + { + info->lpart_handle = lpart->lpartition_handle; + info->segment_offset = current_blocks; + info->status_bits = 0; + if (lpart->mirror_link != lpart) + info->status_bits |= MIRROR_BIT; + payload->payload_object_count ++; + if (payload->payload_object_count >= object_count) + { + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); + } + } + } + break; + } + } + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); +} + +ULONG nwvp_vpartition_scan( + nwvp_payload *payload) +{ + ULONG index; + ULONG object_count; + ULONG *handles; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + object_count = (payload->payload_object_size_buffer_size & 0x000FFFFF) / 4; + handles = (ULONG *) payload->payload_buffer; + index = payload->payload_index; + payload->payload_object_count = 0; + for (; indexvpartition_handle; + handles ++; + payload->payload_object_count ++; + + if (payload->payload_object_count >= object_count) + { + for (; indexpayload_index = index + 1; + NWUnlockNWVP(); + return(0); + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); + } + } + } + payload->payload_index = 0; + NWUnlockNWVP(); + return(0); +} + + +ULONG nwvp_vpartition_return_info( + ULONG vpart_handle, + nwvp_vpartition_info *vpinfo) +{ + ULONG i; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + nwvp_memmove(&vpinfo->volume_name[0], &vpartition->volume_name[0], 16); + vpinfo->volume_valid_flag = vpartition->volume_valid_flag; + vpinfo->open_flag = vpartition->open_flag; + vpinfo->mirror_flag = vpartition->mirror_flag; + vpinfo->cluster_count = vpartition->cluster_count; + vpinfo->segment_count = vpartition->segment_count; + vpinfo->vpart_handle = vpart_handle; + vpinfo->blocks_per_cluster = vpartition->blocks_per_cluster; + vpinfo->FAT1 = vpartition->FAT1; + vpinfo->FAT2 = vpartition->FAT2; + vpinfo->Directory1 = vpartition->Directory1; + vpinfo->Directory2 = vpartition->Directory2; + for (i=0; isegment_count; i++) + { + vpinfo->segments[i].segment_block_count = vpartition->segments[i].segment_block_count; + vpinfo->segments[i].partition_block_offset = vpartition->segments[i].partition_block_offset; + vpinfo->segments[i].relative_cluster_offset = vpartition->segments[i].relative_cluster_offset; + vpinfo->segments[i].lpart_handle = (vpartition->segments[i].lpart_link != 0) ? + vpartition->segments[i].lpart_link->lpartition_handle: + 0xFFFFFFFF; + } + NWUnlockNWVP(); + return(0); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_lpartition_remirror( + ULONG lpart_handle) +{ + nwvp_lpart *lpart; + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle)) + { + if (nwvp_start_remirror(lpart) == 0) + { + NWUnlockNWVP(); + return(0); + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_lpartition_abort_remirror( + ULONG lpart_handle) +{ + nwvp_lpart *lpart; + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle)) + { + if (nwvp_stop_remirror(lpart) == 0) + { + NWUnlockNWVP(); + return(0); + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_lpartition_unformat( + ULONG lpart_handle) +{ + nwvp_lpart *lpart; + nwvp_lpart *temp; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle) && + (lpart->mirror_link == lpart)) + { + logical_partition_table[lpart_handle & 0x0000FFFF] = 0; + while ((temp = lpart->mirror_link) != lpart) + { + lpart->mirror_link = temp->mirror_link; + nwvp_hotfix_destroy(temp); + temp->lpartition_handle = 0xFFFFFFFF; + } + nwvp_hotfix_destroy(temp); + logical_partition_table[lpart_handle & 0x0000FFFF] = 0; + temp->lpartition_handle = 0xFFFFFFFF; + NWUnlockNWVP(); + return(0); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_lpartition_format( + ULONG *lpartition_id, + ULONG logical_block_count, + ULONG *base_partition_ids) +{ + ULONG i; + nwvp_lpart *lparts[4]; + nwvp_lpart *base_part = 0; + + NWLockNWVP(); + for (i=0; i<4; i++) + { + lparts[i] = 0; + if (base_partition_ids[i] != 0xFFFFFFFF) + { + if ((base_partition_ids[i] & 0x0000FFFF) < raw_partition_table_count) + { + if (((lparts[i] = raw_partition_table[base_partition_ids[i] & 0x0000FFFF]) != 0) && + (lparts[i]->rpartition_handle == base_partition_ids[i])) + { + if (base_part == 0) + base_part = lparts[i]; + if ((lparts[i]->partition_type != 0x65) && (lparts[i]->partition_type != 0x77)) + { + NWUnlockNWVP(); + return(-1); + } + if (lparts[i]->lpartition_handle != 0xFFFFFFFF) + { + NWUnlockNWVP(); + return(-1); + } + if (lparts[i]->physical_block_count < (logical_block_count + 64)) + { + NWUnlockNWVP(); + return(-1); + } + } + else + lparts[i] = 0; + } + } + } + if (base_part == 0) + { + NWUnlockNWVP(); + return(-1); + } + for (i=0; i < 4; i++) + { + if (lparts[i] != 0) + { + if (nwvp_hotfix_create(lparts[i], logical_block_count) != 0) + { + for (; i > 0; i--) + { + if (lparts[i-1] != 0) + nwvp_hotfix_destroy(lparts[i-i]); + } + NWUnlockNWVP(); + return(-1); + } + } + } + nwvp_mirror_group_add(base_part); + for (i=0; i<4; i++) + { + if (lparts[i] != 0) + { + if (lparts[i] != base_part) + { + lparts[i]->lpartition_handle = base_part->lpartition_handle; + nwvp_mirror_member_add(base_part, lparts[i]); + } + } + } + nwvp_mirror_group_establish(base_part, 0); + *lpartition_id = base_part->lpartition_handle; + NWUnlockNWVP(); + return(0); +} + + +ULONG nwvp_partition_add_mirror( + ULONG lpart_handle, + ULONG rpart_handle) +{ + ULONG temp_handle; + nwvp_lpart *rpart; + nwvp_lpart *lpart; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle) && + ((lpart->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0)) + { + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((rpart = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (rpart->rpartition_handle == rpart_handle)) + { + if (rpart->physical_block_count < (lpart->logical_block_count + 64)) + { + NWUnlockNWVP(); + return(-1); + } + if ((temp_handle = rpart->lpartition_handle) != 0xFFFFFFFF) + { + if (rpart->mirror_link != rpart) + { + NWUnlockNWVP(); + return(-1); + } + nwvp_hotfix_destroy(rpart); + logical_partition_table[temp_handle & 0x0000FFFF] = 0; + rpart->lpartition_handle = 0xFFFFFFFF; + } + if (nwvp_hotfix_create(rpart, lpart->logical_block_count) == 0) + { + rpart->lpartition_handle = lpart->lpartition_handle; + nwvp_mirror_member_add(lpart, rpart); + NWUnlockNWVP(); + return(0); + } + } + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_partition_del_mirror( + ULONG lpart_handle, + ULONG rpart_handle) +{ + nwvp_lpart *rpart; + nwvp_lpart *lpart; + + NWLockNWVP(); + if ((lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == lpart_handle) && + ((lpart->mirror_status & MIRROR_GROUP_ACTIVE_BIT) != 0) && + (lpart->mirror_count > 1)) + { + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((rpart = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (rpart->rpartition_handle == rpart_handle)) + { + if (nwvp_mirror_member_delete(rpart) == 0) + { + NWUnlockNWVP(); + return(0); + } + } + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_bounds_check( + ULONG start1, + ULONG count1, + ULONG start2, + ULONG count2) +{ + if (start2 >= 0xA0) + { + if ((start2 + count2) > (start1 + count1)) + return(0); + if ((start2 + count2) <= start1) + return(0); + } + return(-1); +} + +ULONG nwvp_vpartition_build_directory( + nwvp_vpartition *vpartition, + ULONG flags) +{ + ULONG i; + ULONG dir_block1; + ULONG dir_block2; + BYTE *dir_table; + + nwvp_io_alloc((void **) &dir_table, 4096); + nwvp_memset(dir_table, 0, 4096); + dir_block1 = vpartition->Directory1 * vpartition->blocks_per_cluster; + dir_block2 = vpartition->Directory2 * vpartition->blocks_per_cluster; + + if (CreateRootDirectory(dir_table, + IO_BLOCK_SIZE, + flags, + vpartition->blocks_per_cluster * + IO_BLOCK_SIZE) == 0) + { + inwvp_vpartition_block_write(vpartition, dir_block1, 1, (BYTE *) dir_table); + inwvp_vpartition_block_write(vpartition, dir_block2, 1, (BYTE *) dir_table); + nwvp_memset(dir_table, 0, 4096); + for (i=0; i<4096; i+=128) + { + dir_table[i + 0] = 0xFF; + dir_table[i + 1] = 0xFF; + dir_table[i + 2] = 0xFF; + dir_table[i + 3] = 0xFF; + } + for (i=1; iblocks_per_cluster; i++) + { + dir_block1 ++; + dir_block2 ++; + inwvp_vpartition_block_write(vpartition, dir_block1, 1, (BYTE *) dir_table); + inwvp_vpartition_block_write(vpartition, dir_block2, 1, (BYTE *) dir_table); + } + nwvp_io_free(dir_table); + return(0); + } + nwvp_io_free(dir_table); + return(-1); +} + +/************************************************************************** +* +* The NetWare VRepair program assumes that the fat tables will be organized +* in a specific manor. Depending upon the cluster size, the second fat table +* will always begin at a certain block offset defined in gap_table[]. The +* fat chains then alternate. +* +* (32k example: F1=0 - 7 F2=8 - 15 F1= 16 - 23 F2= 24 - 31 ... +* +* After the fats are layed out, the directory tables are allocated in the +* holes or at the end. +* +***************************************************************************/ + + +ULONG gap_table[] = { 0x00, 0x40, 0x20, 0x00, + 0x10, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x04}; + +ULONG nwvp_vpartition_fat_check( + ULONG vpart_handle) +{ + ULONG close_flag = 0; + ULONG pass; + ULONG gap; + ULONG fat_index; + ULONG current_index; + ULONG current_block_offset; + ULONG current_block_entry; + ULONG entries_per_cluster; + ULONG entries_per_block; + ULONG total_fat_clusters; + FAT_ENTRY *fat_block; + nwvp_vpartition *vpartition; + + nwvp_io_alloc((void **) &fat_block, 4096); + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag == 0) + { + inwvp_vpartition_open(vpartition); + close_flag = 1; + } + entries_per_cluster = ((vpartition->blocks_per_cluster << 12) >> 3); + entries_per_block = 4096 / sizeof(FAT_ENTRY); + gap = gap_table[vpartition->blocks_per_cluster]; + total_fat_clusters = (vpartition->cluster_count + (entries_per_cluster -1)) / entries_per_cluster; + + fat_index = 0; + pass = 0; + while (1) + { + current_index = 0; + current_block_offset = 0; + current_block_entry = 0x200; + inwvp_vpartition_block_read(vpartition, current_block_offset, 1, (BYTE *) fat_block); + while (fat_block[fat_index & 0x1FF].FATCluster != (long) 0xFFFFFFFF) + { + if (fat_block[fat_index & 0x1FF].FATIndex != (long) current_index) + break; + + if (fat_block[fat_index & 0x1FF].FATCluster >= (long) current_block_entry) + { + current_block_entry = fat_block[fat_index & 0x1FF].FATCluster / entries_per_block; + if ((current_block_entry / vpartition->blocks_per_cluster) == current_index) + current_block_offset = (fat_index * vpartition->blocks_per_cluster) + (current_block_entry % vpartition->blocks_per_cluster); + else + current_block_offset = fat_block[fat_index & 0x1FF].FATCluster * vpartition->blocks_per_cluster; + fat_index = fat_block[fat_index & 0x1FF].FATCluster; + current_block_entry = (current_block_entry + 1) * entries_per_block; + inwvp_vpartition_block_read(vpartition, current_block_offset, 1, (BYTE *) fat_block); + } + else + fat_index = fat_block[fat_index & 0x1FF].FATCluster; + current_index ++; + } + if (fat_block[fat_index & 0x1FF].FATCluster != (long) 0xFFFFFFFF) + break; + if (fat_block[fat_index & 0x1FF].FATIndex != (long) current_index) + break; + if ((current_index + 1) != total_fat_clusters) + break; + if (pass == 1) + { + if (close_flag != 0) + inwvp_vpartition_close(vpartition); + NWUnlockNWVP(); + nwvp_io_free(fat_block); + return(0); + } + pass = 1; + fat_index = gap; + } + if (close_flag != 0) + inwvp_vpartition_close(vpartition); + + } + } + NWUnlockNWVP(); + nwvp_io_free(fat_block); + return(-1); +} + +ULONG nwvp_vpartition_build_fat( + nwvp_vpartition *vpartition, + ULONG current_segment) +{ + ULONG i, j, k; + ULONG entries_per_block; + ULONG entries_per_cluster; + ULONG current_index; + ULONG base_index; + ULONG fat_index; + ULONG next_index; + ULONG dir_flag = 0; + ULONG current_fat_clusters; + ULONG previous_fat_clusters; + ULONG prev_offset; + ULONG current_block_offset; + ULONG current_block_entry; + ULONG extra_block_offset; + ULONG gap; + ULONG block_gap; + ULONG gap_fudge; + FAT_ENTRY *fat_block; + + + nwvp_io_alloc((void **) &fat_block, 4096 * 2); + nwvp_memset(fat_block, 0, 4096 * 2); + + entries_per_cluster = ((vpartition->blocks_per_cluster << 12) >> 3); + entries_per_block = 4096 / sizeof(FAT_ENTRY); + gap = gap_table[vpartition->blocks_per_cluster]; + block_gap = gap * vpartition->blocks_per_cluster; + + if (current_segment == 0) + { + dir_flag = 1; + current_index = 0; + prev_offset = 0; + previous_fat_clusters = 0; + for (k=0; kblocks_per_cluster; k++) + { + inwvp_vpartition_block_write(vpartition, 0 + k, 1, (BYTE *) zero_block_buffer); + inwvp_vpartition_block_write(vpartition, 0 + block_gap + k, 1, (BYTE *) zero_block_buffer); + } + } + else + { + fat_index = 0; + current_index = 0; + current_block_offset = 0; + current_block_entry = 0x200; + inwvp_vpartition_block_read(vpartition, current_block_offset, 2, (BYTE *) fat_block); + while (fat_block[fat_index & 0x1FF].FATCluster != 0xFFFFFFFF) + { + if (fat_block[fat_index & 0x1FF].FATIndex != (long) current_index) + break; + if (fat_block[fat_index & 0x1FF].FATCluster >= (long) current_block_entry) + { + current_block_entry = fat_block[fat_index & 0x1FF].FATCluster / entries_per_block; + if ((current_block_entry / vpartition->blocks_per_cluster) == current_index) + current_block_offset = (fat_index * vpartition->blocks_per_cluster) + (current_block_entry % vpartition->blocks_per_cluster); + else + current_block_offset = fat_block[fat_index & 0x1FF].FATCluster * vpartition->blocks_per_cluster; + fat_index = fat_block[fat_index & 0x1FF].FATCluster; + current_block_entry = (current_block_entry + 1) * entries_per_block; + inwvp_vpartition_block_read(vpartition, current_block_offset, 2, (BYTE *) fat_block); + } + else + fat_index = fat_block[fat_index & 0x1FF].FATCluster; + current_index ++; + } + prev_offset = fat_index; + current_index ++; + current_fat_clusters = vpartition->segments[current_segment].relative_cluster_offset + (vpartition->segments[current_segment].segment_block_count / vpartition->blocks_per_cluster); + current_fat_clusters = (current_fat_clusters + (entries_per_cluster -1)) / entries_per_cluster; + previous_fat_clusters = current_index; + if (current_fat_clusters <= previous_fat_clusters) + { + nwvp_io_free(fat_block); + return(0); + } + fat_block[fat_index & 0x1FF].FATCluster = vpartition->segments[current_segment].relative_cluster_offset; + fat_block[(fat_index & 0x1FF) + gap].FATCluster = vpartition->segments[current_segment].relative_cluster_offset + gap; + inwvp_vpartition_block_write(vpartition, current_block_offset, 2, (BYTE *) fat_block); + inwvp_vpartition_block_write(vpartition, current_block_offset + block_gap, 2, (BYTE *) fat_block); + } + + for (i=current_segment; isegment_count; i++) + { + current_fat_clusters = vpartition->segments[i].relative_cluster_offset + (vpartition->segments[i].segment_block_count / vpartition->blocks_per_cluster); + current_fat_clusters = (current_fat_clusters + (entries_per_cluster -1)) / entries_per_cluster; + fat_index = vpartition->segments[i].relative_cluster_offset; + base_index = current_index; + gap_fudge = gap - (fat_index % gap); + if ((fat_index / entries_per_cluster) < base_index) + { + current_block_offset = (prev_offset * vpartition->blocks_per_cluster) + ((fat_index / entries_per_block) % vpartition->blocks_per_cluster); + if (((fat_index + gap) / entries_per_cluster) < base_index) + extra_block_offset = current_block_offset + 1; + else + extra_block_offset = vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster; + } + else + { + current_block_offset = vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster; + extra_block_offset = current_block_offset + 1; + } + inwvp_vpartition_block_read(vpartition, current_block_offset, 1, (BYTE *) fat_block); + nwvp_memset(&fat_block[0x200], 0, 4096); + prev_offset = vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster; + + for (j=0; j < (current_fat_clusters - previous_fat_clusters); j++) + { + + for (k=0; kblocks_per_cluster; k++) + { + inwvp_vpartition_block_write(vpartition, (fat_index * vpartition->blocks_per_cluster) + k, 1, (BYTE *) zero_block_buffer); + inwvp_vpartition_block_write(vpartition, (fat_index * vpartition->blocks_per_cluster) + block_gap + k, 1, (BYTE *) zero_block_buffer); + } + if ((j+1) < (current_fat_clusters - previous_fat_clusters)) + { + fat_block[fat_index & 0x1FF].FATIndex = current_index; + fat_block[(fat_index & 0x1FF) + gap].FATIndex = current_index; + if (((fat_index + gap_fudge + 1) % gap) == 0) + { + fat_block[fat_index & 0x1FF].FATCluster = fat_index + gap + 1; + fat_block[(fat_index & 0x1FF) + gap].FATCluster = fat_index + gap + gap + 1; + } + else + { + fat_block[fat_index & 0x1FF].FATCluster = fat_index + 1; + fat_block[(fat_index & 0x1FF) + gap].FATCluster = fat_index + gap + 1; + } + if (((fat_index & 0x1FF) == 0x1FF) || (((fat_index+gap) & 0x1FF) == 0x1FF)) + { + inwvp_vpartition_block_write(vpartition, current_block_offset, 1, (BYTE *) fat_block); + inwvp_vpartition_block_write(vpartition, current_block_offset + block_gap, 1, (BYTE *) fat_block); + if (((fat_index & 0x1FF) + gap) > 0x200) + { + inwvp_vpartition_block_write(vpartition, extra_block_offset, 1, (BYTE *) &fat_block[0x200]); + inwvp_vpartition_block_write(vpartition, extra_block_offset + block_gap, 1, (BYTE *) &fat_block[0x200]); + } + nwvp_memmove(fat_block, &fat_block[0x200], 4096); + nwvp_memset(&fat_block[0x200], 0, 4096); + + if (current_block_offset < (vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster)) + { + current_block_offset = vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster; + extra_block_offset = current_block_offset + 1; + } + else + { + current_block_offset ++; + extra_block_offset ++; + } + + if (((fat_index + gap_fudge + 1) % gap) == 0) + fat_index += gap; + fat_index ++; + + if ((fat_index / entries_per_cluster) < base_index) + { + current_block_offset ++; + if (((fat_index + gap) / entries_per_cluster) < current_index) + extra_block_offset = current_block_offset + 1; + else + extra_block_offset = vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster; + } + else + { + if (current_block_offset < (vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster)) + { + current_block_offset = vpartition->segments[i].relative_cluster_offset * vpartition->blocks_per_cluster; + extra_block_offset = current_block_offset + 1; + } + else + { + current_block_offset ++; + extra_block_offset ++; + } + } + } + else + { + if (((fat_index + gap_fudge + 1) % gap) == 0) + fat_index += gap; + fat_index ++; + } + } + else + { + fat_block[fat_index & 0x1FF].FATIndex = current_index; + fat_block[(fat_index & 0x1FF) + gap].FATIndex = current_index; + while ((i+1) < vpartition->segment_count) + { + next_index = (vpartition->segments[i+1].relative_cluster_offset + (vpartition->segments[i+1].segment_block_count / vpartition->blocks_per_cluster)) / entries_per_cluster; + if (next_index == current_index) + i++; + else + { + fat_block[fat_index & 0x1FF].FATCluster = vpartition->segments[i+1].relative_cluster_offset; + fat_block[(fat_index & 0x1FF) + gap].FATCluster = vpartition->segments[i+1].relative_cluster_offset + gap; + break; + } + } + if ((i+1) == vpartition->segment_count) + { + fat_block[fat_index & 0x1FF].FATCluster = 0xFFFFFFFF; + fat_block[(fat_index & 0x1FF) + gap].FATCluster = 0xFFFFFFFF; + } + if (dir_flag == 1) + { + dir_flag = 0; + for (k=0; kFAT1 = 0; + vpartition->FAT2 = gap; + vpartition->Directory1 = (fat_index & 0xFFFFFE00) + k; + vpartition->Directory2 = (fat_index & 0xFFFFFE00) + k + gap + 1; + fat_block[k].FATCluster = 0xFFFFFFFF; + fat_block[k + gap + 1].FATCluster = 0xFFFFFFFF; + break; + } + } + } + inwvp_vpartition_block_write(vpartition, current_block_offset, 1, (BYTE *) fat_block); + inwvp_vpartition_block_write(vpartition, current_block_offset + block_gap, 1, (BYTE *) fat_block); + if (((fat_index & 0x1FF) + gap) > 0x200) + { + inwvp_vpartition_block_write(vpartition, extra_block_offset, 1, (BYTE *) &fat_block[0x200]); + inwvp_vpartition_block_write(vpartition, extra_block_offset + block_gap, 1, (BYTE *) &fat_block[0x200]); + } + prev_offset = fat_index; + } + current_index ++; + } + previous_fat_clusters = current_fat_clusters; + } + nwvp_io_free(fat_block); + return(0); +} + +ULONG nwvp_vpartition_segment_flush( + nwvp_vpartition *vpartition) +{ + ULONG i; + for (i=0; isegment_count; i++) + { + nwvp_segmentation_sectors_flush(vpartition->segments[i].lpart_link); + } + return(0); +} + +ULONG vpartition_update_entry_index( + nwvp_lpart *lpart, + BYTE *volume_name, + ULONG old_index, + ULONG new_index) +{ + ULONG i, j; + nwvp_vpartition *vpartition; + + for (j=0; jvolume_name[0], 16) == 0) + { + for (i=0; isegment_count; i++) + { + if ((vpartition->segments[i].lpart_link == lpart) && (vpartition->segments[i].volume_entry_index == old_index)) + { + vpartition->segments[i].volume_entry_index = new_index; + return (0); + } + } + } + } + } + return(-1); +} + +ULONG vpartition_update_lpartition( + nwvp_lpart *lpart, + nwvp_lpart *new_lpart) +{ + ULONG i, j; + nwvp_vpartition *vpartition; + + for (j=0; jsegment_count; i++) + { + if (vpartition->segments[i].lpart_link == lpart) + { + vpartition->segments[i].lpart_link = new_lpart; + } + } + } + } + return(0); +} + +ULONG nwvp_vpartition_fat_fix( + ULONG vpart_handle, + nwvp_fat_fix_info *fix_info, + ULONG fix_flag) +{ + ULONG ccode; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + NWUnlockNWVP(); + ccode = nwvp_fat_table_fix(vpartition, fix_info, fix_flag); + return(ccode); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG inwvp_vpartition_open( + nwvp_vpartition *vpartition) +{ + ULONG i; + + if ((vpartition->open_flag == 0) && (vpartition->volume_valid_flag != 0xFFFFFFFF)) + { + for (i=0; isegment_count; i++) + { + if (nwvp_mirror_group_open(vpartition->segments[i].lpart_link) != 0) + { + for (; i > 0; i--) + nwvp_mirror_group_close(vpartition->segments[i-1].lpart_link); + break; + } + } + if (i == vpartition->segment_count) + { + vpartition->open_flag = 0xFFFFFFFF; + return(0); + } + } + return(-1); +} + +ULONG nwvp_vpartition_open( + ULONG vpart_handle) +{ + ULONG ccode; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + ccode = inwvp_vpartition_open(vpartition); + NWUnlockNWVP(); + return(ccode); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG inwvp_vpartition_close( + nwvp_vpartition *vpartition) +{ + ULONG i; + + if (vpartition->open_flag != 0) + { + for (i=0; isegment_count; i++) + { + nwvp_mirror_group_close(vpartition->segments[i].lpart_link); + } + vpartition->open_flag = 0; + return(0); + } + return(-1); +} +ULONG nwvp_vpartition_close( + ULONG vpart_handle) +{ + ULONG ccode; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + ccode = inwvp_vpartition_close(vpartition); + NWUnlockNWVP(); + return(ccode); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_vpartition_format( + ULONG *vpart_handle, + vpartition_info *vpart_info, + segment_info *segment_info_table) +{ + ULONG i, j, k; + ULONG total_blocks = 0; + nwvp_lpart *lpart; + segment_info *sinfo; + nwvp_vpartition *vpartition; + nwvp_lpart *lpartition; + + + NWLockNWVP(); + if (virtual_partition_table_count >= MAX_VOLUMES) + { + NWUnlockNWVP(); + return(-1); + } + + sinfo = segment_info_table; + for (i=0; isegment_count; i++, sinfo ++) + { + if (((lpart = logical_partition_table[sinfo->lpartition_id & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == sinfo->lpartition_id)) + { + if ((sinfo->block_offset + sinfo->block_count) > lpart->logical_block_count) + { + NWUnlockNWVP(); + return(-1); + } + for (j=0; jsegment_sector->NumberOfTableEntries; j++) + { + + if (nwvp_bounds_check(lpart->segment_sector->VolumeEntry[j].VolumeRoot, lpart->segment_sector->VolumeEntry[j].SegmentSectors, sinfo->block_offset * lpart->sectors_per_block, sinfo->block_count * lpart->sectors_per_block) != 0) + { + NWUnlockNWVP(); + return(-1); + } + } + total_blocks += (sinfo->block_count / vpart_info->blocks_per_cluster) * vpart_info->blocks_per_cluster; + } + else + { + NWUnlockNWVP(); + return(-1); + } + } + if (total_blocks != vpart_info->cluster_count * vpart_info->blocks_per_cluster) + { + NWUnlockNWVP(); + return(-1); + } + + sinfo = segment_info_table; + nwvp_alloc((void **) &vpartition, sizeof(nwvp_vpartition)); + nwvp_memset((void *) vpartition, 0, sizeof(nwvp_vpartition)); + for (i=0; ivpartition_handle = (handle_instance ++ << 16) + i; + vpartition->segment_count = vpart_info->segment_count; + vpartition->cluster_count = vpart_info->cluster_count; + vpartition->blocks_per_cluster = vpart_info->blocks_per_cluster; + + + total_blocks = 0; + for (i=0; isegment_count; i++, sinfo ++) + { + if ((lpart = logical_partition_table[sinfo->lpartition_id & 0x0000FFFF]) != 0) + { + for (j=0; jsegment_sector->NumberOfTableEntries; j++) + { + if (((sinfo->block_count + sinfo->block_offset) * lpart->sectors_per_block) <= lpart->segment_sector->VolumeEntry[j].VolumeRoot) + { + for (k=lpart->segment_sector->NumberOfTableEntries; k>j; k--) + { + nwvp_memmove(&lpart->segment_sector->VolumeEntry[k], &lpart->segment_sector->VolumeEntry[k-1], sizeof(VOLUME_TABLE_ENTRY)); + vpartition_update_entry_index(lpart, lpart->segment_sector->VolumeEntry[k].VolumeName, k-1, k); + } + lpart->segment_sector->NumberOfTableEntries ++; + break; + } + } + if (j == lpart->segment_sector->NumberOfTableEntries) + { + lpart->segment_sector->NumberOfTableEntries ++; + } + + for (k=0; k < (ULONG)(vpart_info->volume_name[0] + 1); k++) + { + lpart->segment_sector->VolumeEntry[j].VolumeName[k] = vpart_info->volume_name[k]; + vpartition->volume_name[k] = vpart_info->volume_name[k]; + } + for (; k<16; k++) + { + lpart->segment_sector->VolumeEntry[j].VolumeName[k] = 0; + vpartition->volume_name[k] = 0; + } + +// nwvp_memmove(&lpart->segment_sector->VolumeEntry[j].VolumeName[0], &vpart_info->volume_name[0], 16); +// nwvp_memmove(&vpartition->volume_name[0], &vpart_info->volume_name[0], 16); + + lpart->segment_sector->VolumeEntry[j].LastVolumeSegment = vpart_info->segment_count - 1; + lpart->segment_sector->VolumeEntry[j].VolumeSignature = (i << 16) + (vpart_info->segment_count << 8) + cluster_size_table[vpart_info->blocks_per_cluster]; + lpart->segment_sector->VolumeEntry[j].VolumeRoot = sinfo->block_offset * lpart->sectors_per_block; + lpart->segment_sector->VolumeEntry[j].SegmentSectors = sinfo->block_count * lpart->sectors_per_block; + lpart->segment_sector->VolumeEntry[j].VolumeClusters = vpart_info->cluster_count; + lpart->segment_sector->VolumeEntry[j].SegmentClusterStart = total_blocks / vpart_info->blocks_per_cluster; + lpart->segment_sector->VolumeEntry[j].FirstFAT = 0xFFFFFFFF; + lpart->segment_sector->VolumeEntry[j].SecondFAT = 0xFFFFFFFF; + lpart->segment_sector->VolumeEntry[j].FirstDirectory = 0xFFFFFFFF; + lpart->segment_sector->VolumeEntry[j].SecondDirectory = 0xFFFFFFFF; + lpart->segment_sector->VolumeEntry[j].Padding = 0; + vpartition->segments[i].lpart_link = logical_partition_table[sinfo->lpartition_id & 0x0000FFFF]; + vpartition->segments[i].segment_block_count = (sinfo->block_count / vpart_info->blocks_per_cluster) * vpart_info->blocks_per_cluster; + vpartition->segments[i].partition_block_offset = sinfo->block_offset; + vpartition->segments[i].relative_cluster_offset = total_blocks / vpart_info->blocks_per_cluster; + vpartition->segments[i].volume_entry_index = j; + total_blocks += (sinfo->block_count / vpart_info->blocks_per_cluster) * vpart_info->blocks_per_cluster; + } + } + vpartition->volume_valid_flag = 0; + inwvp_vpartition_open(vpartition); + nwvp_vpartition_build_fat(vpartition, 0); + nwvp_vpartition_build_directory(vpartition, vpart_info->flags); + for (i=0; isegment_count; i++) + { + lpartition = vpartition->segments[i].lpart_link; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].FirstFAT = vpartition->FAT1; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].SecondFAT = vpartition->FAT2; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].FirstDirectory = vpartition->Directory1; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].SecondDirectory = vpartition->Directory2; + } + nwvp_vpartition_segment_flush(vpartition); + *vpart_handle = vpartition->vpartition_handle; + inwvp_vpartition_close(vpartition); + NWUnlockNWVP(); + return(0); +} + +ULONG nwvp_vpartition_add_segment( + ULONG vpart_handle, + segment_info *segment_info_table) +{ + ULONG i, j, k; + ULONG total_blocks; + ULONG close_flag = 0; + nwvp_lpart *lpart; + segment_info *sinfo; + nwvp_vpartition *vpartition; + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle) && + (vpartition->volume_valid_flag == 0)) + { + sinfo = segment_info_table; + if (((lpart = logical_partition_table[sinfo->lpartition_id & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == sinfo->lpartition_id)) + { + for (j=0; jsegment_sector->NumberOfTableEntries; j++) + { + if (nwvp_bounds_check(lpart->segment_sector->VolumeEntry[j].VolumeRoot, lpart->segment_sector->VolumeEntry[j].SegmentSectors, sinfo->block_offset * lpart->sectors_per_block, sinfo->block_count * lpart->sectors_per_block) != 0) + { + NWUnlockNWVP(); + return(-1); + } + } + } + else + { + NWUnlockNWVP(); + return(-1); + } + if (((lpart = logical_partition_table[sinfo->lpartition_id & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == sinfo->lpartition_id)) + { + for (j=0; jsegment_sector->NumberOfTableEntries; j++) + { + if (((sinfo->block_count + sinfo->block_offset) * lpart->sectors_per_block) <= lpart->segment_sector->VolumeEntry[j].VolumeRoot) + { + for (k=lpart->segment_sector->NumberOfTableEntries; k>j; k--) + { + nwvp_memmove(&lpart->segment_sector->VolumeEntry[k], &lpart->segment_sector->VolumeEntry[k-1], sizeof(VOLUME_TABLE_ENTRY)); + vpartition_update_entry_index(lpart, lpart->segment_sector->VolumeEntry[k].VolumeName, k-1, k); + } + lpart->segment_sector->NumberOfTableEntries ++; + break; + } + } + if (j == lpart->segment_sector->NumberOfTableEntries) + { + lpart->segment_sector->NumberOfTableEntries ++; + } + total_blocks = vpartition->cluster_count * vpartition->blocks_per_cluster; + vpartition->cluster_count += sinfo->block_count / vpartition->blocks_per_cluster; + i = vpartition->segment_count; + vpartition->segment_count ++; + nwvp_memmove(&lpart->segment_sector->VolumeEntry[j].VolumeName[0], &vpartition->volume_name[0], 16); + lpart->segment_sector->VolumeEntry[j].VolumeRoot = sinfo->block_offset * lpart->sectors_per_block; + lpart->segment_sector->VolumeEntry[j].SegmentSectors = sinfo->block_count * lpart->sectors_per_block; + lpart->segment_sector->VolumeEntry[j].SegmentClusterStart = total_blocks / vpartition->blocks_per_cluster; + lpart->segment_sector->VolumeEntry[j].FirstFAT = vpartition->FAT1; + lpart->segment_sector->VolumeEntry[j].SecondFAT = vpartition->FAT2; + lpart->segment_sector->VolumeEntry[j].FirstDirectory = vpartition->Directory1; + lpart->segment_sector->VolumeEntry[j].SecondDirectory = vpartition->Directory2; + lpart->segment_sector->VolumeEntry[j].Padding = 0; + vpartition->segments[i].lpart_link = logical_partition_table[sinfo->lpartition_id & 0x0000FFFF]; + vpartition->segments[i].segment_block_count = (sinfo->block_count / vpartition->blocks_per_cluster) * vpartition->blocks_per_cluster; + vpartition->segments[i].partition_block_offset = sinfo->block_offset; + vpartition->segments[i].relative_cluster_offset = total_blocks / vpartition->blocks_per_cluster; + vpartition->segments[i].volume_entry_index = j; + for (i=0; isegment_count; i++) + { + vpartition->segments[i].lpart_link->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].LastVolumeSegment = vpartition->segment_count - 1; + vpartition->segments[i].lpart_link->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].VolumeSignature = (i << 16) + (vpartition->segment_count << 8) + cluster_size_table[vpartition->blocks_per_cluster]; + vpartition->segments[i].lpart_link->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].VolumeClusters = vpartition->cluster_count; + lpartition = vpartition->segments[i].lpart_link; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].FirstFAT = vpartition->FAT1; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].SecondFAT = vpartition->FAT2; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].FirstDirectory = vpartition->Directory1; + lpartition->segment_sector->VolumeEntry[vpartition->segments[i].volume_entry_index].SecondDirectory = vpartition->Directory2; + } + + if (vpartition->open_flag == 0) + { + close_flag = 1; + inwvp_vpartition_open(vpartition); + } + + nwvp_vpartition_build_fat(vpartition, i-1); + nwvp_vpartition_segment_flush(vpartition); + + if (close_flag != 0) + inwvp_vpartition_close(vpartition); + + NWUnlockNWVP(); + return(0); + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_vpartition_unformat( + ULONG vpart_handle) +{ + ULONG i; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + for (i=0; isegment_count; i++) + { + if (vpartition->segments[i].lpart_link != 0) + nwvp_segmentation_remove_specific(vpartition->segments[i].lpart_link, vpartition->segments[i].volume_entry_index); + } + nwvp_free(vpartition); + virtual_partition_table[vpart_handle & 0x0000FFFF] = 0; + NWUnlockNWVP(); + return(0); + } + } + NWUnlockNWVP(); + return(-1); +} + +void nwvp_scan_routine( + ULONG scan_flag) +{ + ULONG i, j; + ULONG free_slot; + ULONG handles[10]; + ULONG partition_id; + ULONG group_id; + BYTE *temp_buffer; + nwvp_payload payload; + nwvp_part_info part_info; + nwvp_lpart *lpart; + MIRROR *mirror_sector; + + + if (nwvp_init_flag == 0) + nwvp_init(); + + + NWLockNWVP(); + nwvp_io_alloc((void **) &temp_buffer, 4096); + + for (i=0; iscan_flag = 0xFFFFFFFF; + } + + payload.payload_object_count = 0; + payload.payload_index = 0; + payload.payload_object_size_buffer_size = (sizeof(ULONG) << 20) + sizeof(handles); + payload.payload_buffer = (BYTE *) &handles[0]; + do + { + nwvp_part_scan(&payload); + for (j=0; j< payload.payload_object_count; j++) + { + if (nwvp_part_scan_specific (handles[j], &part_info) == 0) + { + partition_id = 0xFFFFFFFF; + group_id = 0xFFFFFFFF; + if ((part_info.partition_type & 0xFF) == 0x65) + { + mirror_sector = (MIRROR *) &temp_buffer[512]; + for (i=0x20; i<=0x80; i+=0x20) + { + if (nwvp_part_read(handles[j], i, 1 << (12 - part_info.sector_size_shift), temp_buffer) == 0) + { + if (nwvp_hotfix_and_mirror_validate(temp_buffer, part_info.sector_count) == 0) + { + partition_id = mirror_sector->PartitionID; + group_id = mirror_sector->MirrorGroupID; + break; + } + else + { + nwvp_memset(temp_buffer, 0, 4096); + } + } + } + } + + free_slot = 0xFFFFFFFF; + for (i=0; irpart_handle != handles[j]) + { + if ((partition_id != 0xFFFFFFFF) && + (lpart->mirror_partition_id == partition_id) && + (lpart->mirror_group_id == group_id)) + { + if ((lpart->mirror_status & MIRROR_PRESENT_BIT) == 0) + { + if ((part_info.partition_type & 0x80000000) != 0) + lpart->mirror_status |= MIRROR_READ_ONLY_BIT; + lpart->partition_type = part_info.partition_type & 0xFF; + lpart->rpart_handle = handles[j]; + lpart->physical_block_count = part_info.sector_count >> (12 - part_info.sector_size_shift); + lpart->sectors_per_block = 1 << (12 - part_info.sector_size_shift); + lpart->sector_size_shift = part_info.sector_size_shift; + nwvp_hotfix_scan(lpart); + lpart->mirror_status |= MIRROR_NEW_BIT; + lpart->mirror_status |= MIRROR_PRESENT_BIT; + nwvp_log(NWLOG_DEVICE_ONLINE, lpart->lpartition_handle, lpart->rpart_handle, 0); + nwvp_mirror_group_establish(lpart->primary_link, 0); + } + lpart->scan_flag = 0; + break; + } + } + else + { + lpart->scan_flag = 0; + break; + } + } + else + { + free_slot = i; + } + } + + if (i == raw_partition_table_count) + { + if (free_slot == 0xFFFFFFFF) + { + free_slot = raw_partition_table_count; + raw_partition_table_count ++; + } + + nwvp_alloc((void *) &lpart, sizeof(nwvp_lpart)); + nwvp_memset(lpart, 0, sizeof(nwvp_lpart)); + nwvp_alloc((void *) &lpart->netware_mirror_sector, 512); + nwvp_alloc((void *) &lpart->mirror_sector, 512); + nwvp_memmove(lpart->netware_mirror_sector, &temp_buffer[512], 512); + nwvp_memmove(lpart->mirror_sector, &temp_buffer[1024], 512); + + if ((part_info.partition_type & 0x80000000) != 0) + lpart->mirror_status |= MIRROR_READ_ONLY_BIT; + + raw_partition_table[free_slot] = lpart; + lpart->remirror_section = 0xFFFFFFFF; + lpart->lpartition_handle = 0xFFFFFFFF; + lpart->low_level_handle = part_info.low_level_handle; + lpart->primary_link = lpart; + lpart->mirror_link = lpart; + lpart->mirror_partition_id = partition_id; + lpart->mirror_group_id = group_id; + lpart->rpartition_handle = ((handle_instance ++) << 16) + free_slot; + lpart->partition_type = part_info.partition_type; + lpart->rpart_handle = handles[j]; + lpart->physical_block_count = part_info.sector_count >> (12 - part_info.sector_size_shift); + lpart->sectors_per_block = 1 << (12 - part_info.sector_size_shift); + lpart->sector_size_shift = part_info.sector_size_shift; +// if (nwvp_part_read(handles[j], lpart->physical_block_count * lpart->sectors_per_block, lpart->sectors_per_block, temp_buffer) != 0) +// nwvp_part_write(handles[j], lpart->physical_block_count * lpart->sectors_per_block, lpart->sectors_per_block, temp_buffer); + if ((partition_id != 0xFFFFFFFF) && (scan_flag == 0)) + { + nwvp_hotfix_scan(lpart); + lpart->mirror_status |= MIRROR_PRESENT_BIT; + nwvp_log(NWLOG_DEVICE_ONLINE, lpart->lpartition_handle, lpart->rpart_handle, 0); + nwvp_mirror_group_add(lpart); + nwvp_mirror_group_establish(lpart->primary_link, 0); + } + else + { + lpart->mirror_status |= MIRROR_PRESENT_BIT; + nwvp_log(NWLOG_DEVICE_ONLINE, lpart->lpartition_handle, lpart->rpart_handle, 0); + } + } + } + } + } while ((payload.payload_index != 0) && (payload.payload_object_count != 0)); + + for (i=0; iscan_flag != 0) + { + raw_partition_table[i]->scan_flag = 0; + raw_partition_table[i]->rpart_handle = 0xFFFFFFFF; + if (raw_partition_table[i]->mirror_status & MIRROR_PRESENT_BIT) + nwvp_log(NWLOG_DEVICE_OFFLINE, raw_partition_table[i]->lpartition_handle, raw_partition_table[i]->rpart_handle, 0); + raw_partition_table[i]->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + if (raw_partition_table[i]->lpartition_handle != 0xFFFFFFFF) + { + if (nwvp_mirror_group_update(raw_partition_table[i]->primary_link) != 0) + { + nwvp_mirror_group_delete(raw_partition_table[i]); + } + } + else + { + if (raw_partition_table[i]->mirror_sector != 0) + { + nwvp_free(raw_partition_table[i]->mirror_sector); + raw_partition_table[i]->mirror_sector = 0; + } + if (raw_partition_table[i]->netware_mirror_sector != 0) + { + nwvp_free(raw_partition_table[i]->netware_mirror_sector); + raw_partition_table[i]->netware_mirror_sector = 0; + } + nwvp_free(raw_partition_table[i]); + raw_partition_table[i] = 0; + } + } + } + } + nwvp_io_free(temp_buffer); + NWUnlockNWVP(); +} + +void nwvp_unscan_routine() +{ + ULONG i; + + NWLockNWVP(); + for (i=0; i < virtual_partition_table_count; i++) + { + if (virtual_partition_table[i] != 0) + { + nwvp_free(virtual_partition_table[i]); + virtual_partition_table[i] = 0; + } + } + virtual_partition_table_count = 0; +#if !(LINUX_20 | LINUX_22 | LINUX_24) + NWUnlockNWVP(); + nwvp_quiese_remirroring(); + while (nwvp_remirror_control_list_head != 0) + { + nwvp_remirror_poll(); + + } + NWLockNWVP(); +#endif + for (i=0; imirror_status & MIRROR_PRESENT_BIT) + nwvp_log(NWLOG_DEVICE_OFFLINE, raw_partition_table[i]->lpartition_handle, raw_partition_table[i]->rpart_handle, 0); + raw_partition_table[i]->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + if (raw_partition_table[i]->lpartition_handle != 0xFFFFFFFF) + { + if (nwvp_mirror_group_update(raw_partition_table[i]->primary_link) != 0) + { + nwvp_mirror_group_delete(raw_partition_table[i]); + } + } + else + { + if (raw_partition_table[i]->mirror_sector != 0) + { + nwvp_free(raw_partition_table[i]->mirror_sector); + raw_partition_table[i]->mirror_sector = 0; + } + if (raw_partition_table[i]->netware_mirror_sector != 0) + { + nwvp_free(raw_partition_table[i]->netware_mirror_sector); + raw_partition_table[i]->netware_mirror_sector = 0; + } + nwvp_free(raw_partition_table[i]); + raw_partition_table[i] = 0; + } + } + } + raw_partition_table_count = 0; + + for (i=0; i= logical_partition_table_count) + { + NWUnlockNWVP(); + return(-1); + + } + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) == 0) || + (lpart->lpartition_handle != lpart_handle)) + { + NWUnlockNWVP(); + return(-1); + } + if (nwvp_mirror_group_remirror_check(lpart, block_number >> 10, reset_flag) != 0) + { + NWUnlockNWVP(); + return(-1); + } + if (*reset_flag != 0) + { + NWUnlockNWVP(); + return(0); + } + if (block_number >= lpart->logical_block_count) + { + NWUnlockNWVP(); + return(0); + } + mirror_count = lpart->mirror_count; + temp = lpart; + do + { + if (temp->mirror_sector_index == index) + break; + temp = temp->mirror_link; + } while (temp != lpart); + + if (temp->mirror_sector_index != index) + { + NWUnlockNWVP(); + return(-1); + } + + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + if (buffer_valid == 0) + { + NWUnlockNWVP(); + if (inwvp_lpartition_specific_read(temp, block_number, 1, buffer1) != 0) + return(-1); + NWLockNWVP(); + buffer_valid = 1; + } + else + { + NWUnlockNWVP(); + if (inwvp_lpartition_specific_read(temp, block_number, 1, buffer2) != 0) + return(-1); + NWLockNWVP(); + if (nwvp_memcomp(buffer1, buffer2, 4096) != 0) + { + NWUnlockNWVP(); + return(-1); + } + } + } + index ++; + if (index >= mirror_count) + break; + } + NWUnlockNWVP(); + return(0); +} + + +ULONG nwvp_mirror_block_remirror( + ULONG lpart_handle, + ULONG block_number, + BYTE *buffer1, + BYTE *buffer2, + ULONG *reset_flag) +{ + nwvp_lpart *lpart; + nwvp_lpart *temp; + ULONG mirror_count; + ULONG index = 0; + ULONG read_index = 0; + ULONG buffer_valid = 0; + + *reset_flag = 0; + NWLockNWVP(); + while (1) + { + if ((lpart_handle & 0x0000FFFF) >= logical_partition_table_count) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 1 %x/n", (int) block_number); +#endif + NWUnlockNWVP(); + return(-1); + + } + if (((lpart = logical_partition_table[lpart_handle & 0x0000FFFF]) == 0) || + (lpart->lpartition_handle != lpart_handle)) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 2 %x/n", (int) block_number); +#endif + NWUnlockNWVP(); + return(-1); + } + if (nwvp_mirror_group_remirror_check(lpart, block_number >> 10, reset_flag) != 0) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 3 %x/n", (int) block_number); +#endif + NWUnlockNWVP(); + return(-1); + } + if (*reset_flag != 0) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 4 %x/n", (int) block_number); +#endif + NWUnlockNWVP(); + return(0); + } + + if ((lpart->mirror_status & MIRROR_GROUP_REMIRRORING_BIT) == 0) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 5 %x/n", (int) block_number); +#endif + NWUnlockNWVP(); + return(-1); + } + + mirror_count = lpart->mirror_count; + if (buffer_valid == 0) + { + temp = lpart; + do + { + if (temp->mirror_sector_index == index) + { + if (((temp->mirror_status & MIRROR_INSYNCH_BIT) != 0) && + ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) && + (temp->remirror_section == 0)) + { + NWUnlockNWVP(); + if (inwvp_lpartition_specific_read(temp, block_number, 1, buffer1) != 0) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 6 %x/n", (int) block_number); +#endif + return(-1); + } + NWLockNWVP(); + buffer_valid = 0xFFFFFFFF; + read_index = index; + index = 0; + } + break; + } + temp = temp->mirror_link; + } while (temp != lpart); + + if (buffer_valid == 0) + { + if (temp->mirror_sector_index != index) + break; + index ++; + if (index >= mirror_count) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint(" remirror block 7 %x/n", (int) block_number); +#endif + NWUnlockNWVP(); + return(-1); + } + } + } + else + { + temp = lpart; + do + { + if (temp->mirror_sector_index == index) + { + if (index != read_index) + { + if ((temp->mirror_status & MIRROR_PRESENT_BIT) != 0) + { + + if (((temp->mirror_status & MIRROR_INSYNCH_BIT) == 0) || + (temp->remirror_section > (block_number >> 10))) + { + NWUnlockNWVP(); + if (inwvp_lpartition_specific_write(temp, block_number, 1, buffer1) != 0) + { + return(-1); + } + NWLockNWVP(); + } + } + } + break; + } + temp = temp->mirror_link; + } while (temp != lpart); + + if (temp->mirror_sector_index != index) + break; + index ++; + if (index >= mirror_count) + break; + } + } + NWUnlockNWVP(); + return(0); +} + + +ULONG nwvp_remirror_poll() +{ + ULONG reset_flag = 0; + nwvp_remirror_control *control; + nwvp_lpart *lpart; + nwvp_lpart *temp; + + NWLockNWVP(); + if ((control = nwvp_remirror_control_list_head) != 0) + { + nwvp_remirror_control_list_head = control->next_link; + + if (control->abort_flag != 0) + { + if (nwvp_remirror_control_list_head == control) + { + if ((nwvp_remirror_control_list_head = control->next_link) == control) + nwvp_remirror_control_list_head = 0; + } + else + { + control->next_link->last_link = control->last_link; + control->last_link->next_link = control->next_link; + } + if ((control->lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[control->lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == control->lpart_handle)) + { + temp = lpart; + do + { + temp->mirror_status &= ~MIRROR_REMIRRORING_BIT; + temp = temp->mirror_link; + } while (temp != lpart); + lpart->mirror_status &= ~MIRROR_GROUP_REMIRRORING_BIT; + nwvp_log(NWLOG_REMIRROR_ABORT, lpart->lpartition_handle, control->section, 0); + nwvp_mirror_group_close(lpart); + } + } + NWUnlockNWVP(); +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint("1 returning remirror control structure %08X\n", (int) control); +#endif + nwvp_free(control); + return(0); + } + + NWUnlockNWVP(); + switch(control->state) + { + case NWVP_VALIDATE_PHASE: + while ((control->valid_bits[control->index/8] & (1 << (control->index % 8))) != 0) + { + control->index ++; + if (control->index == 1024) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint("validate phase complete %08X\n", (int) control->section); +#endif + break; + } + } + if (control->index < 1024) + { + if (nwvp_mirror_block_validate(control->lpart_handle, control->index + (control->section << 10), remirror_buffer1, remirror_buffer2, &reset_flag) == 0) + { + if (reset_flag != 0) + { + nwvp_memset(&control->valid_bits[0], 0, 1024 / 8); + control->index = 0; + control->check_flag = 0; + control->remirror_flag = 0; + control->state = NWVP_VALIDATE_PHASE; + control->section = control->original_section; + break; + } + else + { + control->valid_bits[control->index/8] |= 1 << (control->index % 8); + } + } + else + { + control->check_flag = 1; + } + control->index ++; + } + if ((control->index & 0xFF) == 0xFF) + nwvp_thread_delay(nwvp_remirror_delay); + if (control->index == 1024) + { + control->state = (control->check_flag == 0) ? NWVP_UPDATE_PHASE : NWVP_REMIRROR_PHASE; + control->index = 0; + control->check_flag = 0; + } + break; + case NWVP_REMIRROR_PHASE: + while ((control->valid_bits[control->index/8] & (1 << (control->index % 8))) != 0) + { + control->index ++; + if (control->index == 1024) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint("remirror phase complete %08X\n", (int) control->section); +#endif + break; + } + } + if (control->index < 1024) + { + if (nwvp_mirror_block_remirror(control->lpart_handle, control->index + (control->section << 10), remirror_buffer1, remirror_buffer2, &reset_flag) == 0) + { + if (reset_flag != 0) + { +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint("remirror reset called %08X\n", (int) control->section); +#endif + + nwvp_memset(&control->valid_bits[0], 0, 1024 / 8); + control->index = 0; + control->check_flag = 0; + control->remirror_flag = 0; + control->state = NWVP_VALIDATE_PHASE; + control->section = control->original_section; + break; + } + } + else + { + control->abort_flag = 0xFFFFFFFF; + } + control->index ++; + } + if (control->index == 1024) + { + control->index = 0; + control->check_flag = 0; + control->state = NWVP_VALIDATE_PHASE; + } + break; + case NWVP_UPDATE_PHASE: +#if (DEBUG_MIRRORING) + NWFSPrint("update phase active control-%08X control->section-%08X\n", + (unsigned)control, (unsigned)control->section); +#endif + + if (nwvp_mirror_group_remirror_update(control->lpart_handle, control->section, &reset_flag) != 0) + { + control->abort_flag = 0xFFFFFFFF; + break; + } + if (reset_flag != 0) + { + nwvp_memset(&control->valid_bits[0], 0, 1024 / 8); + control->index = 0; + control->check_flag = 0; + control->remirror_flag = 0; + control->state = NWVP_VALIDATE_PHASE; + control->section = control->original_section; + break; + } + if (control->section == 0) + { + NWLockNWVP(); + if (control == nwvp_remirror_control_list_head) + { + if ((nwvp_remirror_control_list_head = control->next_link) == control) + nwvp_remirror_control_list_head = 0; + } + else + { + + control->next_link->last_link = control->last_link; + control->last_link->next_link = control->next_link; + } + if ((control->lpart_handle & 0x0000FFFF) < logical_partition_table_count) + { + if (((lpart = logical_partition_table[control->lpart_handle & 0x0000FFFF]) != 0) && + (lpart->lpartition_handle == control->lpart_handle)) + { + temp = lpart; + do + { + temp->mirror_status &= ~MIRROR_REMIRRORING_BIT; + temp = temp->mirror_link; + } while (temp != lpart); + lpart->mirror_status &= ~MIRROR_GROUP_REMIRRORING_BIT; + lpart->mirror_status &= ~MIRROR_GROUP_CHECK_BIT; + nwvp_log(NWLOG_REMIRROR_COMPLETE, lpart->lpartition_handle, control->section, 0); + nwvp_mirror_group_close(lpart); + } + } + NWUnlockNWVP(); +#if (DEBUG_MIRROR_CONTROL) + NWFSPrint("2 returning remirror control structure %08X\n", (int) control); +#endif + nwvp_free(control); + break; + } + nwvp_memset(&control->valid_bits[0], 0, 1024 / 8); + control->index = 0; + control->check_flag = 0; + control->remirror_flag = 0; + control->state = NWVP_VALIDATE_PHASE; + control->section --; + break; + } + return(0); + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_mirror_validate_process_done = 0; + +ULONG nwvp_mirror_validate_process() +{ + NWLockREMIRROR(); + while (nwvp_mirror_validate_process_done == 0) + { + while (nwvp_remirror_poll() == 0); + NWLockREMIRROR(); + } + return(0); +} + +ULONG nwvp_map_volume_physical( + ULONG vpart_handle, + ULONG SectorOffsetInVolume, + ULONG SectorCount, + void **PartitionPointer, + ULONG *SectorOffsetInPartition, + ULONG *SectorsReturned) +{ + ULONG i, j; + ULONG bad_bits; + ULONG count; + ULONG relative_offset; + ULONG relative_block; + ULONG relative_count; + ULONG block_number; + nwvp_lpart *lpart; + nwvp_lpart *original_part; + nwvp_vpartition *vpartition; + + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle)) + { + if (vpartition->open_flag != 0) + { + relative_block = SectorOffsetInVolume / 8; + relative_offset = SectorOffsetInVolume % 8; + relative_count = (relative_offset + SectorCount + 7) / 8; + for (i=0; isegment_count; i++) + { + if (relative_block < vpartition->segments[i].segment_block_count) + { + if ((vpartition->segments[i].segment_block_count - relative_block) < relative_count) + relative_count = vpartition->segments[i].segment_block_count - relative_block; + + block_number = relative_block + vpartition->segments[i].partition_block_offset; + original_part = vpartition->segments[i].lpart_link; + count = (original_part->read_round_robin ++) & 0x3; + for (j=0; j< count; j++) + original_part = original_part->mirror_link; + + lpart = original_part; + do + { + if (((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) && + ((lpart->mirror_status & MIRROR_INSYNCH_BIT) != 0)) + { + for (j=0; jhotfix.bit_table[(block_number + j) >> 15][((block_number + j) >> 5) & 0x3FF] & (1 << ((block_number + j) & 0x1F))) + break; + } + if (j == relative_count) + { + *SectorOffsetInPartition = ((block_number + lpart->hotfix.block_count) * 8) + relative_offset; + *SectorsReturned = (relative_count * 8) - relative_offset; + *PartitionPointer = (void *) lpart->rpart_handle; + return(0); + } + } + lpart = lpart->mirror_link; + } while (lpart != original_part); + +// +// there are one or more hotfixed blocks in this region +// + + do + { + if (((lpart->mirror_status & MIRROR_PRESENT_BIT) != 0) && + ((lpart->mirror_status & MIRROR_INSYNCH_BIT) != 0)) + { + for (j=0; jhotfix.bit_table[(block_number + j) >> 15][((block_number + j) >> 5) & 0x3FF] & (1 << ((block_number + j) & 0x1F))) + { + if (j == 0) + { + nwvp_hotfix_block_lookup(lpart, block_number, &relative_block, &bad_bits); + *SectorOffsetInPartition = (relative_block * 8) + relative_offset; + *SectorsReturned = 8 - relative_offset; + *PartitionPointer = (void *) lpart->rpart_handle; + return((bad_bits == 0) ? 0 : -1); + } + else + { + *SectorOffsetInPartition = ((block_number + lpart->hotfix.block_count) * 8) + relative_offset; + *SectorsReturned = (j * 8) - relative_offset; + *PartitionPointer = (void *) lpart->rpart_handle; + return(0); + } + } + } + } + lpart = lpart->mirror_link; + } while (lpart != original_part); + +// +// the code should never reach this point +// + } + relative_block -= vpartition->segments[i].segment_block_count; + } + } + } + } + return (-1); +} + + +ULONG nwvp_get_physical_partitions( + ULONG vpart_handle, + ULONG *ppartition_table_count, + ULONG *ppartition_table) +{ + ULONG i; + nwvp_vpartition *vpartition; + + NWLockNWVP(); + if ((vpart_handle & 0x0000FFFF) < virtual_partition_table_count) + { + if (((vpartition = virtual_partition_table[vpart_handle & 0x0000FFFF]) != 0) && + (vpartition->vpartition_handle == vpart_handle) && + (vpartition->volume_valid_flag == 0)) + { + for (i=0; isegment_count; i++) + { + ppartition_table[i] = vpartition->segments[i].lpart_link->rpartition_handle; + } + *ppartition_table_count = i; + NWUnlockNWVP(); + return(0); + + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_convert_local_handle( + ULONG rpart_handle, + ULONG *NT_handle) +{ + nwvp_lpart *lpartition; + + NWLockNWVP(); + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((lpartition = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (lpartition->rpartition_handle == rpart_handle)) + { + *NT_handle = lpartition->low_level_handle; + return(0); + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_hotfix_table_check( + ULONG rpart_handle, + ULONG index, + ULONG *value) +{ + ULONG *table; + nwvp_lpart *lpart; + + NWLockNWVP(); + if ((rpart_handle & 0x0000FFFF) < raw_partition_table_count) + { + if (((lpart = raw_partition_table[rpart_handle & 0x0000FFFF]) != 0) && + (lpart->rpartition_handle == rpart_handle) && + (index < lpart->hotfix.block_count)) + { + if ((table = lpart->hotfix.hotfix_table[index >> 10]) != 0) + { + *value = table[index & 0x3FF]; + NWUnlockNWVP(); + return(0); + } + } + } + NWUnlockNWVP(); + return(-1); +} + +ULONG nwvp_nt_partition_shutdown( + ULONG low_level_handle) +{ + ULONG i; + + NWLockNWVP(); + for (i=0; ilow_level_handle == low_level_handle)) + { + raw_partition_table[i]->rpart_handle = 0xFFFFFFFF; + if (raw_partition_table[i]->mirror_status & MIRROR_PRESENT_BIT) + nwvp_log(NWLOG_DEVICE_OFFLINE, raw_partition_table[i]->lpartition_handle, raw_partition_table[i]->rpart_handle, 0); + raw_partition_table[i]->mirror_status &= ~(MIRROR_PRESENT_BIT | MIRROR_REMIRRORING_BIT); + if (raw_partition_table[i]->lpartition_handle != 0xFFFFFFFF) + { + if (nwvp_mirror_group_update(raw_partition_table[i]->primary_link) != 0) + { + nwvp_mirror_group_delete(raw_partition_table[i]); + } + NWUnlockNWVP(); + return(0); + } + } + } + NWUnlockNWVP(); + return(-1); +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvp.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvp.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvp.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,811 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +*************************************************************************** +* +* AUTHOR : Darren Major and Jeff V. Merkey +* FILE : NWVP.H +* DESCRIP : NetWare Virtual Partition +* DATE : August 1, 1999 +* +***************************************************************************/ + +extern BYTE *bit_bucket_buffer; +#define NWVP_ERROR_DATA_VALID 0 +#define NWVP_ERROR_DATA_INVALID 1 +#define NWVP_ERROR_NOT_PRESENT -2 +#define NWVP_ERROR_INVALID_INDEX -3 +#define NWLOG_REMIRROR_START 0x54525453 +#define NWLOG_REMIRROR_START_ERROR 0x45525453 +#define NWLOG_REMIRROR_STOP 0x504F5453 +#define NWLOG_REMIRROR_STOP_ERROR 0x45505453 +#define NWLOG_REMIRROR_RESET1 0x31534552 +#define NWLOG_REMIRROR_RESET2 0x32534552 +#define NWLOG_REMIRROR_RESET3 0x33534552 +#define NWLOG_REMIRROR_ABORT 0x54524241 +#define NWLOG_REMIRROR_COMPLETE 0x504D4F43 +#define NWLOG_DEVICE_OFFLINE 0x4C46464F +#define NWLOG_DEVICE_ONLINE 0x4E4C4E4F +#define NWLOG_DEVICE_INSYNCH 0x434C5953 +#define NWLOG_DEVICE_OUT_OF_SYNCH 0x4C59534F + +#define FFIX_NULL_NULL 0x0000 +#define FFIX_NULL_EOF 0x0001 +#define FFIX_NULL_SA 0x0010 +#define FFIX_NULL_FAT 0x0011 +#define FFIX_EOF_NULL 0x0100 +#define FFIX_EOF_EOF 0x0101 +#define FFIX_EOF_SA 0x0110 +#define FFIX_EOF_FAT 0x0111 +#define FFIX_SA_NULL 0x1000 +#define FFIX_SA_EOF 0x1001 +#define FFIX_SA_SA 0x1010 +#define FFIX_SA_FAT 0x1011 +#define FFIX_FAT_NULL 0x1100 +#define FFIX_FAT_EOF 0x1101 +#define FFIX_FAT_SA 0x1110 +#define FFIX_FAT_FAT 0x1111 + +extern void mem_check_init(void); +extern void mem_check_uninit(void); + +#define NWVP_HOTFIX_READ 0x11111111 +#define NWVP_HOTFIX_WRITE 0x22222222 +#define NWVP_HOTFIX_FORCE 0x33333333 +#define NWVP_HOTFIX_FORCE_BAD 0x44444444 + + +#define NWVP_MIRROR_STATUS_OPENED 0x4E45504F +#define NWVP_MIRROR_STATUS_CLOSED 0x534F4C43 +#define NWVP_MIRROR_STATUS_CHECK 0x4B454843 +#define NWVP_MIRROR_STATUS_REMOVED 0x4F4D4552 +#define NWVP_MIRROR_STATUS_BAD 0x4C444142 + +//#define NWVPMIRR_GROUP_OPERATIONAL 0x00010000 +//#define NWVPMIRR_GROUP_COMPLETE 0x00020000 + +#define NETWARE_IN_SYNCH_INSTANCE 0x01860000 +#define NETWARE_OUT_OF_SYNCH_INSTANCE 0x01850000 +#define NETWARE_INUSE_BIT 0x00000100 +#define NETWARE_OUT_OF_SYNCH_BIT 0x00000002 +#define NETWARE_5_BASE_BIT 0x00010000 + +#define RPART_ERROR_IO 1 +#define RPART_ONLINE 1 +#define RPART_OFFLINE 0 +#define NWVP_READWRITE_BUFFER_SIZE 16384 + + +#define INUSE_BIT 0x80000000 +#define MIRROR_BIT 0x00080000 + +typedef struct _nwvp_asynch_map +{ + ULONG sector_offset; + ULONG disk_id; + ULONG bad_bits; + ULONG extra; +} nwvp_asynch_map; + +typedef struct segment_info_def +{ + ULONG lpartition_id; + ULONG block_offset; + ULONG block_count; + ULONG extra; +} segment_info; + +typedef struct vpartition_info_def +{ + BYTE volume_name[16]; + ULONG blocks_per_cluster; + ULONG cluster_count; + ULONG segment_count; + ULONG flags; +} vpartition_info; + +typedef struct nwvp_remirror_message_def +{ + struct nwvp_remirror_message_def *next_link; + ULONG return_code; + ULONG block_number; + ULONG block_count; + + BYTE *data_buffer; + ULONG thread_id; + ULONG filler[3]; +} nwvp_remirror_message; + +typedef struct nwvp_mirror_sector_def +{ + BYTE nwvp_mirror_stamp[16]; + ULONG mirror_id; + ULONG time_stamp; + ULONG modified_stamp; + ULONG table_index; + struct + { + ULONG partition_id; + ULONG time_stamp; + ULONG remirror_section; + ULONG status; + }log[30]; +} nwvp_mirror_sector; + +#define MIRROR_NEW_BIT 0x00000001 +#define MIRROR_PRESENT_BIT 0x00000002 +#define MIRROR_INSYNCH_BIT 0x00000004 +#define MIRROR_DELETED_BIT 0x00000008 +#define MIRROR_REMIRRORING_BIT 0x00000010 +#define MIRROR_READ_ONLY_BIT 0x00000020 + +#define MIRROR_GROUP_ESTABLISHED_BIT 0x00010000 +#define MIRROR_GROUP_ACTIVE_BIT 0x00020000 +#define MIRROR_GROUP_OPEN_BIT 0x00040000 +#define MIRROR_GROUP_MODIFY_CHECK_BIT 0x00080000 +#define MIRROR_GROUP_REMIRRORING_BIT 0x00100000 +#define MIRROR_GROUP_CHECK_BIT 0x00200000 +#define MIRROR_GROUP_READ_ONLY_BIT 0x00400000 + +typedef struct nwvp_rpartition_scan_info_def +{ + ULONG rpart_handle; + ULONG physical_block_count; + ULONG lpart_handle; + ULONG partition_type; +} nwvp_rpartition_scan_info; + +typedef struct nwvp_rpartition_info_def +{ + ULONG rpart_handle; + ULONG lpart_handle; + ULONG physical_block_count; + ULONG partition_type; + ULONG physical_handle; + ULONG physical_disk_number; + ULONG partition_offset; + ULONG partition_number; + ULONG status; +} nwvp_rpartition_info; + +typedef struct nwvp_lpart_def +{ + ULONG rpartition_handle; + ULONG lpartition_handle; + ULONG lpartition_type; + ULONG partition_type; + ULONG mirror_partition_id; + ULONG mirror_group_id; + ULONG open_count; + ULONG read_round_robin; + ULONG rpart_handle; + ULONG low_level_handle; + ULONG remirror_section; + nwvp_remirror_message *remirror_list_head; + nwvp_remirror_message *remirror_list_tail; + ULONG remirror_spin_lock; + ULONG physical_block_count; + ULONG logical_block_count; + ULONG minimum_segment_size; + ULONG maximum_segment_size; + ULONG available_capacity; + ULONG sectors_per_block; + ULONG sector_size_shift; + struct + { + ULONG block_count; + ULONG **bit_table; + ULONG **hotfix_table; + ULONG **bad_bit_table; + HOTFIX *sector; + } hotfix; + + ULONG scan_flag; + ULONG mirror_status; + ULONG mirror_count; + ULONG mirror_sector_index; + struct nwvp_lpart_def *primary_link; + struct nwvp_lpart_def *mirror_link; + nwvp_mirror_sector *mirror_sector; + MIRROR *netware_mirror_sector; + VOLUME_TABLE *segment_sector; +} nwvp_lpart; + +typedef struct nwvp_lpartition_scan_info_def +{ + ULONG lpart_handle; + ULONG logical_block_count; + ULONG open_flag; + ULONG mirror_status; +} nwvp_lpartition_scan_info; + +typedef struct nwvp_lpartition_space_return_info_Def +{ + ULONG lpart_handle; + ULONG segment_offset; + ULONG segment_count; + ULONG status_bits; +} nwvp_lpartition_space_return_info; + +typedef struct nwvp_lpartition_info_def +{ + ULONG lpartition_handle; + ULONG lpartition_type; + ULONG lpartition_status; + ULONG open_count; + ULONG segment_count; + ULONG mirror_count; + ULONG logical_block_count; + struct + { + ULONG rpart_handle; + ULONG hotfix_block_count; + ULONG status; + ULONG extra; + } m[8]; +} nwvp_lpartition_info; + +typedef struct nwvp_vpartition_def +{ + ULONG vpartition_handle; + ULONG vpartition_type; + ULONG volume_valid_flag; + ULONG open_flag; + BYTE volume_name[16]; + ULONG mirror_flag; + ULONG blocks_per_cluster; + ULONG segment_count; + ULONG cluster_count; + ULONG FAT1; + ULONG FAT2; + ULONG Directory1; + ULONG Directory2; + struct + { + ULONG volume_entry_index; + ULONG segment_block_count; + ULONG partition_block_offset; + ULONG relative_cluster_offset; + nwvp_lpart *lpart_link; + } segments[32]; +} nwvp_vpartition; + +typedef struct nwvp_vpartition_info_def +{ + ULONG vpartition_handle; + ULONG vpartition_type; + ULONG volume_valid_flag; + ULONG open_flag; + BYTE volume_name[16]; + ULONG mirror_flag; + ULONG segment_count; + ULONG cluster_count; + ULONG blocks_per_cluster; + ULONG vpart_handle; + ULONG FAT1; + ULONG FAT2; + ULONG Directory1; + ULONG Directory2; + struct + { + ULONG segment_block_count; + ULONG partition_block_offset; + ULONG relative_cluster_offset; + ULONG lpart_handle; + } segments[32]; +} nwvp_vpartition_info; + +extern ULONG virtual_partition_table_count; +extern nwvp_vpartition *virtual_partition_table[256]; + +typedef struct nwvp_block_map_def +{ + ULONG rpart_handle; + ULONG block_offset; + ULONG block_count; + ULONG block_bad_bits; +} nwvp_block_map; + +#define NWVP_VALIDATE_PHASE 0 +#define NWVP_REMIRROR_PHASE 1 +#define NWVP_UPDATE_PHASE 2 +#define NWVP_ABORT_PHASE 3 + +typedef struct nwvp_remirror_control_def +{ + struct nwvp_remirror_control_def *next_link; + struct nwvp_remirror_control_def *last_link; + ULONG state; + ULONG index; + ULONG section; + ULONG original_section; + ULONG abort_flag; + ULONG lpart_handle; + ULONG check_flag; + ULONG remirror_flag; + BYTE valid_bits[1024 / 8]; +} nwvp_remirror_control; + +typedef struct nwvp_mismatch_def +{ + struct nwvp_mismatch_def *next_link; + struct nwvp_mismatch_def *last_link; + ULONG block_number; + nwvp_lpart *lpart; + ULONG fat_block_number; + ULONG *fat_block1; + ULONG *fat_block2; + ULONG extra; +} nwvp_mismatch; + +typedef struct nwvp_fat_fix_info_def +{ + ULONG total_fat_blocks; + ULONG total_valid_mirror_blocks; + ULONG total_valid_single_blocks; + ULONG total_missing_blocks; + ULONG total_mismatch_blocks; + + ULONG total_entries; + ULONG total_index_mismatch_entries; + ULONG total_end_null_entries; + ULONG total_SA_null_entries; + ULONG total_FAT_null_entries; + ULONG total_SA_end_entries; + ULONG total_SA_FAT_entries; + ULONG total_SA_mismatch_entries; + ULONG total_FAT_end_entries; + ULONG total_FAT_mismatch_entries; +} nwvp_fat_fix_info; + +#define NWVP_EXTENT_TABLE_SIZE 200 + +typedef struct nwvp_file_extent_def +{ + struct nwvp_file_extent_def *next_link; + ULONG directory_info[23]; + ULONG table_index; + struct + { + ULONG file_offset; + ULONG sector_count; + ULONG partition_offset; + ULONG partition_handle; + } table[NWVP_EXTENT_TABLE_SIZE]; +} nwvp_file_extent; + +void nwvp_init(void); + +void nwvp_uninit(void); + +ULONG nwvp_segmentation_remove( + nwvp_lpart *lpart); + +ULONG nwvp_segmentation_add( + nwvp_lpart *lpart); + +ULONG nwvp_create_new_id(void); + +ULONG nwvp_hotfix_destroy( + nwvp_lpart *lpart); + +ULONG nwvp_segmentation_sectors_flush( + nwvp_lpart *lpart); + +ULONG nwvp_segmentation_sector_validate( + VOLUME_TABLE *seg_sector); + +ULONG nwvp_segmentation_sectors_load( + nwvp_lpart *lpart); + +ULONG nwvp_master_sectors_flush( + nwvp_lpart *lpart); + +ULONG nwvp_netware_mirror_update( + nwvp_lpart *lpart, + ULONG flush_flag); + +ULONG nwvp_hotfix_tables_flush( + nwvp_lpart *lpart, + ULONG table_index); + +ULONG nwvp_hotfix_tables_load( + nwvp_lpart *lpart); + +ULONG nwvp_hotfix_tables_alloc( + nwvp_lpart *lpart); + +ULONG nwvp_hotfix_tables_free( + nwvp_lpart *lpart); + +ULONG nwvp_hotfix_scan( + nwvp_lpart *lpart); + +ULONG nwvp_hotfix_create( + nwvp_lpart *lpart, + ULONG logical_block_count); + +ULONG nwvp_hotfix_block_lookup( + nwvp_lpart *lpart, + ULONG block_number, + ULONG *relative_block_number, + ULONG *bad_bits); + +ULONG nwvp_hotfix_block( + nwvp_lpart *original_part, + ULONG original_block_number, + BYTE *original_buffer, + ULONG *original_bad_bits, + ULONG read_flag); + +ULONG nwvp_hotfix_update_bad_bits( + nwvp_lpart *original_part, + ULONG original_block_number, + ULONG original_bad_bits); + + + +ULONG nwvp_mirror_create_entry( + nwvp_lpart *lpart, + ULONG mirror_sector_index, + ULONG partition_id, + ULONG group_id); + +void nwvp_mirror_group_establish( + nwvp_lpart *lpart, + ULONG hard_activate_flag); + +ULONG nwvp_mirror_group_modify_check( + nwvp_lpart *lpart); + +ULONG nwvp_mirror_group_remirror_update( + ULONG lpart_handle, + ULONG section, + ULONG *reset_flag); + +ULONG nwvp_mirror_group_add( + nwvp_lpart *lpart); + +void nwvp_mirror_group_delete( + nwvp_lpart *member); + +ULONG nwvp_mirror_group_update( + nwvp_lpart *member); + +ULONG nwvp_mirror_member_add( + nwvp_lpart *mpart, + nwvp_lpart *new_part); + +ULONG nwvp_mirror_member_delete( + nwvp_lpart *del_part); + +ULONG nwvp_mirror_group_open( + nwvp_lpart *lpart); + +ULONG nwvp_mirror_group_close( + nwvp_lpart *lpart); + +ULONG nwvp_rpartition_sector_read( + ULONG rpart_handle, + ULONG sector_number, + ULONG sector_count, + BYTE *data_buffer); + +ULONG nwvp_rpartition_sector_write( + ULONG rpart_handle, + ULONG sector_number, + ULONG sector_count, + BYTE *data_buffer); + +/* +ULONG nwvp_lpartition_open( + ULONG lpart_handle, + ULONG group_complete_flag); + +ULONG nwvp_lpartition_close( + ULONG lpart_handle); +*/ + +ULONG nwvp_lpartition_activate( + ULONG lpart_handle); + +ULONG inwvp_lpartition_block_read( + nwvp_lpart *original_part, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + +ULONG nwvp_lpartition_block_read( + ULONG lpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + +ULONG inwvp_lpartition_block_write( + nwvp_lpart *original_part, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + +ULONG nwvp_lpartition_block_write( + ULONG lpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + + +ULONG nwvp_vpartition_sub_block_read( + ULONG vpart_handle, + ULONG block_number, + ULONG block_offset, + ULONG data_size, + BYTE *data_buffer, + ULONG as); + +ULONG nwvp_vpartition_map_asynch_read( + ULONG vpart_handle, + ULONG block_number, + ULONG *map_entry_count, + nwvp_asynch_map *map); + +ULONG nwvp_vpartition_block_read( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + +ULONG nwvp_vpartition_map_asynch_write( + ULONG vpart_handle, + ULONG block_number, + ULONG *map_entry_count, + nwvp_asynch_map *map); + +ULONG inwvp_vpartition_block_write( + nwvp_vpartition *vpartition, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + +ULONG nwvp_vpartition_sub_block_write( + ULONG vpart_handle, + ULONG block_number, + ULONG block_offset, + ULONG data_size, + BYTE *data_buffer, + ULONG as); + +ULONG nwvp_vpartition_bad_bit_update( + ULONG vpart_handle, + ULONG block_number, + ULONG new_bad_bits); + +ULONG nwvp_vpartition_block_write( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count, + BYTE *data_buffer); + +ULONG nwvp_vpartition_block_hotfix( + ULONG vpart_handle, + ULONG block_number, + BYTE *data_buffer); + +ULONG nwvp_vpartition_block_zero( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count); + +ULONG nwvp_rpartition_scan( + nwvp_payload *payload); + +ULONG nwvp_rpartition_return_info( + ULONG rpart_handle, + nwvp_rpartition_info *rpart_info); + +ULONG nwvp_rpartition_map_rpart_handle( + ULONG *rpart_handle, + ULONG physical_handle); + +ULONG nwvp_lpartition_scan( + nwvp_payload *payload); + +ULONG nwvp_lpartition_return_info( + ULONG lpart_handle, + nwvp_lpartition_info *lpart_info); + +ULONG nwvp_vpartition_scan( + nwvp_payload *payload); + +ULONG nwvp_vpartition_return_info( + ULONG vpart_handle, + nwvp_vpartition_info *vpinfo); + +ULONG nwvp_lpartition_return_space_info( + ULONG lpart_handle, + nwvp_payload *payload); + +ULONG nwvp_lpartition_format( + ULONG *lpartition_id, + ULONG logical_block_count, + ULONG *base_partition_ids); + +ULONG nwvp_lpartition_abort_remirror( + ULONG lpart_handle); + +ULONG nwvp_lpartition_remirror( + ULONG lpart_handle); + +ULONG nwvp_lpartition_unformat( + ULONG lpart_handle); + +ULONG nwvp_remirror_section( + nwvp_lpart *lpart, + ULONG section_number, + ULONG block_count, + BYTE *buffer); + +ULONG nwvp_mirror_validate_process(void); + +ULONG nwvp_partition_add_mirror( + ULONG lpart_handle, + ULONG rpart_handle); + +ULONG nwvp_partition_del_mirror( + ULONG lpart_handle, + ULONG rpart_handle); + +ULONG nwvp_bounds_check( + ULONG start1, + ULONG count1, + ULONG start2, + ULONG count2); + +ULONG nwvp_vpartition_fat_check( + ULONG vpart_handle); + +ULONG nwvp_vpartition_build_fat( + nwvp_vpartition *vpartition, + ULONG current_segment); + +ULONG nwvp_vpartition_segment_flush( + nwvp_vpartition *vpartition); + +ULONG vpartition_update_entry_index( + nwvp_lpart *lpart, + BYTE *volume_name, + ULONG old_index, + ULONG new_index); + +ULONG vpartition_update_lpartition( + nwvp_lpart *lpart, + nwvp_lpart *new_lpart); + +ULONG nwvp_vpartition_fat_fix( + ULONG vpart_handle, + nwvp_fat_fix_info *fix_info, + ULONG fix_flag); + +ULONG inwvp_vpartition_open( + nwvp_vpartition *vpartition); + +ULONG nwvp_vpartition_open( + ULONG vpart_handle); + +ULONG inwvp_vpartition_close( + nwvp_vpartition *vpartition); + +ULONG nwvp_vpartition_close( + ULONG vpart_handle); + +ULONG nwvp_vpartition_format( + ULONG *vpartition_id, + vpartition_info *vpart_info, + segment_info *segment_info_table); + +ULONG nwvp_vpartition_add_segment( + ULONG vpart_handle, + segment_info *segment_info_table); + +ULONG nwvp_vpartition_unformat( + ULONG vpart_handle); + +void nwvp_scan_routine( + ULONG scan_flag); + +void nwvp_unscan_routine(void); + +ULONG nwvp_map_volume_physical( + ULONG vpart_handle, + ULONG SectorOffsetInVolume, + ULONG SectorCount, + void **PartitionPointer, + ULONG *SectorOffsetInPartition, + ULONG *SectorsReturned); + + +void nwvp_log( + ULONG event_type, + ULONG handle, + ULONG parameter0, + ULONG parameter1); + +ULONG nwvp_get_physical_partitions( + ULONG vpart_handle, + ULONG *ppartition_table_count, + ULONG *ppartition_table); + +ULONG nwvp_convert_local_handle( + ULONG rpart_handle, + ULONG *NT_handle); + +ULONG nwvp_hotfix_table_check( + ULONG rpart_handle, + ULONG index, + ULONG *value); + +ULONG nwvp_part_map_to_physical( + ULONG rpart_handle, + ULONG *disk_id, + ULONG *disk_offset, + ULONG *partition_number); + +ULONG nwvp_nt_partition_shutdown( + ULONG low_level_handle); + +ULONG nwvp_alloc( + void **mem_ptr, + ULONG size); + +ULONG nwvp_io_alloc( + void **mem_ptr, + ULONG size); + +ULONG nwvp_io_free(void *mem_ptr); + +ULONG nwvp_free(void *mem_ptr); + +void nwvp_spin_lock( + ULONG *spin_lock); + +void nwvp_spin_unlock( + ULONG *spin_lock); + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvpext.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvpext.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvpext.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvpext.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,83 @@ + + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* +**************************************************************************** +* +* AUTHOR : Darren Major +* FILE : NWVP1.H +* DESCRIP : NetWare Virtual Partition +* DATE : August 1, 1999 +* +***************************************************************************/ + + +#define NWVP_HOTFIX_FOUND 1 +#define NWVP_VOLUMES_FOUND 2 +#define NWVP_FIRST_FAT_FOUND 3 + +typedef struct nwvp_hotfix_scan_info_def +{ + ULONG hotfix_partition_offset; + ULONG hotfix_data_offset; + ULONG hotfix_data_size; +} nwvp_hotfix_scan_info; + +typedef struct nwvp_volume_scan_info_def +{ + ULONG volume_sector_offset; + ULONG volume_segment_count; + struct + { + ULONG total_cluster_count; + ULONG segment_sector_offset; + ULONG segment_sector_count; + ULONG segment_info; + } segments[8]; +} nwvp_volume_scan_info; + +typedef struct nwvp_fat_scan_info_def +{ + ULONG complete_flag; + ULONG blocks_per_cluster; + ULONG DIR_cluster_count; + ULONG DIR1_cluster_offset; + ULONG DIR2_cluster_offset; + ULONG FAT_sector_offset; + ULONG FAT_cluster_count; + ULONG FAT1_cluster_offset; + ULONG FAT2_cluster_offset; +} nwvp_fat_scan_info; + +ULONG nwvp_FAT_compare( + FAT_ENTRY *fat1, + FAT_ENTRY *fat2, + ULONG mismatch_count); + +ULONG nwvp_recover_nwpart_info( + ULONG lpart_handle, + ULONG total_sector_count, + ULONG block_offset, + ULONG block_count, + nwvp_hotfix_scan_info *hotfix_info, + nwvp_volume_scan_info *volume_info, + nwvp_fat_scan_info *fat_info); + +ULONG inwvp_lpartition_block_map( + nwvp_lpart *original_part, + ULONG block_number, + ULONG block_count, + ULONG mirror_index, + nwvp_block_map *bmap); + +ULONG nwvp_vpartition_block_map( + ULONG vpart_handle, + ULONG block_number, + ULONG block_count, + ULONG mirror_index, + nwvp_block_map *bmap); + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvphal.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvphal.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvphal.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvphal.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,560 @@ +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +*************************************************************************** +* +* AUTHOR : Darren Major an Jeff V. Merkey +* FILE : NWVPHAL.C +* DESCRIP : NetWare Virtual Partition +* DATE : August 1, 1999 +* +***************************************************************************/ + +#include "globals.h" +#include "nwstruct.h" +#include "nwfs.h" +extern BYTE *zero_block_buffer; + + +typedef struct nwvp_rrpart_def +{ + ULONG vpart_handle; + ULONG rrpart_table_index; + ULONG scan_field; + ULONG capacity; + ULONG partition_offset; + ULONG sector_size_shift; + ULONG partition_type; + ULONG online_flag; + ULONG error_flag; + ULONG low_level_handle; + ULONG scan_flag; +} nwvp_rrpart; + +ULONG raw_instance = 0x10000000; +ULONG base_partition_table_count = 0; +nwvp_rrpart base_partition_table[MAX_PARTITIONS]; + +ULONG nwvp_part_scan( + nwvp_payload *req_payload) +{ + ULONG i, j, k; + ULONG *handle_ptr; + ULONG index; + ULONG object_count; + ULONG *hotfix_sector; + ULONG new_partition_flag; + + nwvp_io_alloc((void **) &hotfix_sector, 4096); + + ScanDiskDevices(); + for (k=0; kPartitionTable[i].nSectorsTotal) + { + for (k=0; kPartitionTable[i].SysFlag == 0x65) + { + ReadDiskSectors(j, SystemDisk[j]->PartitionTable[i].StartLBA + 0x20, (BYTE *) &hotfix_sector[0], 8, 8); + if (hotfix_sector[0] != 0x46544f48) + { + new_partition_flag = 1; + + } + } + + if ((base_partition_table[k].capacity != SystemDisk[j]->PartitionTable[i].nSectorsTotal) || + (base_partition_table[k].partition_offset != SystemDisk[j]->PartitionTable[i].StartLBA) || + (new_partition_flag != 0)) + { + base_partition_table[k].vpart_handle += 0x10000000; + base_partition_table[k].rrpart_table_index = k; + base_partition_table[k].partition_offset = SystemDisk[j]->PartitionTable[i].StartLBA; + base_partition_table[k].capacity = SystemDisk[j]->PartitionTable[i].nSectorsTotal; + base_partition_table[k].sector_size_shift = 9; + base_partition_table[k].partition_type = SystemDisk[j]->PartitionTable[i].SysFlag; +// base_partition_table[k].low_level_handle = (ULONG) SystemDisk[j]->PhysicalDiskHandle; + base_partition_table[k].low_level_handle = (ULONG) SystemDisk[j]->PartitionContext[i]; + WriteDiskSectors(j, SystemDisk[j]->PartitionTable[i].StartLBA + 0x20, zero_block_buffer, 8, 8); + WriteDiskSectors(j, SystemDisk[j]->PartitionTable[i].StartLBA + 0x40, zero_block_buffer, 8, 8); + WriteDiskSectors(j, SystemDisk[j]->PartitionTable[i].StartLBA + 0x60, zero_block_buffer, 8, 8); + WriteDiskSectors(j, SystemDisk[j]->PartitionTable[i].StartLBA + 0x80, zero_block_buffer, 8, 8); + } + base_partition_table[k].scan_flag = 0; + break; + } + } + if ((k == base_partition_table_count) && (base_partition_table_count < MAX_PARTITIONS)) + { + raw_instance += 0x10000000; + base_partition_table[k].vpart_handle = (raw_instance + (j << 16) + (i << 12) + k) & 0x7FFFFFFF; + base_partition_table[k].scan_flag = 0; + base_partition_table[k].rrpart_table_index = k; + base_partition_table[k].partition_offset = SystemDisk[j]->PartitionTable[i].StartLBA; + base_partition_table[k].capacity = SystemDisk[j]->PartitionTable[i].nSectorsTotal; + base_partition_table[k].sector_size_shift = 9; + base_partition_table[k].partition_type = SystemDisk[j]->PartitionTable[i].SysFlag; + base_partition_table[k].low_level_handle = (ULONG) SystemDisk[j]->PartitionContext[i]; + base_partition_table_count ++; + } + } + } + } + } + nwvp_io_free(hotfix_sector); + + for (k=0; kpayload_object_size_buffer_size & 0x000FFFFF) / 4; + handle_ptr= (ULONG *) req_payload->payload_buffer; + index = req_payload->payload_index; + req_payload->payload_object_count = 0; + for (; indexpayload_object_count ++; + + if (req_payload->payload_object_count >= object_count) + { + for (; indexpayload_index = index; + return(0); + } + req_payload->payload_index = 0; + return(0); + } + } + } + } + req_payload->payload_index = 0; + return(0); +} + +ULONG nwvp_part_scan_specific( + ULONG handle, + nwvp_part_info *part_info) +{ + if ((base_partition_table[handle & 0xFFF].vpart_handle != 0) && + (base_partition_table[handle & 0xFFF].vpart_handle == handle)) + { + part_info->partition_type = base_partition_table[handle & 0xFFF].partition_type; + part_info->sector_size_shift = 9; + part_info->sector_count = base_partition_table[handle & 0xFFF].capacity; + part_info->low_level_handle = base_partition_table[handle & 0xFFF].low_level_handle; + return(0); + } + return(-1); +} + +ULONG nwvp_part_map_to_physical( + ULONG rpart_handle, + ULONG *disk_id, + ULONG *disk_offset, + ULONG *partition_number) +{ + nwvp_rrpart *rrpart; + + if (((rrpart = &base_partition_table[rpart_handle & 0xFFF]) != 0) && + (rrpart->vpart_handle == rpart_handle)) + { + if (disk_id != 0) + *disk_id = (rrpart->vpart_handle & 0x0FFF0000) >> 16; + if (disk_offset != 0) + *disk_offset = rrpart->partition_offset; + if (partition_number != 0) + *partition_number = (rrpart->vpart_handle & 0x0000F000) >> 12; + return(0); + } + return(-1); +} + +ULONG nwvp_part_read( + ULONG handle, + ULONG sector_offset, + ULONG sector_count, + BYTE *data_buffer) +{ + nwvp_rrpart *rrpart; + + if (((rrpart = &base_partition_table[handle & 0xFFF]) != 0) && + (rrpart->vpart_handle == handle)) + { +// if (rrpart->online_flag != 0) +// { +// if ((rrpart->error_flag != 0xFFFFFFFF) && (rrpart->error_flag != sector_offset)) +// { + if(ReadDiskSectors( + (rrpart->vpart_handle & 0x0FFF0000) >> 16, + rrpart->partition_offset + sector_offset, + data_buffer, + sector_count, + sector_count) != 0) + return(0); +// } +// } + } + return(-1); +} + +ULONG nwvp_part_write( + ULONG handle, + ULONG sector_offset, + ULONG sector_count, + BYTE *data_buffer) +{ + nwvp_rrpart *rrpart; + +// NWFSPrint("nwvp_part_write called with %d %x %x %x \n", handle, sector_offset, sector_count, (ULONG) data_buffer); + if (((rrpart = &base_partition_table[handle & 0xFFF]) != 0) && + (rrpart->vpart_handle == handle)) + { +// if (rrpart->online_flag != 0) +// { +// if ((rrpart->error_flag != 0xFFFFFFFF) && (rrpart->error_flag != sector_offset)) +// { + if(WriteDiskSectors( + (rrpart->vpart_handle & 0x0FFF0000) >> 16, + rrpart->partition_offset + sector_offset, + data_buffer, + sector_count, + sector_count) != 0) + return(0); +// } +// } + } + return(-1); +} + +void mem_check_init(void) +{ + return; +} + +void mem_check_uninit(void) +{ + return; +} + +ULONG nwvp_alloc( + void **mem_ptr, + ULONG size) +{ + if ((*mem_ptr = NWFSAlloc(size, NWVP_TAG)) != 0) + return(0); + return(-1); +} + +ULONG nwvp_io_alloc( + void **mem_ptr, + ULONG size) +{ + *mem_ptr = kmalloc(size, GFP_KERNEL); + if (*mem_ptr) + return(0); + return(-1); +} + +ULONG nwvp_io_free(void *memptr) +{ + kfree(memptr); + return(0); +} + + +ULONG nwvp_free( + void *mem_ptr) +{ + NWFSFree(mem_ptr); + return(0); +} + + +ULONG nwvp_thread_get_id() +{ +// return(get_running_process()); + return(0); +} + +void nwvp_thread_yield() +{ +// return(get_running_process()); + return; +} + +void nwvp_thread_delay( + ULONG amount) +{ +// delayThread(amount); +} + +void nwvp_thread_sleep() +{ +// sleepThread(); +}; + +void nwvp_thread_wakeup( + ULONG thread_id) +{ +// rescheduleThread(thread_id); +} + +void nwvp_thread_kill( + ULONG thread_id) +{ +// killThread(thread_id); +} + +ULONG nwvp_thread_create( + BYTE *name, + ULONG (*start_routine)(ULONG), + ULONG start_parameter) +{ +// return(createThread(name, start_routine, 4096, (void *) start_parameter, -1)); + return(0); +} + +ULONG nwvp_memset(void *p, int c, long size) +{ + NWFSSet(p, c, size); + return(0); +} + +ULONG nwvp_memcpy(void *d, void *s, long size) +{ + NWFSCopy(d, s, size); + return(0); +} + +ULONG nwvp_memcomp(void *d, void *s, long size) +{ + return(NWFSCompare(d, s, size)); +} + + +ULONG nwvp_memmove(void *d, void *s, long size) +{ + NWFSCopy(d, s, size); + return (0); +} + +void nwvp_spin_lock( + ULONG *spin_lock) +{ + *spin_lock = 1; +} + +void nwvp_spin_unlock( + ULONG *spin_lock) +{ + *spin_lock = 0; +} + +ULONG nwvp_ascii_to_int( + ULONG *value, + BYTE *string) +{ + BYTE *bptr; + int base = 10; + *value = 0; + + bptr = string; + if ((bptr[0] == '0') && ((bptr[1] == 'x') || (bptr[1] == 'X'))) + { + base = 16; + bptr += 2; + } + while (*bptr != 0) + { + if ((bptr[0] >= '0') && (bptr[0] <= '9')) + { + *value *= base; + *value += bptr[0] - '0'; + } + else + if (base == 16) + { + if ((bptr[0] >= 'a') && (bptr[0] <= 'f')) + { + *value *= base; + *value += bptr[0] - 'a' + 10; + } + else + if ((bptr[0] >= 'A') && (bptr[0] <= 'F')) + { + *value *= base; + *value += bptr[0] - 'A' + 10; + } + else + return(-1); + } + else + return(-1); + bptr ++; + } + return(0); +} + +ULONG nwvp_int_to_ascii( + ULONG value, + ULONG base, + BYTE *string) +{ + BYTE temp_string[16]; + BYTE *sptr; + ULONG digit; + ULONG index = 0; + ULONG temp_value = value; + + string[0] = '0'; + string[1] = 0; + sptr = string; + while (temp_value != 0) + { + digit = temp_value % base; + if (digit < 10) + temp_string[index] = (BYTE)(digit + '0'); + else + temp_string[index] = (BYTE)(digit + 'A') - 10; + temp_value /= base; + index ++; + } + if (base == 16) + { + for (digit = 0; digit < (8 - index); digit ++) + { + sptr[0] = '0'; + sptr ++; + } + } + while (index) + { + index --; + sptr[0] = temp_string[index]; + sptr ++; + sptr[0] = 0; + } + return(0); +} + +#if (LINUX_SLEEP) +NWFSInitMutex(NWVPSemaphore); +#endif + +ULONG double_check = 0; + +void NWLockNWVP(void) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&NWVPSemaphore) == -EINTR) + NWFSPrint("lock nwvp was interrupted\n"); +#endif +} + +void NWUnlockNWVP(void) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&NWVPSemaphore); +#endif +} + +#if (LINUX_SLEEP) +NWFSInitMutex(HOTFIXSemaphore); +#endif + +void NWLockHOTFIX(void) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&HOTFIXSemaphore) == -EINTR) + NWFSPrint("lock hotfix was interrupted\n"); +#endif +} + +void NWUnlockHOTFIX(void) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&HOTFIXSemaphore); +#endif +} + +#if (LINUX_SLEEP) +NWFSInitSemaphore(REMIRRORSemaphore); +#endif + +void NWLockREMIRROR(void) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&REMIRRORSemaphore) == -EINTR) + NWFSPrint("lock remirror was interrupted\n"); +#endif +} + +void NWUnlockREMIRROR(void) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&REMIRRORSemaphore); +#endif +} + +ULONG nwvp_get_date_and_time(void) +{ + return (NWFSSystemToNetwareTime(NWFSGetSystemTime())); +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvphal.h linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvphal.h --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/nwvphal.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/nwvphal.h 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,187 @@ +/*************************************************************************** +* +* Copyright (c) 1997, 1998, 1999 Jeff V. Merkey All Rights +* Reserved. +* +* +* AUTHOR : Darren Major +* FILE : NWVPHAL.H +* DESCRIP : NetWare Virtual Partition +* DATE : August 1, 1999 +* +***************************************************************************/ + +#ifndef _NWVPHAL_ +#define _NWVPHAL_ + +#define vndi_console nwvp_console +#define vndi_payload nwvp_payload + +typedef struct nwvp_payload_def +{ + ULONG payload_index; + ULONG payload_object_count; // return value + ULONG payload_object_size_buffer_size; + BYTE *payload_buffer; +} nwvp_payload; + +typedef struct nwvp_part_info_def +{ + ULONG partition_type; + ULONG sector_size_shift; + ULONG sector_count; + ULONG low_level_handle; +} nwvp_part_info; + +typedef struct nwvp_rpart_def +{ + ULONG vndi_type; + ULONG vndi_handle; + ULONG rpart_table_index; + ULONG scan_field; + + BYTE filename[32]; + + ULONG capacity; + ULONG sector_size_shift; + ULONG online_flag; + ULONG error_flag; + + ULONG f_handle; + ULONG errors[32]; + ULONG error_param[32]; + ULONG index; +} nwvp_part; + +typedef struct nwvp_entry_def +{ + ULONG vndi_type; + ULONG index; + BYTE filename[32]; +} nwvp_entry; + +#define RPART_ERROR_IO 1 +#define RPART_ONLINE 1 +#define RPART_OFFLINE 0 +#define NWVP_READWRITE_BUFFER_SIZE 16384 + +void nwvp_part_unscan(void); + +ULONG nwvp_part_scan( + nwvp_payload *req_payload); + +ULONG nwvp_part_scan_specific( + ULONG handle, + nwvp_part_info *part_info); + +ULONG nwvp_part_read( + ULONG handle, + ULONG sector_offset, + ULONG sector_count, + BYTE *data_buffer); + +ULONG nwvp_raw_read ( + nwvp_part *rpart, + ULONG sector_offset, + ULONG sector_count, + BYTE *data_buffer); + +ULONG nwvp_part_write( + ULONG handle, + ULONG sector_offset, + ULONG sector_count, + BYTE *data_buffer); + +ULONG nwvp_raw_write ( + nwvp_part *rpart, + ULONG sector_offset, + ULONG sector_count, + BYTE *data_buffer); + +ULONG dbase_write(void); + +ULONG rpart_open( + BYTE *filename, + ULONG index); + + +ULONG nwvp_get_date_and_time(void); + +ULONG nwvp_thread_get_id(void); + +void nwvp_thread_delay( + ULONG amount); + +void nwvp_thread_sleep(void); + +void nwvp_thread_wakeup( + ULONG thread_id); + +void nwvp_thread_kill( + ULONG thread_id); + +void nwvp_thread_yield(void); + +ULONG nwvp_thread_create( + BYTE *name, + ULONG (*start_routine)(ULONG), + ULONG start_parameter); + +ULONG nwvp_memset(void *p, int c, long size); + +ULONG nwvp_memcpy(void *d, void *s, long size); + +ULONG nwvp_memcomp(void *d, void *s, long size); + +ULONG nwvp_memmove(void *d, void *s, long size); + +ULONG nwvp_init_partitions (void); + +ULONG nwvp_uninit_partitions (void); + +ULONG nwvp_create_file_partition ( + ULONG sector_size_shift, + ULONG capacity); + +ULONG nwvp_delete_file_partition ( + ULONG rpart_handle); + +ULONG partition_online ( + ULONG part_handle); + +ULONG partition_offline ( + ULONG part_handle); + +//void raw_offline_routine( +// vndi_console *console); + +ULONG nwvp_part_scan_all( + vndi_payload *req_payload); + +ULONG inject_error ( + ULONG rpart_handle, + ULONG error, + ULONG param); + +ULONG remove_error ( + ULONG rpart_handle, + ULONG error, + ULONG param); + +ULONG nwvp_ascii_to_int( + ULONG *value, + BYTE *string); + +ULONG nwvp_int_to_ascii( + ULONG value, + ULONG base, + BYTE *string); + +#endif + +void NWLockNWVP(void); +void NWUnlockNWVP(void); +void NWLockHOTFIX(void); +void NWUnlockHOTFIX(void); +void NWLockREMIRROR(void); +void NWUnlockREMIRROR(void); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/rapidfat.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/rapidfat.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/rapidfat.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/rapidfat.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,69 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : RAPIDFAT.C +* DESCRIP : NWFS Rapid FAT Module +* DATE : July 11, 1999 +* +* +***************************************************************************/ + +#include "globals.h" + +void NWLockFCB(FCB *fcb) +{ +#if (LINUX) + if (WaitOnSemaphore(&fcb->Semaphore) == -EINTR) + NWFSPrint("lock fcb was interrupted\n"); +#endif +} + +void NWUnlockFCB(FCB *fcb) +{ +#if (LINUX) + SignalSemaphore(&fcb->Semaphore); +#endif +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/suballoc.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/suballoc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/suballoc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/suballoc.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,1254 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : SUBALLOC.C +* DESCRIP : NWFS NetWare File System Suballocation Support +* DATE : January 9, 1999 +* +* +***************************************************************************/ + +#include "globals.h" + +ULONG TrgDebugSA = 0; + +void NWLockSuballoc(VOLUME *volume, ULONG blockCount) +{ + if (blockCount >= volume->SuballocListCount) + { + NWFSPrint("nwfs: suballoc blockCount too big (%d/%d) in LockSuballoc\n", + (int)blockCount, (int)volume->SuballocListCount); + return; + } +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&volume->SuballocSemaphore[blockCount]) == -EINTR) + NWFSPrint("lock suballoc-%d was interrupted\n", (int)blockCount); +#endif +} + +void NWUnlockSuballoc(VOLUME *volume, ULONG blockCount) +{ + if (blockCount >= volume->SuballocListCount) + { + NWFSPrint("nwfs: suballoc blockCount too big (%d/%d) in UnlockSuballoc\n", + (int)blockCount, (int)volume->SuballocListCount); + return; + } +#if (LINUX_SLEEP) + SignalSemaphore(&volume->SuballocSemaphore[blockCount]); +#endif +} + +ULONG NWCreateSuballocRecords(VOLUME *volume) +{ + register ULONG retCode; + register SUBALLOC *suballoc; + register ULONG i, LastDirNo; + register ROOT *root; + + // if suballocation is disabled for this volume, then + // return. + if (!(volume->VolumeFlags & SUB_ALLOCATION_ON)) + return 0; + + if (!volume->ClusterSize) + return -1; + + volume->VolumeSuballocRoot = 0; + volume->SuballocChainComplete = 0; + + root = NWFSAlloc(sizeof(ROOT), DIR_WORKSPACE_TAG); + if (!root) + { + NWFSPrint("nwfs: could not get workspace memory\n"); + return NwInsufficientResources; + } + + retCode = ReadDirectoryRecord(volume, (DOS *)root, 0); + if (retCode) + { + NWFSPrint("nwfs: could not read rootdir during suballoc create\n"); + NWFSFree(root); + return NwDiskIoError; + } + + volume->SuballocCurrentCount = 0; + volume->SuballocListCount = (volume->ClusterSize / SUBALLOC_BLOCK_SIZE); + volume->SuballocCount = (volume->SuballocListCount + 27) / 28; + + for (i=0; i < volume->SuballocCount; i++) + { + volume->SuballocChainFlag[i] = 0; + if (volume->SuballocChain[i]) + NWFSSet(volume->SuballocChain[i], 0, sizeof(SUBALLOC)); + } + + for (i=0; i < volume->SuballocCount; i++) + { + if (volume->SuballocChainFlag[i]) + { + NWFSPrint("nwfs: suballoc node sequence collision (#%d)\n", (int)i); + NWFSFree(root); + return NwHashError; + } + + volume->SuballocDirNo[i] = 0; + volume->SuballocChainFlag[i] = (ULONG) -1; + + if (!volume->SuballocChain[i]) + { + volume->SuballocChain[i] = NWFSAlloc(sizeof(SUBALLOC), + SUBALLOC_HEAD_TAG); + if (!volume->SuballocChain[i]) + { + NWFSPrint("nwfs: suballoc dir node alloc failure\n"); + NWFSFree(root); + return NwHashError; + } + NWFSSet(volume->SuballocChain[i], 0, sizeof(SUBALLOC)); + } + volume->SuballocCurrentCount++; + } + + // create the directory records + LastDirNo = (ULONG) -1; + for (i=0; i < volume->SuballocCount; i++) + { + volume->SuballocDirNo[i] = AllocateDirectoryRecord(volume, 0); + + if ((volume->SuballocDirNo[i] == (ULONG) -1) || + (volume->SuballocDirNo[i] == LastDirNo) || + (!volume->SuballocDirNo[i])) + { + retCode = FreeDirectoryRecords(volume, volume->SuballocDirNo, + 0, i); + if (retCode) + { + NWFSPrint("nwfs: could not release dir record in CreateSuballoc\n"); + NWFSFree(root); + return retCode; + } + NWFSPrint("nwfs: could not allocate directory record\n"); + NWFSFree(root); + return NwInsufficientResources; + } + LastDirNo = volume->SuballocDirNo[i]; + } + + // initialize the suballoc root; + volume->VolumeSuballocRoot = volume->SuballocDirNo[0]; + root->SubAllocationList = volume->VolumeSuballocRoot; + + for (i=0; i < (volume->SuballocCount - 1); i++) + { + // store the DirNo for next record into SuballocationList + suballoc = (SUBALLOC *) volume->SuballocChain[i]; + suballoc->Flag = SUBALLOC_NODE; + suballoc->ID = 0; + suballoc->Reserved1 = 0; + suballoc->SubAllocationList = volume->SuballocDirNo[i + 1]; + suballoc->SequenceNumber = (BYTE) i; + } + // null terminate last suballoc directory record + suballoc = (SUBALLOC *) volume->SuballocChain[i]; + suballoc->Flag = SUBALLOC_NODE; + suballoc->ID = 0; + suballoc->Reserved1 = 0; + suballoc->SubAllocationList = 0; + suballoc->SequenceNumber = (BYTE) i; + + retCode = WriteDirectoryRecord(volume, (DOS *)root, 0); + if (retCode) + { + NWFSPrint("nwfs: could not write rootdir during suballoc create\n"); + NWFSFree(root); + return NwDiskIoError; + } + + NWFSFree(root); + + // Write the suballocation chain heads to the volume directory. + for (i=0; i < volume->SuballocCount; i++) + { + retCode = WriteDirectoryRecord(volume, + (DOS *)volume->SuballocChain[i], + volume->SuballocDirNo[i]); + if (retCode) + { + NWFSPrint("nwfs: could not write rootdir during suballoc create\n"); + NWFSFree(root); + return NwDiskIoError; + } + } + volume->SuballocChainComplete = (ULONG) -1; + + return 0; + +} + +ULONG ReadSuballocTable(VOLUME *volume) +{ + register ULONG i, SuballocLink, sequence; + ULONG chainSize; + register ULONG binSize, totalBlocks; + register ULONG cbytes, count; + register DOS *dos1, *dos2; + register SUBALLOC *suballoc; + register ROOT *root; + register BYTE *Buffer; + ULONG retCode = 0; + + Buffer = NWFSIOAlloc(IO_BLOCK_SIZE, ALIGN_BUF_TAG); + if (!Buffer) + return 0; + + retCode = nwvp_vpartition_block_read(volume->nwvp_handle, + (volume->FirstDirectory * + volume->BlocksPerCluster), + 1, Buffer); + if (retCode) + { + NWFSFree(Buffer); + return 0; + } + + root = (ROOT *) Buffer; + if ((root->Subdirectory != ROOT_NODE) || + (root->NameSpace != DOS_NAME_SPACE)) + { + NWFSFree(Buffer); + return 0; + } + + if ((root->VolumeFlags & NDS_FLAG) || + (root->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + volume->VolumeSuballocRoot = root->SubAllocationList; + } + NWFSFree(Buffer); + + // If suballocation has not been initialized for this volume, + // then return success without any further processing at this + // point during volume mount. Suballoc chains will be created + // after the directory chain has been processed. + + if (!volume->VolumeSuballocRoot) + return 0; + +#if (MOUNT_VERBOSE) + NWFSPrint("*** Verifying Suballocation Tables ***\n"); +#endif + + dos1 = NWFSAlloc(sizeof(ROOT), DIR_WORKSPACE_TAG); + if (!dos1) + return NwInsufficientResources; + + dos2 = NWFSAlloc(sizeof(ROOT), DIR_WORKSPACE_TAG); + if (!dos2) + { + NWFSFree(dos1); + return NwInsufficientResources; + } + + count = 0; + volume->SuballocCurrentCount = 0; + volume->SuballocListCount = (volume->ClusterSize / SUBALLOC_BLOCK_SIZE); + volume->SuballocCount = (volume->SuballocListCount + 27) / 28; + + SuballocLink = volume->VolumeSuballocRoot; + while (SuballocLink) + { +#if (VERBOSE) + NWFSPrint("SuballocLink -> %X\n", (unsigned int)SuballocLink); +#endif + + if (count++ > MAX_SUBALLOC_NODES) + { + NWFSPrint("nwfs: encountered too many suballoc dir records\n"); + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + + cbytes = NWReadFile(volume, + &volume->FirstDirectory, + 0, + (ULONG)-1, // set the filesize to infinity + (SuballocLink * sizeof(ROOT)), + (BYTE *)dos1, + sizeof(ROOT), + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + NO_SUBALLOC, + 0); + + if (cbytes != sizeof(ROOT)) + { + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + + cbytes = NWReadFile(volume, + &volume->SecondDirectory, + 0, + (ULONG)-1, // set the filesize to infinity + (SuballocLink * sizeof(ROOT)), + (BYTE *)dos2, + sizeof(ROOT), + 0, + 0, + &retCode, + KERNEL_ADDRESS_SPACE, + 0, + NO_SUBALLOC, + 0); + + if (cbytes != sizeof(ROOT)) + { + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + + if (NWFSCompare(dos1, dos2, sizeof(ROOT))) + { + NWFSFree(dos1); + NWFSFree(dos2); + NWFSPrint("nwfs: dir data mismatch during suballoc table read\n"); + return NwHashError; + } + + suballoc = (SUBALLOC *) dos1; + sequence = suballoc->SequenceNumber; + if (volume->SuballocChainFlag[sequence]) + { + NWFSPrint("nwfs: suballoc node sequence collision (#%u)\n", + (unsigned int)sequence); + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + + if (sequence > 4) + { + NWFSPrint("nwfs: suballoc node sequence error\n"); + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + + volume->SuballocDirNo[sequence] = SuballocLink; + volume->SuballocChainFlag[sequence] = (ULONG) -1; + +#if (VERBOSE) + NWFSPrint("count-%d list_count-%d curr_count-%d\n", + (int)volume->SuballocCount, + (int)volume->SuballocListCount, + (int)volume->SuballocCurrentCount); +#endif + + if (!volume->SuballocChain[sequence]) + { + volume->SuballocChain[sequence] = NWFSAlloc(sizeof(SUBALLOC), + SUBALLOC_HEAD_TAG); + if (!volume->SuballocChain[sequence]) + { + NWFSPrint("nwfs: suballoc dir node alloc failure\n"); + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + } + + NWFSCopy(volume->SuballocChain[sequence], suballoc, sizeof(SUBALLOC)); + volume->SuballocCurrentCount++; + if (volume->SuballocCurrentCount >= volume->SuballocCount) + { + for (i=0; i < volume->SuballocListCount; i++) + { + volume->SuballocSearchIndex[i] = 0; + + // allocate a block free list for each suballoc fat chain. + if (volume->SuballocChain[i / 28]->StartingFATChain[i % 28]) + { + // determine the total length of the suballoc chain + chainSize = GetChainSize(volume, + volume->SuballocChain[i / 28]->StartingFATChain[i % 28]); + + // map the current cluster allocation for this suballoc + // chain. + retCode = BuildChainAssignment(volume, + volume->SuballocChain[i / 28]->StartingFATChain[i % 28], + 0); + + if (retCode) + { + register FAT_ENTRY *fat; + FAT_ENTRY FAT_S; + + fat = GetFatEntry(volume, + volume->SuballocChain[i / 28]->StartingFATChain[i % 28], + &FAT_S); + + NWFSPrint("%d: %X ", (int)i, + (unsigned int) volume->SuballocChain[i / 28]->StartingFATChain[i % 28]); + + while (fat && fat->FATCluster) + { + if (fat->FATCluster) + NWFSPrint("-> "); + NWFSPrint("%X ", (unsigned int)fat->FATCluster); + fat = GetFatEntry(volume, fat->FATCluster, &FAT_S); + } + NWFSPrint("\n"); + + NWFSPrint("nwfs: suballoc fat chain (%d)-%d is corrupt\n", + (int)i, (int)(i * SUBALLOC_BLOCK_SIZE)); + NWFSFree(dos1); + NWFSFree(dos2); + return NwHashError; + } + + // calculate the total number of logical blocks in this + // suballoc chain. we do not count partial blocks + // or round to the next logical block at this point + // because we need an accurate count of whole blocks. + + binSize = (i * SUBALLOC_BLOCK_SIZE); + volume->SuballocAssignedBlocks[i] = 0; + volume->SuballocTotalBlocks[i] = totalBlocks = chainSize / binSize; + +#if (VERBOSE) + NWFSPrint("size-%d blocks-%d\n", + (int)chainSize, (int)totalBlocks); +#endif + volume->FreeSuballoc[i] = NWFSAlloc(sizeof(BIT_BLOCK_HEAD), + BITBLOCK_TAG); + if (!volume->FreeSuballoc[i]) + { + NWFSFree(dos1); + NWFSFree(dos2); + return NwInsufficientResources; + } + NWFSSet(volume->FreeSuballoc[i], 0, sizeof(BIT_BLOCK_HEAD)); + + retCode = CreateBitBlockList(volume->FreeSuballoc[i], + totalBlocks, + SUBALLOC_BLOCK_SIZE, + "suballoc list"); + if (retCode) + { + NWFSFree(volume->FreeSuballoc[i]); + volume->FreeSuballoc[i] = 0; + + NWFSFree(dos1); + NWFSFree(dos2); + return NwInsufficientResources; + } + } + } + volume->SuballocChainComplete = (ULONG) -1; + NWFSFree(dos1); + NWFSFree(dos2); + return 0; + } + SuballocLink = suballoc->SubAllocationList; + } + NWFSFree(dos1); + NWFSFree(dos2); + + return 0; + +} + +ULONG AllocateSuballocRecord(VOLUME *volume, ULONG size, ULONG *retCode) +{ + register ULONG blockIndex, blockOffset, blockCount, i; + register ULONG ccode, blockSize, SAEntry, blockNumber; + + if (retCode) + *retCode = 0; + + if (!volume->VolumeSuballocRoot) + { + if (retCode) + *retCode = NwSuballocMissing; + return 0; + } + + if (size >= volume->ClusterSize) + { + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + blockIndex = size / SUBALLOC_BLOCK_SIZE; + blockOffset = size % SUBALLOC_BLOCK_SIZE; + i = blockCount = blockIndex + (blockOffset ? 1 : 0); + blockSize = blockCount * SUBALLOC_BLOCK_SIZE; + + if (blockCount >= volume->SuballocListCount) + { + NWFSPrint("nwfs: suballoc blockCount too big (%d/%d)\n", + (int)blockCount, (int)volume->SuballocListCount); + if (retCode) + *retCode = NwInvalidParameter; + return 0; + } + + // lock this suballoc block bin + NWLockSuballoc(volume, blockCount); + + // if this element has a free list + if (volume->FreeSuballoc[i]) + { + // if the last allocated index was at the end of the suballoc + // file, go ahead and extend the bit block list since we will + // extend it anyway on the next bit block search operation. + if ((volume->SuballocSearchIndex[i] + 1) >= + volume->SuballocTotalBlocks[i]) + { + // extend the suballocation chain + volume->SuballocTotalBlocks[i]++; + + // if we exceed the max blocks, report we have exceeded + // the maximum number of suballoc blocks supported in + // a single chain. The IA32 limit is 16,777,215 + // (sixteen million blocks). + + if (volume->SuballocTotalBlocks[i] >= 0xFFFFFF) + { + volume->SuballocTotalBlocks[i]--; + if (retCode) + *retCode = NwSuballocExceeded; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + // adjust the length of the free list + ccode = AdjustBitBlockList(volume->FreeSuballoc[i], + volume->SuballocTotalBlocks[i]); + if (ccode) + { + if (retCode) + *retCode = NwOtherError; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + blockNumber = + ScanAndSetBitBlockValueWithIndex(volume->FreeSuballoc[i], + 0, volume->SuballocSearchIndex[i], + 1); + if (blockNumber == (ULONG) -1) + { + if (retCode) + *retCode = NwInsufficientResources; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + } + else + { + // see if there are any free blocks + blockNumber = + ScanAndSetBitBlockValueWithIndex(volume->FreeSuballoc[i], + 0, volume->SuballocSearchIndex[i], + 1); + if (blockNumber == (ULONG) -1) + { + // extend the suballocation chain + volume->SuballocTotalBlocks[i]++; + + // if we exceed the max blocks, report we have exceeded + // the maximum number of suballoc blocks supported in + // a single chain. The IA32 limit is 16,777,215 + // (sixteen million blocks). + + if (volume->SuballocTotalBlocks[i] >= 0xFFFFFF) + { + volume->SuballocTotalBlocks[i]--; + if (retCode) + *retCode = NwSuballocExceeded; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + // adjust the length of the free list + ccode = AdjustBitBlockList(volume->FreeSuballoc[i], + volume->SuballocTotalBlocks[i]); + if (ccode) + { + if (retCode) + *retCode = NwOtherError; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + blockNumber = + ScanAndSetBitBlockValueWithIndex(volume->FreeSuballoc[i], + 0, volume->SuballocSearchIndex[i], + 1); + if (blockNumber == (ULONG) -1) + { + if (retCode) + *retCode = NwInsufficientResources; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + } + } + volume->SuballocSearchIndex[i] = blockNumber; + + // construct the suballoc entry + SAEntry = 0x80000000; + SAEntry |= (blockCount << 24); + SAEntry |= (blockNumber & 0x00FFFFFF); + +#if (VERBOSE) + NWFSPrint("SuballocGet -> %08X TotalBlocks-%d %s\n", + (unsigned int)SAEntry, (int)volume->SuballocTotalBlocks[i], + (blockNumber == volume->SuballocTotalBlocks[i]) + ? "blockNumber = TotalBlocks" : ""); +#endif + NWUnlockSuballoc(volume, blockCount); + return SAEntry; + } + else + { + volume->FreeSuballoc[i] = NWFSAlloc(sizeof(BIT_BLOCK_HEAD), + BITBLOCK_TAG); + if (!volume->FreeSuballoc[i]) + { + if (retCode) + *retCode = NwInsufficientResources; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + NWFSSet(volume->FreeSuballoc[i], 0, sizeof(BIT_BLOCK_HEAD)); + + volume->SuballocTotalBlocks[i] = 0; + volume->SuballocTotalBlocks[i]++; + + ccode = CreateBitBlockList(volume->FreeSuballoc[i], + volume->SuballocTotalBlocks[i], + SUBALLOC_BLOCK_SIZE, + "suballoc list"); + if (ccode) + { + NWFSFree(volume->FreeSuballoc[i]); + volume->FreeSuballoc[i] = 0; + if (retCode) + *retCode = NwInsufficientResources; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + blockNumber = ScanAndSetBitBlockValueWithIndex(volume->FreeSuballoc[i], + 0, volume->SuballocSearchIndex[i], + 1); + if (blockNumber == (ULONG) -1) + { + if (retCode) + *retCode = NwInsufficientResources; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + volume->SuballocSearchIndex[i] = blockNumber; + + // construct the suballoc entry + SAEntry = 0x80000000; + SAEntry |= (blockCount << 24); + SAEntry |= (blockNumber & 0x00FFFFFF); + +#if (VERBOSE) + NWFSPrint("SuballocGet -> %08X TotalBlocks-%d %s\n", + (unsigned int)SAEntry, (int)volume->SuballocTotalBlocks[i], + (blockNumber == volume->SuballocTotalBlocks[i]) + ? "blockNumber = TotalBlocks" : ""); +#endif + NWUnlockSuballoc(volume, blockCount); + return SAEntry; + } + + if (retCode) + *retCode = NwInvalidParameter; + return 0; +} + +ULONG GetSuballocListValue(VOLUME *volume, ULONG SAEntry) +{ + register ULONG blockCount, blockNumber, retCode; + + if (!volume->VolumeSuballocRoot) + return NwSuballocMissing; + + if (!(SAEntry & 0x80000000) || (SAEntry == (ULONG) -1)) + return NwInvalidParameter; + + blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + return NwInvalidParameter; + + // if there is no suballoc free list, return error; + if (!volume->FreeSuballoc[blockCount]) + return NwInvalidParameter; + + blockNumber = (SAEntry & 0x00FFFFFF); + + retCode = GetBitBlockValue(volume->FreeSuballoc[blockCount], blockNumber); + + return retCode; +} + +// this function is called only during volume mount, and does not +// need to be locked. + +ULONG SetSuballocListValue(VOLUME *volume, ULONG SAEntry, ULONG Value) +{ + register ULONG blockCount, blockNumber, retCode; + + if (!volume->VolumeSuballocRoot) + return NwSuballocMissing; + + if (!(SAEntry & 0x80000000) || (SAEntry == (ULONG) -1)) + return NwInvalidParameter; + + blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + return NwInvalidParameter; + + // if there is no suballoc free list, return error; + if (!volume->FreeSuballoc[blockCount]) + return NwInvalidParameter; + + blockNumber = (SAEntry & 0x00FFFFFF); + + // keep a running counter of the highest allocated + // block number seen for this suballoc file chain. + // add 1 to block number since we are converting a zero + // based index into a count of elements. + + if ((blockNumber + 1) > volume->SuballocTotalBlocks[blockCount]) + { + NWFSPrint("nwfs: suballoc fat error [%08X] block-%d > total-%d clust-%d\n", + (unsigned int)SAEntry, (int)(blockNumber + 1), + (int)volume->SuballocTotalBlocks[blockCount], + (int)((volume->SuballocTotalBlocks[blockCount] * + (blockCount * SUBALLOC_BLOCK_SIZE)) / + volume->ClusterSize)); + } + + if ((blockNumber + 1) > volume->SuballocAssignedBlocks[blockCount]) + volume->SuballocAssignedBlocks[blockCount] = (blockNumber + 1); + +#if (DEBUG_SA) + if (GetBitBlockValue(volume->FreeSuballoc[blockCount], blockNumber)) + { + NWFSPrint("nwfs: duplicate suballoc entry detected/bin-%d/%d limit-%d\n", + (int)blockNumber, (int)blockCount, + (int)GetBitBlockLimit(volume->FreeSuballoc[blockCount])); + return NwInvalidParameter; + } +#endif + + retCode = SetBitBlockValue(volume->FreeSuballoc[blockCount], blockNumber, Value); + if (retCode) + { + NWFSPrint("nwfs: invalid suballoc node detected block/bin-%d/%d limit-%d\n", + (int)blockNumber, (int)blockCount, + (int)GetBitBlockLimit(volume->FreeSuballoc[blockCount])); + return NwInvalidParameter; + } + return 0; +} + +ULONG FreeSuballocRecord(VOLUME *volume, ULONG SAEntry) +{ + register ULONG blockCount, blockNumber, retCode; + +#if (VERBOSE) + NWFSPrint("SuballocFree -> %08X\n", (unsigned int)SAEntry); +#endif + + if (!volume->VolumeSuballocRoot) + return NwSuballocMissing; + + if (!(SAEntry & 0x80000000) || (SAEntry == (ULONG) -1)) + return NwInvalidParameter; + + blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + return NwInvalidParameter; + + blockNumber = (SAEntry & 0x00FFFFFF); + + if (volume->FreeSuballoc[blockCount]) + { +#if (DEBUG_SA) + if (!GetBitBlockValue(volume->FreeSuballoc[blockCount], blockNumber)) + { + NWFSPrint("nwfs: suballoc entry already free bin-%d/%d limit-%d\n", + (int)blockNumber, (int)blockCount, + (int)GetBitBlockLimit(volume->FreeSuballoc[blockCount])); + return NwInvalidParameter; + } +#endif + + retCode = SetBitBlockValue(volume->FreeSuballoc[blockCount], blockNumber, 0); + if (retCode) + { + NWFSPrint("nwfs: invalid suballoc node detected block/bin-%d/%d limit-%d\n", + (int)blockNumber, (int)blockCount, + (int)GetBitBlockLimit(volume->FreeSuballoc[blockCount])); + return NwInvalidParameter; + } + + if ((blockNumber) && + ((blockNumber - 1) <= volume->SuballocSearchIndex[blockCount])) + volume->SuballocSearchIndex[blockCount] = (blockNumber - 1); + + return 0; + } + return NwInvalidParameter; +} + +ULONG GetSuballocSize(VOLUME *volume, ULONG SAEntry) +{ + register ULONG blockCount; + + blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + { + NWFSPrint("block count error in GetSuballocSize\n"); + return 0; + } + return (blockCount * SUBALLOC_BLOCK_SIZE); +} + +ULONG ReadSuballocRecord(VOLUME *volume, long offset, + ULONG SAEntry, BYTE *buf, long count, + ULONG as, ULONG *retCode) +{ + register ULONG blockCount, blockNumber; + ULONG blockOffset, blockSize; + register ULONG cbytes, i; + ULONG FATChain; + +#if (VERBOSE) + NWFSPrint("ReadSuballoc -> %08X-%d\n", (unsigned int)SAEntry, (int)count); +#endif + + if (!(SAEntry & 0x80000000) || (SAEntry == (ULONG) -1)) + return 0; + + i = blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + return 0; + + blockSize = blockCount * SUBALLOC_BLOCK_SIZE; + if (offset > (long)blockSize) + return 0; + + if ((offset + count) > (long)blockSize) + count = blockSize - offset; + + if (count <= 0) + return 0; + + blockNumber = (SAEntry & 0x00FFFFFF); + blockOffset = blockNumber * blockSize; + + NWLockSuballoc(volume, blockCount); + if (!volume->SuballocChain[i / 28]) + { + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + // Suballoc chains are zero relative when empty as compared to file + // records, which use a -1 to indicate End of File. We check and + // see if the suballoc chain was null. If so, then pass -1 as the fat + // chain for this suballoc. + + FATChain = volume->SuballocChain[i / 28]->StartingFATChain[i % 28]; + if (!FATChain) + FATChain = (ULONG) -1; + + cbytes = NWReadFile(volume, + &FATChain, + 0, + volume->SuballocTotalBlocks[blockCount] * blockSize, + (blockOffset + offset), + buf, + count, + &volume->SuballocTurboFATCluster[i], + &volume->SuballocTurboFATIndex[i], + retCode, + as, + 0, + NO_SUBALLOC, + 0); + + NWUnlockSuballoc(volume, blockCount); + return cbytes; +} + +ULONG WriteSuballocRecord(VOLUME *volume, long offset, + ULONG SAEntry, BYTE *buf, long count, + ULONG as, ULONG *retCode) +{ + register ULONG blockCount, blockNumber; + ULONG blockOffset, blockSize; + register ULONG cbytes, ccode, i; + ULONG FATChain; + +#if (VERBOSE) + NWFSPrint("WriteSuballoc -> %08X-%d\n", (unsigned int)SAEntry, (int)count); +#endif + + if (!(SAEntry & 0x80000000) || (SAEntry == (ULONG) -1)) + return 0; + + i = blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + return 0; + + blockSize = blockCount * SUBALLOC_BLOCK_SIZE; + if (offset > (long)blockSize) + return 0; + + if ((offset + count) > (long)blockSize) + count = blockSize - offset; + + if (count <= 0) + return 0; + + blockNumber = SAEntry & 0x00FFFFFF; + blockOffset = blockNumber * blockSize; + + NWLockSuballoc(volume, blockCount); + if (!volume->SuballocChain[i / 28]) + { + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + // Suballoc chains are zero relative when empty as compared to file + // records, which use a -1 to indicate End of File. We check and + // see if the suballoc chain was null. If so, then pass -1 as the fat + // chain for this suballoc. + + FATChain = volume->SuballocChain[i / 28]->StartingFATChain[i % 28]; + if (!FATChain) + FATChain = (ULONG) -1; + + cbytes = NWWriteFile(volume, + &FATChain, + 0, + (blockOffset + offset), + buf, + count, + &volume->SuballocTurboFATCluster[i], + &volume->SuballocTurboFATIndex[i], + retCode, + as, + 0, + NO_SUBALLOC); + + // sanity check the suballoc dir catalog and make certain it has + // valid data. ditto with the suballoc directory record we intend + // to write. + + if ((!volume->SuballocDirNo[i / 28]) || (!volume->SuballocChain[i / 28])) + { + NWFSPrint("nwfs: invalid suballoc directory number\n"); + if (retCode) + *retCode = NwVolumeCorrupt; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + // if we updated any suballocation fat chains inside of write, then + // update the suballocation directory records and write them to the + // volume directory file. if the chain head was updated to EOF by + // the write operation, then write a zero into the suballoc dir + // chain head + + volume->SuballocChain[i / 28]->StartingFATChain[i % 28] = + ((FATChain == (ULONG) -1) ? 0 : FATChain); + + ccode = WriteDirectoryRecord(volume, + (DOS *)volume->SuballocChain[i / 28], + volume->SuballocDirNo[i / 28]); + if (ccode) + { + NWFSPrint("nwfs: error updating suballoc directory entry\n"); + if (retCode) + *retCode = NwVolumeCorrupt; + NWUnlockSuballoc(volume, blockCount); + return 0; + } + + NWUnlockSuballoc(volume, blockCount); + return cbytes; +} + + + +ULONG MapSuballocNode(VOLUME *volume, SUBALLOC_MAP *map, long SAEntry) +{ + register ULONG blockNumber, blockCount, blockOffset; + register ULONG startElement, startOffset; + register ULONG nextElement, nextOffset; + register ULONG sacluster, i; + register FAT_ENTRY *FAT; + FAT_ENTRY FAT_S; + register ULONG spc = volume->SectorsPerCluster; + + if (!map || (SAEntry == (ULONG) -1)) + return -1; + + // suballoc chains are organized into bins based on size. we extract + // the bin number from the suballoc cluster entry + + i = blockCount = (SAEntry & 0x7FFFFFFF) >> 24; + if (blockCount >= volume->SuballocListCount) + { + NWFSPrint("block count error in MapSuballocNode\n"); + return -1; + } + blockNumber = SAEntry & 0x00FFFFFF; + blockOffset = (blockNumber * blockCount); + startElement = blockOffset / spc; + startOffset = blockOffset % spc; + nextElement = (blockOffset + blockCount) / spc; + nextOffset = (blockOffset + blockCount) % spc; + + if ((startOffset + blockCount) > spc) // if greater, span is two elements + { + map->Count = 2; + map->Size = 0; + map->clusterIndex[0] = startElement; + map->clusterOffset[0] = startOffset * SUBALLOC_BLOCK_SIZE; + map->clusterSize[0] = (blockCount * SUBALLOC_BLOCK_SIZE) - + (nextOffset * SUBALLOC_BLOCK_SIZE); + map->Size += map->clusterSize[0]; + + map->clusterIndex[1] = nextElement; + map->clusterOffset[1] = 0; + map->clusterSize[1] = nextOffset * SUBALLOC_BLOCK_SIZE; + map->Size += map->clusterSize[1]; + + NWLockSuballoc(volume, blockCount); + if (!volume->SuballocChain[i / 28]) + { + NWFSPrint("nwfs: suballoc head error in MapSuballocNode\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + + // check is there is a Turbo FAT entry for this suballoc chain + if ((startElement >= volume->SuballocTurboFATIndex[i]) && + (volume->SuballocTurboFATCluster[i])) + sacluster = volume->SuballocTurboFATCluster[i]; + else + sacluster = volume->SuballocChain[i / 28]->StartingFATChain[i % 28]; + + FAT = GetFatEntry(volume, sacluster, &FAT_S); + while (FAT && FAT->FATCluster) + { + if (FAT->FATIndex == (long)startElement) + break; + + if (FAT->FATCluster == (ULONG) -1) + { + NWFSPrint("nwfs: fat chain error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + if (FAT->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: suballoc fat chain error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + sacluster = FAT->FATCluster; + FAT = GetFatEntry(volume, sacluster, &FAT_S); + } + + if (!FAT) + { + NWFSPrint("nwfs: fat table error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + + if (FAT->FATCluster == (ULONG) -1) + { + NWFSPrint("nwfs: fat entry error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + + if (FAT->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: fat entry suballoc error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + map->clusterNumber[0] = sacluster; + map->clusterNumber[1] = FAT->FATCluster; + + NWUnlockSuballoc(volume, blockCount); + +#if DEBUG_SA + if (TrgDebugSA) + { + NWFSPrint("map[1,2](%d/%d) index-%d offset-%d/%d size-%d clstr-%X [0x%08X]\n", + (int)blockCount, + (int)(blockCount * SUBALLOC_BLOCK_SIZE), + (int)map->clusterIndex[0], + (int)map->clusterOffset[0], + (int)startOffset, + (int)map->clusterSize[0], + (int)map->clusterNumber[0], + (unsigned int)SAEntry); + + NWFSPrint("map[2,2](%d/%d) index-%d offset-%d/0 size-%d clstr-%X\n", + (int)blockCount, + (int)(blockCount * SUBALLOC_BLOCK_SIZE), + (int)map->clusterIndex[1], + (int)map->clusterOffset[1], + (int)map->clusterSize[1], + (int)map->clusterNumber[1]); + } +#endif + + return 0; + } + else + { + map->Count = 1; + map->clusterIndex[0] = startElement; + map->clusterOffset[0] = startOffset * SUBALLOC_BLOCK_SIZE; + map->clusterSize[0] = blockCount * SUBALLOC_BLOCK_SIZE; + map->Size = map->clusterSize[0]; + + NWLockSuballoc(volume, blockCount); + + if (!volume->SuballocChain[i / 28]) + { + NWFSPrint("nwfs: suballoc head error in MapSuballocNode\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + + // check is there is a Turbo FAT entry for this suballoc chain + if ((startElement >= volume->SuballocTurboFATIndex[i]) && + (volume->SuballocTurboFATCluster[i])) + sacluster = volume->SuballocTurboFATCluster[i]; + else + sacluster = volume->SuballocChain[i / 28]->StartingFATChain[i % 28]; + + FAT = GetFatEntry(volume, sacluster, &FAT_S); + while (FAT && FAT->FATCluster) + { + if (FAT->FATIndex == (long)startElement) + break; + + if (FAT->FATCluster == (ULONG) -1) + { + NWFSPrint("nwfs: fat chain error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + + if (FAT->FATCluster & 0x80000000) + { + NWFSPrint("nwfs: suballoc fat chain error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + sacluster = FAT->FATCluster; + FAT = GetFatEntry(volume, sacluster, &FAT_S); + } + if (!FAT) + { + NWFSPrint("nwfs: fat table error in suballoc map\n"); + NWUnlockSuballoc(volume, blockCount); + return -1; + } + map->clusterNumber[0] = sacluster; + + NWUnlockSuballoc(volume, blockCount); + +#if DEBUG_SA + if (TrgDebugSA) + { + NWFSPrint("map[1,1](%d/%d) index-%d offset-%d/%d size-%d clstr-%X [0x%08X]\n", + (int)blockCount, + (int)(blockCount * SUBALLOC_BLOCK_SIZE), + (int)map->clusterIndex[0], + (int)map->clusterOffset[0], + (int)startOffset, + (int)map->clusterSize[0], + (int)map->clusterNumber[0], + (unsigned int)SAEntry); + } +#endif + + return 0; + } + return -1; + +} + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/super.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/super.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/super.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/super.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,185 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : SUPER.C +* DESCRIP : NWFS VFS Super Block Module for Linux* DATE : November 16, 1998 +* +* +***************************************************************************/ + +#define NWFSMOD_VERSION_INFO 1 +#include "globals.h" + + + +int nwfs_remount(struct super_block *sb, int *flags, char *data) +{ + return 0; +} + +struct super_block *nwfs_read_super(struct super_block *sb, void *data, int silent) +{ + register VOLUME *volume; + BYTE name[64]; + register BYTE *p, *n; + register ULONG count, AutoRepair = FALSE; + kdev_t dev = sb->s_dev; + +#if (VERBOSE) + NWFSPrint("read super\n"); +#endif + + if (!data) + { + NWFSPrint("nwfs: missing VOLUME_NAME\n"); + NWFSPrint("usage: mount [name] [/mount_point] -t nwfs -o VOLUME_NAME(+)\n"); + NWFSPrint(" where VOLUME_NAME is the name of a NetWare file system Volume\n"); + NWFSPrint(" and '+' enables the driver to auto-repair volume errors during volume mount\n"); + NWFSPrint(" invoke NWVOL for a listing of detected NetWare Volumes in\n"); + NWFSPrint(" this system.\n\n"); + NWFSPrint(" NWFS Utilities for Linux are:\n"); + NWFSPrint(" NWVOL - List detected NetWare volumes\n"); + NWFSPrint(" NWDISK/NWCONFIG - File System/Partition Config Utility\n"); + sb->s_dev = 0; + return NULL; + } + + NWFSVolumeScan(); + + count = 0; + p = (BYTE *) data; + n = &name[0]; + while (*p && (*p != ' ') && (*p != '\r') && (*p != '\n') && (*p != '+') && + (count < 16)) + { + *n++ = *p++; + count++; + } + *n = '\0'; + + if (*p == '+') + { + NWFSPrint("nwfs: volume auto-repair enabled\n"); + AutoRepair = TRUE; + } + + volume = MountHandledVolume(name); + if (!volume) + { + NWFSPrint("nwfs: error mounting volume %s\n", name); + sb->s_dev = 0; + return NULL; + } + + sb->s_blocksize = LogicalBlockSize; + switch (sb->s_blocksize) + { + case 512: + sb->s_blocksize_bits = 9; + break; + + case 1024: + sb->s_blocksize_bits = 10; + break; + + case 2048: + sb->s_blocksize_bits = 11; + break; + + case 4096: + sb->s_blocksize_bits = 12; + break; + + } + sb->s_magic = NWFS_LINUX_FS_ID; + sb->s_dev = dev; + sb->s_op = &nwfs_sops; + sb->u.generic_sbp = (void *) volume; + + sb->s_root = d_alloc_root(iget(sb, 0)); + if (!sb->s_root) + { + NWFSPrint("nwfs: get root inode failed\n"); + sb->s_dev = 0; + return NULL; + } + return sb; +} + +void nwfs_put_super(struct super_block *sb) +{ + register VOLUME *volume; + register ULONG retCode; + +#if (VERBOSE) + NWFSPrint("put super\n"); +#endif + + sb->s_dev = 0; + volume = (VOLUME *) sb->u.generic_sbp; + sb->u.generic_sbp = 0; + + retCode = DismountVolumeByHandle(volume); + if (retCode) + NWFSPrint("nwfs: errors dismounting volume %s", volume->VolumeName); + + return; +} + +int nwfs_statfs(struct super_block *sb, struct statfs *buf) +{ + register VOLUME *volume = (VOLUME *) sb->u.generic_sbp; + register ULONG bpb = (IO_BLOCK_SIZE / LogicalBlockSize); + + buf->f_type = NWFS_LINUX_FS_ID; + buf->f_bsize = LogicalBlockSize; + buf->f_blocks = volume->VolumeClusters * volume->BlocksPerCluster * bpb; + buf->f_bfree = volume->VolumeFreeClusters * volume->BlocksPerCluster * bpb; + buf->f_bavail = volume->VolumeFreeClusters * volume->BlocksPerCluster * bpb; + buf->f_namelen = 255; + + return 0; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/symlink.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/symlink.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/symlink.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/symlink.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,94 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : SYMLINK.C +* DESCRIP : NWFS Symbolic Link Code for Linux +* DATE : June 24, 1999 +* +* This code was adapted from the Linux UMSDOS File system for nwfs. +* +***************************************************************************/ + +#include "globals.h" + + +struct inode_operations nwfs_symlink_inode_operations = +{ + readlink: page_readlink, + follow_link: page_follow_link, + setattr: nwfs_notify_change, +}; + +static int nwfs_symlink_readpage(struct file *file, struct page *page) +{ + register int length, ccode; + register struct inode *inode = (struct inode *)page->mapping->host; + BYTE *buf = (BYTE *) kmap(page); + loff_t loffs = 0; + extern int nwfs_read_file_link(struct inode *, BYTE *, int, loff_t *); + + length = inode->i_size; + ccode = nwfs_read_file_link(inode, buf, length, &loffs); + if (ccode != length) + { + SetPageError(page); + kunmap(page); + UnlockPage(page); + return -EIO; + } + + buf[length] = '\0'; + SetPageUptodate(page); + kunmap(page); + UnlockPage(page); + + return 0; +} + +struct address_space_operations nwfs_symlink_aops = +{ + readpage: nwfs_symlink_readpage, +}; + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/trustee.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/trustee.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/trustee.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/trustee.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,107 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : TRUSTEE.C +* DESCRIP : NWFS Trustee Hashing Functions +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +THASH *GetTrusteeEntry(VOLUME *volume, ULONG entry, ULONG Directory) +{ + register THASH *tname; + register THASH_LIST *HashTable; + register ULONG Value, pos; + + Value = (Directory & (volume->TrusteeHashLimit - 1)); + HashTable = (THASH_LIST *) volume->TrusteeHash; + if (!HashTable) + return 0; + + tname = (THASH *) HashTable[Value].head; + pos = 0; + while (tname) + { + if (tname->Parent == Directory) + { + if (entry == pos) + return tname; + pos++; + } + tname = tname->next; + } + return 0; + +} + +UHASH *GetUserQuotaEntry(VOLUME *volume, ULONG entry, ULONG Directory) +{ + register UHASH *uname; + register UHASH_LIST *HashTable; + register ULONG Value, pos; + + Value = (Directory & (volume->UserQuotaHashLimit - 1)); + HashTable = (UHASH_LIST *) volume->UserQuotaHash; + if (!HashTable) + return 0; + + uname = (UHASH *) HashTable[Value].head; + pos = 0; + while (uname) + { + if (uname->Parent == Directory) + { + if (entry == pos) + return uname; + pos++; + } + uname = uname->next; + } + return 0; + +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/volume.c linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/volume.c --- linux-2.4.20-wolk4.6-fullkernel/fs/nwfs/volume.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/nwfs/volume.c 2003-08-17 21:29:02.000000000 +0200 @@ -0,0 +1,2077 @@ + +/*************************************************************************** +* +* Copyright (c) 1998, 1999 Jeff V. Merkey +* 895 West Center Street +* Orem, Utah 84057 +* jmerkey@utah-nac.org +* +* 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, version 2, or 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 are free to modify and re-distribute this program in accordance +* with the terms specified in the GNU Public License. The copyright +* contained in this code is required to be present in any derivative +* works and you are required to provide the source code for this +* program as part of any commercial or non-commercial distribution. +* You are required to respect the rights of the Copyright holders +* named within this code. +* +* jmerkey@utah-nac.org is the official maintainer of +* this code. You are encouraged to report any bugs, problems, fixes, +* suggestions, and comments about this software to jmerkey@utah-nac.org +* or linux-kernel@vger.kernel.org. New releases, patches, bug fixes, and +* technical documentation can be found at www.kernel.org. We will +* periodically post new releases of this software to www.kernel.org +* that contain bug fixes and enhanced capabilities. +* +* Original Authorship : +* source code written by Jeff V. Merkey +* +* Original Contributors : +* Jeff V. Merkey +* Darren Major +* +* +**************************************************************************** +* +* +* AUTHOR : Jeff V. Merkey (jmerkey@utah-nac.org) +* FILE : VOLUME.C +* DESCRIP : NWFS Netware Volume Manager +* DATE : November 1, 1998 +* +* +***************************************************************************/ + +#include "globals.h" + +#if (LINUX_SLEEP) +NWFSInitMutex(ScanSemaphore); +#endif + +void NWLockScan(void) +{ +#if (LINUX_SLEEP) + if (WaitOnSemaphore(&ScanSemaphore) == -EINTR) + NWFSPrint("lock scan was interrupted\n"); +#endif +} + +void NWUnlockScan(void) +{ +#if (LINUX_SLEEP) + SignalSemaphore(&ScanSemaphore); +#endif +} + +void NWLockWK(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->WK_spinlock, volume->WK_flags); +#else + if (WaitOnSemaphore(&volume->WKSemaphore) == -EINTR) + NWFSPrint("lock workspace was interupted\n"); +#endif +#endif +} + +void NWUnlockWK(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->WK_spinlock, volume->WK_flags); +#else + SignalSemaphore(&volume->WKSemaphore); +#endif +#endif +} + +void NWLockNSWK(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_irqsave(&volume->NS_spinlock, volume->NS_flags); +#else + if (WaitOnSemaphore(&volume->NSSemaphore) == -EINTR) + NWFSPrint("lock ns workspace was interupted\n"); +#endif +#endif +} + +void NWUnlockNSWK(VOLUME *volume) +{ +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_unlock_irqrestore(&volume->NS_spinlock, volume->NS_flags); +#else + SignalSemaphore(&volume->NSSemaphore); +#endif +#endif +} + +// +// suballocation workspace memory +// + +void FreeWorkspace(VOLUME *volume, VOLUME_WORKSPACE *wk) +{ + NWLockWK(volume); + +#if (CONSERVE_MEMORY) + if (volume->WKCount > MAX_WORKSPACE_BUFFERS) + { + NWUnlockWK(volume); + NWFSFree(wk); + return; + } +#endif + + if (!volume->WKHead) + { + volume->WKHead = volume->WKTail = wk; + wk->next = wk->prior = 0; + } + else + { + volume->WKTail->next = wk; + wk->next = 0; + wk->prior = volume->WKTail; + volume->WKTail = wk; + } + volume->WKCount++; + + NWUnlockWK(volume); + return; +} + +VOLUME_WORKSPACE *AllocateWorkspace(VOLUME *volume) +{ + register VOLUME_WORKSPACE *wk; + + NWLockWK(volume); + if (volume->WKHead) + { + wk = volume->WKHead; + volume->WKHead = wk->next; + if (volume->WKHead) + volume->WKHead->prior = NULL; + else + volume->WKTail = NULL; + + if (volume->WKCount) + volume->WKCount--; + + NWUnlockWK(volume); + return wk; + } + else + { + NWUnlockWK(volume); + + wk = NWFSCacheAlloc((volume->ClusterSize + + (sizeof(VOLUME_WORKSPACE) * 2)), + VOLUME_WS_TAG); + if (!wk) + return 0; + + NWFSSet(wk, 0, (volume->ClusterSize + + (sizeof(VOLUME_WORKSPACE) * 2))); + return wk; + } + NWUnlockWK(volume); + return 0; +} + +void FreeWorkspaceMemory(VOLUME *volume) +{ + register VOLUME_WORKSPACE *wk; + + NWLockWK(volume); + while (volume->WKHead) + { + wk = volume->WKHead; + volume->WKHead = wk->next; + + if (volume->WKCount) + volume->WKCount--; + + NWFSFree(wk); + } + volume->WKHead = volume->WKTail = 0; + NWUnlockWK(volume); + return; +} + +// +// namespace workspace memory +// + +void FreeNSWorkspace(VOLUME *volume, VOLUME_WORKSPACE *wk) +{ + NWLockNSWK(volume); + +#if (CONSERVE_MEMORY) + if (volume->NSCount > MAX_WORKSPACE_BUFFERS) + { + NWUnlockNSWK(volume); + NWFSFree(wk); + return; + } +#endif + + if (!volume->NSHead) + { + volume->NSHead = volume->NSTail = wk; + wk->next = wk->prior = 0; + } + else + { + volume->NSTail->next = wk; + wk->next = 0; + wk->prior = volume->NSTail; + volume->NSTail = wk; + } + volume->NSCount++; + + NWUnlockNSWK(volume); + return; +} + +VOLUME_WORKSPACE *AllocateNSWorkspace(VOLUME *volume) +{ + register VOLUME_WORKSPACE *wk; + + NWLockNSWK(volume); + if (volume->NSHead) + { + wk = volume->NSHead; + volume->NSHead = wk->next; + if (volume->NSHead) + volume->NSHead->prior = NULL; + else + volume->NSTail = NULL; + + if (volume->NSCount) + volume->NSCount--; + + NWUnlockNSWK(volume); + return wk; + } + else + { + NWUnlockNSWK(volume); + + wk = NWFSCacheAlloc(((sizeof(ROOT) * (volume->NameSpaceCount + 1)) + + (sizeof(VOLUME_WORKSPACE) * 2)), + VOLUME_WS_TAG); + if (!wk) + return 0; + + NWFSSet(wk, 0, ((sizeof(ROOT) * (volume->NameSpaceCount + 1)) + + (sizeof(VOLUME_WORKSPACE) * 2))); + return wk; + } + NWUnlockNSWK(volume); + return 0; +} + +void FreeNSWorkspaceMemory(VOLUME *volume) +{ + register VOLUME_WORKSPACE *wk; + + NWLockNSWK(volume); + while (volume->NSHead) + { + wk = volume->NSHead; + volume->NSHead = wk->next; + + if (volume->NSCount) + volume->NSCount--; + + NWFSFree(wk); + } + volume->NSHead = volume->NSTail = 0; + NWUnlockNSWK(volume); + return; +} + + +// +// NOTE: This code is here for debugging purposes. +// + +BYTE *dumpRecordBytes(BYTE *p, ULONG size) +{ + register ULONG i, r, total, count; + register BYTE *op = p; + + count = size / 16; + + NWFSPrint(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); + for (r=0; r < count; r++) + { + NWFSPrint("%08X ", (unsigned int)(p - op)); + for (total = 0, i=0; i < 16; i++, total++) + { + NWFSPrint(" %02X", (BYTE) p[i]); + } + NWFSPrint(" "); + for (i=0; i < total; i++) + { + if ((p[i] < 32) || (p[i] > 126)) + NWFSPrint("."); + else + NWFSPrint("%c", p[i]); + } + NWFSPrint("\n"); + + p = (void *)((ULONG) p + (ULONG) total); + } + return p; + +} + +// +// NOTE: This code is here for debugging purposes. +// + +BYTE *dumpRecord(BYTE *p, ULONG size) +{ + register int i, r, count; + register BYTE *op = p; + ULONG *lp; + + count = size / 16; + + lp = (ULONG *) p; + + for (r=0; r < count; r++) + { + NWFSPrint("%08X ", (unsigned int)(p - op)); + for (i=0; i < (16 / 4); i++) + { + NWFSPrint(" %08X", (unsigned int) lp[i]); + } + NWFSPrint(" "); + for (i=0; i < 16; i++) + { + if ((p[i] < 32) || (p[i] > 126)) + NWFSPrint("."); + else + NWFSPrint("%c", p[i]); + } + NWFSPrint("\n"); + + p = (void *)((ULONG) p + (ULONG) 16); + lp = (ULONG *) p; + } + return p; + +} + +// This is the standard mount routine for mounting a NetWare volume. + +static ULONG MountFileVolume(VOLUME *volume) +{ + register ULONG retCode, ccode, r, NameSpace, i; + extern ULONG ReadFATTable(VOLUME *volume); + extern ULONG ReadDirectoryTable(VOLUME *volume); + extern ULONG ReadSuballocTable(VOLUME *volume); + extern ULONG ReadExtendedDirectory(VOLUME *volume); + extern void FreeVolumeNamespaces(VOLUME *volume); + ULONG month, day, year, hour, minute, second; + BYTE FoundNameSpace[MAX_NAMESPACES]; + + if (!volume->VolumePresent) + { + NWFSPrint("nwfs: volume %s is missing one or more segments\n", volume->VolumeName); + return -5; + } + + if (VolumeMountedTable[volume->VolumeNumber]) + { +#if (ALLOW_REMOUNT) + volume->InUseCount++; + return 0; +#else + NWFSPrint("nwfs: volume %s disk(%d) already mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; +#endif + } + +#if (ALLOW_REMOUNT) + volume->InUseCount++; +#endif + + month = day = year = hour = minute = second = 0; + GetNWTime(NWFSSystemToNetwareTime(NWFSGetSystemTime()), + &second, &minute, &hour, &day, &month, &year); + NWFSPrint("Mounting Volume %s %02d/%02d/%02d %02d:%02d:%02d\n", + volume->VolumeName, + (int)month, (int)day, (int)year, + (int)hour, (int)minute, (int)second); + + if (nwvp_vpartition_open(volume->nwvp_handle) != 0) + { + NWFSPrint("nwfs: volume %s could not attach to NVMP\n", + volume->VolumeName); +#if (ALLOW_REMOUNT) + if (volume->InUseCount) + volume->InUseCount--; +#endif + return -1; + } + +#if (LINUX_SLEEP) +#if (LINUX_SPIN) + spin_lock_init(&volume->WK_spinlock); + spin_lock_init(&volume->NS_spinlock); + spin_lock_init(&volume->NameHash_spinlock); + spin_lock_init(&volume->DirHash_spinlock); + spin_lock_init(&volume->ParentHash_spinlock); + spin_lock_init(&volume->TrusteeHash_spinlock); + spin_lock_init(&volume->QuotaHash_spinlock); + spin_lock_init(&volume->ExtHash_spinlock); + spin_lock_init(&volume->NameSpace_spinlock); + + volume->WK_flags = 0; + volume->NS_flags = 0; + volume->NameHash_flags = 0; + volume->DirHash_flags = 0; + volume->ParentHash_flags = 0; + volume->TrusteeHash_flags = 0; + volume->QuotaHash_flags = 0; + volume->ExtHash_flags = 0; + volume->NameSpace_flags = 0; + +#else + AllocateSemaphore(&volume->WKSemaphore, 1); + AllocateSemaphore(&volume->NSSemaphore, 1); + AllocateSemaphore(&volume->NameHashSemaphore, 1); + AllocateSemaphore(&volume->DirHashSemaphore, 1); + AllocateSemaphore(&volume->ParentHashSemaphore, 1); + AllocateSemaphore(&volume->TrusteeHashSemaphore, 1); + AllocateSemaphore(&volume->QuotaHashSemaphore, 1); + AllocateSemaphore(&volume->ExtHashSemaphore, 1); + AllocateSemaphore(&volume->NameSpaceSemaphore, 1); +#endif + + for (i=0; i < 128; i++) + AllocateSemaphore(&volume->SuballocSemaphore[i], 1); + AllocateSemaphore(&volume->FatSemaphore, 1); + AllocateSemaphore(&volume->VolumeSemaphore, 1); + AllocateSemaphore(&volume->DirBlockSemaphore, 1); + AllocateSemaphore(&volume->DirAssignSemaphore, 1); + +#endif + + // Initialize orphan and deleted list heads + volume->HashMountHead = volume->HashMountTail = 0; + volume->DelHashMountHead = volume->DelHashMountTail = 0; + + // initialize suballocation workspaces + volume->WKHead = volume->WKTail = 0; + volume->WKCount = 0; + + // initialize namespace workspaces + volume->NSHead = volume->NSTail = 0; + volume->NSCount = 0; + + // initialize suballocation tables + volume->SuballocCount = 0; + volume->SuballocChainComplete = 0; + for (i=0; i < 5; i++) + volume->SuballocChainFlag[i] = 0; + + volume->DirectoryCount = 0; + volume->FreeDirectoryCount = 0; + volume->FreeDirectoryBlockCount = 0; + volume->VolumeAllocatedClusters = 0; + volume->VolumeFreeClusters = 0; + volume->DeletedDirNo = 0; + + volume->MinimumFATBlocks = MIN_FAT_LRU_BLOCKS; + volume->MaximumFATBlocks = MAX_FAT_LRU_BLOCKS; + + volume->MountedNumberOfSegments = volume->NumberOfSegments; + volume->MountedVolumeClusters = volume->VolumeClusters; + + if (InitializeFAT_LRU(volume)) + { + retCode = -2; + goto FATInitFailed; + } + + if (InitializeDirBlockHash(volume)) + { + retCode = -2; + goto DirBlockInitFailed; + } + + if (InitializeDirAssignHash(volume)) + { + retCode = -2; + goto DirAssignInitFailed; + } + + // allocate hash memory for namespaces and directory blocks + + volume->ParentHash = NWFSCacheAlloc(PARENT_HASH_SIZE, PAR_HASH_TAG); + if (!volume->ParentHash) + { + retCode = -2; + goto HashInitFailed; + } + volume->ParentHashLimit = NUMBER_OF_PARENT_ENTRIES; + NWFSSet(volume->ParentHash, 0, PARENT_HASH_SIZE); + + volume->ExtDirHash = NWFSCacheAlloc(EXT_HASH_SIZE, EXD_HASH_TAG); + if (!volume->ExtDirHash) + { + retCode = -2; + goto HashInitFailed; + } + volume->ExtDirHashLimit = NUMBER_OF_EXT_HASH_ENTRIES; + NWFSSet(volume->ExtDirHash, 0, EXT_HASH_SIZE); + + volume->TrusteeHash = NWFSCacheAlloc(TRUSTEE_HASH_SIZE, TRS_HASH_TAG); + if (!volume->TrusteeHash) + { + retCode = -2; + goto HashInitFailed; + } + volume->TrusteeHashLimit = NUMBER_OF_TRUSTEE_ENTRIES; + NWFSSet(volume->TrusteeHash, 0, TRUSTEE_HASH_SIZE); + + volume->UserQuotaHash = NWFSCacheAlloc(USER_QUOTA_HASH_SIZE, QUO_HASH_TAG); + if (!volume->UserQuotaHash) + { + retCode = -2; + goto HashInitFailed; + } + volume->UserQuotaHashLimit = NUMBER_OF_QUOTA_ENTRIES; + NWFSSet(volume->UserQuotaHash, 0, USER_QUOTA_HASH_SIZE); + + volume->DirectoryNumberHash = NWFSCacheAlloc(DIR_NUMBER_HASH_SIZE, DNM_HASH_TAG); + if (!volume->DirectoryNumberHash) + { + retCode = -2; + goto HashInitFailed; + } + volume->DirectoryNumberHashLimit = NUMBER_OF_DIR_NUMBER_ENTRIES; + NWFSSet(volume->DirectoryNumberHash, 0, DIR_NUMBER_HASH_SIZE); + + // set default name space to MSDOS + volume->NameSpaceDefault = DOS_NAME_SPACE; + + // check for duplicate namespaces + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + for (r=0; r < volume->NameSpaceCount; r++) + { + if (!r && volume->NameSpaceID[r]) + { + NWFSPrint("nwfs: dos name space not present\n"); + retCode = -2; + goto HashInitFailed; + } + + if (r && (FoundNameSpace[volume->NameSpaceID[r] & 0xF])) + { + NWFSPrint("nwfs: duplicate volume namespaces detected\n"); + retCode = -2; + goto HashInitFailed; + } + FoundNameSpace[volume->NameSpaceID[r] & 0xF] = TRUE; + } + + // look for unix namespace, if found use as default. + for (r=0; r < volume->NameSpaceCount; r++) + { + NameSpace = volume->NameSpaceID[r]; + if (NameSpace == UNIX_NAME_SPACE) + { + volume->NameSpaceDefault = UNIX_NAME_SPACE; + break; + } + } + + // if no unix namespace, default to LONG namespace + if (volume->NameSpaceDefault != UNIX_NAME_SPACE) + { + for (r=0; r < volume->NameSpaceCount; r++) + { + NameSpace = volume->NameSpaceID[r]; + if (NameSpace == LONG_NAME_SPACE) + { + volume->NameSpaceDefault = LONG_NAME_SPACE; + break; + } + } + } + +#if (MOUNT_VERBOSE) + switch (volume->NameSpaceDefault) + { + case DOS_NAME_SPACE: + NWFSPrint("*** DOS Name Space ***\n"); + break; + + case MAC_NAME_SPACE: + NWFSPrint("*** MAC Name Space ***\n"); + break; + + case UNIX_NAME_SPACE: + NWFSPrint("*** UNIX Name Space ***\n"); + break; + + case LONG_NAME_SPACE: + NWFSPrint("*** LONG Name Space ***\n"); + break; + + case NT_NAME_SPACE: + NWFSPrint("*** NT Name_Space ***\n"); + break; + } +#endif + + for (r=0; r < volume->NameSpaceCount; r++) + { + NameSpace = volume->NameSpaceID[r]; + if (volume->VolumeNameHash[NameSpace & 0xF]) + { + NWFSPrint("nwfs: name space entries detected that are identical\n"); + retCode = -2; + goto HashInitFailed; + } + + volume->VolumeNameHash[NameSpace & 0xF] = NWFSCacheAlloc(VOLUME_NAME_HASH_SIZE, + NAM_HASH_TAG); + if (!volume->VolumeNameHash[NameSpace & 0xF]) + { + retCode = -2; + goto HashInitFailed; + } + volume->VolumeNameHashLimit[NameSpace & 0xF] = NUMBER_OF_NAME_HASH_ENTRIES; + NWFSSet(volume->VolumeNameHash[NameSpace & 0xF], 0, VOLUME_NAME_HASH_SIZE); + } + + if (InitializeClusterFreeList(volume)) + { + retCode = -2; + goto FreeBlockInitFailed; + } + + if (InitializeClusterAssignedList(volume)) + { + retCode = -2; + goto AssignedBlockInitFailed; + } + + retCode = ReadFATTable(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error reading FAT tables\n"); + goto ReadFATInitFailed; + } + + retCode = ReadExtendedDirectory(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error reading extended directory\n"); + goto ReadExtendedDirectoryInitFailed; + } + + retCode = ReadSuballocTable(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error reading suballoc tables\n"); + goto ReadSuballocInitFailed; + } + + retCode = ReadDirectoryTable(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error reading directory tables\n"); + goto ReadDirectoryInitFailed; + } + + // Process any hash records that were placed in the mount + // list because their DirNo was less than their assigned + // parent. + + retCode = ProcessOrphans(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error processing orphan hash records\n"); + goto LinkNameSpacesFailed; + } + + // now link the namespace records together + retCode = LinkVolumeNameSpaces(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error linking volume namespaces\n"); + goto LinkNameSpacesFailed; + } + + // this procedure performs two functions. It builds the suballocation + // free list maps and checks the fat table allocation map and frees + // any unassigned clusters for which there is no valid fat chain entry + // for the volume. + + retCode = AdjustAllocatedClusters(volume); + if (retCode) + NWFSPrint("%d clusters have been freed\n", (int)retCode); + + // if the DELETED.SAV and _NETWARE directories do not exist, + // then create them. We also check for suballocation chain + // heads, if they do not exist and suballocation is enabled, + // we create these as well. + + retCode = InitializeVolumeDirectory(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: could not initialize volume directory\n"); + goto LinkNameSpacesFailed; + } + + if (volume->VolumeFlags & SUB_ALLOCATION_ON) + { + if (!volume->SuballocChainComplete) + { + retCode = -2; + NWFSPrint("nwfs: suballoc tables are malformed\n"); + goto LinkNameSpacesFailed; + } + } + + volume->MountTime = NWFSGetSystemTime(); + volume->FileSeed = 0; + volume->AllocSegment = 0; + VolumeMountedTable[volume->VolumeNumber] = TRUE; + + month = day = year = hour = minute = second = 0; + GetNWTime(NWFSSystemToNetwareTime(NWFSGetSystemTime()), + &second, &minute, &hour, &day, &month, &year); + NWFSPrint("Volume %s Mounted %02d/%02d/%02d %02d:%02d:%02d\n", + volume->VolumeName, + (int)month, (int)day, (int)year, + (int)hour, (int)minute, (int)second); +#if (VERBOSE) + NWFSPrint("dirs-%d empty_dirs-%d free_dir_blocks-%d\n", + (int)volume->DirectoryCount, + (int)volume->FreeDirectoryCount, + (int)volume->FreeDirectoryBlockCount); +#endif + + return 0; + +// error exit code paths + +LinkNameSpacesFailed:; +ReadDirectoryInitFailed:; +ReadSuballocInitFailed:; + // free any suballoc directory records + for (i=0; i < MAX_SUBALLOC_NODES; i++) + { + if (volume->SuballocChain[i]) + NWFSFree(volume->SuballocChain[i]); + volume->SuballocChain[i] = 0; + } + + // release suballoc free lists + for (i=0; i < volume->SuballocListCount; i++) + { + if (volume->FreeSuballoc[i]) + { + ccode = FreeBitBlockList(volume->FreeSuballoc[i]); + if (ccode) + NWFSPrint("nwfs: could not free suballoc bit list (%d)\n", (int)i); + NWFSFree(volume->FreeSuballoc[i]); + } + volume->FreeSuballoc[i] = 0; + } + +ReadExtendedDirectoryInitFailed:; +ReadFATInitFailed:; + FreeClusterAssignedList(volume); + +AssignedBlockInitFailed:; + FreeClusterFreeList(volume); + +FreeBlockInitFailed:; +HashInitFailed:; + FreeVolumeNamespaces(volume); + FreeDirAssignHash(volume); + +DirAssignInitFailed:; + FreeDirBlockHash(volume); + +DirBlockInitFailed:; + FreeFAT_LRU(volume); + FlushVolumeLRU(volume); + +FATInitFailed:; + FreeWorkspaceMemory(volume); + FreeNSWorkspaceMemory(volume); + nwvp_vpartition_close(volume->nwvp_handle); + +#if (ALLOW_REMOUNT) + if (volume->InUseCount) + volume->InUseCount--; +#endif + + return retCode; + +} + +ULONG MountVolumeByHandle(VOLUME *volume) +{ + register ULONG ccode; + + NWLockScan(); + ccode = MountFileVolume(volume); + NWUnlockScan(); + + return ccode; +} + +ULONG MountVolume(BYTE *VolumeName) +{ + register ULONG retCode, i, len; + register BYTE *p; + + len = 0; + p = VolumeName; + while (*p++) + len++; + + NWLockScan(); + for (i=0; i < MaximumNumberOfVolumes; i++) + { + if (VolumeTable[i]) + { + if (len == VolumeTable[i]->VolumeNameLength) + { + if (!NWFSCompare(VolumeName, VolumeTable[i]->VolumeName, + VolumeTable[i]->VolumeNameLength)) + { + retCode = MountFileVolume(VolumeTable[i]); + NWUnlockScan(); + return retCode; + } + } + } + } + NWUnlockScan(); + return -1; + +} + +VOLUME *MountHandledVolume(BYTE *VolumeName) +{ + register ULONG i, retCode, len; + register BYTE *p; + + len = 0; + p = VolumeName; + while (*p++) + len++; + + NWLockScan(); + for (i=0; i < MaximumNumberOfVolumes; i++) + { + if (VolumeTable[i]) + { + if (len == VolumeTable[i]->VolumeNameLength) + { + if (!NWFSCompare(VolumeName, VolumeTable[i]->VolumeName, + VolumeTable[i]->VolumeNameLength)) + { + retCode = MountFileVolume(VolumeTable[i]); + if (!retCode) + { + NWUnlockScan(); + return VolumeTable[i]; + } + NWUnlockScan(); + return 0; + } + } + } + } + NWUnlockScan(); + return 0; + +} + +ULONG MountAllVolumes(void) +{ + register ULONG retCode, finalCode = 0; + register ULONG i; + + NWLockScan(); + for (i=0; i < MaximumNumberOfVolumes; i++) + { + if (VolumeTable[i]) + { + retCode = MountFileVolume(VolumeTable[i]); + if (retCode) + { + finalCode = retCode; + NWFSPrint("nwfs: error mounting %s\n", VolumeTable[i]->VolumeName); + } + } + } + NWUnlockScan(); + return finalCode; + +} + +static ULONG DismountFileVolume(VOLUME *volume, ULONG force) +{ + register ULONG i, retCode; + extern void FreeVolumeNamespaces(VOLUME *volume); + extern ULONG CompareDirectoryTable(VOLUME *volume); + extern ULONG SyncVolumeLRU(LRU_HANDLE *lru_handle, VOLUME *volume); + extern void DisplayLRUInfo(LRU_HANDLE *lru_handle); + + if (!VolumeMountedTable[volume->VolumeNumber]) + { + NWFSPrint("Volume %s disk(%d) is not mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; + } + +#if (ALLOW_REMOUNT) + if (!force) + { + if (!volume->InUseCount) + { + NWFSPrint("Volume %s disk(%d) is not in use\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; + } + + volume->InUseCount--; + if (volume->InUseCount) + return 0; + } +#endif + + NWFSPrint("Dismounting Volume %s\n", volume->VolumeName); + +#if (VERBOSE) + DisplayLRUInfo(&DataLRU); + DisplayLRUInfo(&JournalLRU); + DisplayLRUInfo(&FATLRU); +#endif + + SyncVolumeLRU(&DataLRU, volume); + SyncVolumeLRU(&JournalLRU, volume); + + FreeFAT_LRU(volume); + FlushVolumeLRU(volume); + + FreeClusterAssignedList(volume); + FreeClusterFreeList(volume); + FreeVolumeNamespaces(volume); + + FreeDirBlockHash(volume); + FreeDirAssignHash(volume); + + // free any suballoc directory records + for (i=0; i < MAX_SUBALLOC_NODES; i++) + { + if (volume->SuballocChain[i]) + NWFSFree(volume->SuballocChain[i]); + volume->SuballocChain[i] = 0; + } + + // release suballoc free lists + for (i=0; i < volume->SuballocListCount; i++) + { + if (volume->FreeSuballoc[i]) + { + retCode = FreeBitBlockList(volume->FreeSuballoc[i]); + if (retCode) + NWFSPrint("nwfs: could not free suballoc bit list (%d)\n", (int)i); + NWFSFree(volume->FreeSuballoc[i]); + } + volume->FreeSuballoc[i] = 0; + } + + FreeWorkspaceMemory(volume); + FreeNSWorkspaceMemory(volume); + nwvp_vpartition_close(volume->nwvp_handle); + + VolumeMountedTable[volume->VolumeNumber] = 0; + + return 0; + +} + + +ULONG DismountVolume(BYTE *VolumeName) +{ + register ULONG retCode, i, len; + register BYTE *p; + + len = 0; + p = VolumeName; + while (*p++) + len++; + + NWLockScan(); + for (i=0; i < MaximumNumberOfVolumes; i++) + { + if (VolumeTable[i]) + { + if (len == VolumeTable[i]->VolumeNameLength) + { + if (!NWFSCompare(VolumeName, VolumeTable[i]->VolumeName, + VolumeTable[i]->VolumeNameLength)) + { + retCode = DismountFileVolume(VolumeTable[i], 0); + NWUnlockScan(); + return retCode; + } + } + } + } + NWUnlockScan(); + return -1; +} + +ULONG DismountVolumeByHandle(VOLUME *volume) +{ + register ULONG ccode; + + NWLockScan(); + ccode = DismountFileVolume(volume, 0); + NWUnlockScan(); + + return ccode; +} + +VOLUME *GetVolumeHandle(BYTE *VolumeName) +{ + register VOLUME *volume; + register BYTE *p; + register ULONG i, len; + + len = 0; + p = VolumeName; + while (*p++) + len++; + + NWLockScan(); + for (i=0; i < MaximumNumberOfVolumes; i++) + { + if (VolumeTable[i]) + { + if (len == VolumeTable[i]->VolumeNameLength) + { + if (!NWFSCompare(VolumeName, VolumeTable[i]->VolumeName, len)) + { + volume = VolumeTable[i]; + NWUnlockScan(); + return volume; + } + } + } + } + NWUnlockScan(); + return 0; +} + +ULONG DismountAllVolumes(void) +{ + register ULONG retCode, finalCode = 0; + register ULONG i; + + NWLockScan(); + for (i=0; i < MaximumNumberOfVolumes; i++) + { + if (VolumeTable[i]) + { + if (!VolumeMountedTable[i]) + continue; + retCode = DismountFileVolume(VolumeTable[i], TRUE); + if (retCode) + { + finalCode = retCode; + NWFSPrint("nwfs: error dismounting %s\n", VolumeTable[i]->VolumeName); + } + } + } + NWUnlockScan(); + return finalCode; +} + +// WARNING!!!. This mount routine is used to completely wipe all +// file system data from a particular volume. If you call it, +// all your file system data will be cleared. This routine is used +// by the utilities to re-initialize a volume during imaging +// and restore operations. + +ULONG MountUtilityVolume(VOLUME *volume) +{ + register ULONG retCode, i; + extern ULONG ReadFATTable(VOLUME *volume); + extern ULONG ReadSuballocTable(VOLUME *volume); + ULONG month, day, year, hour, minute, second; + + if (!volume->VolumePresent) + { + NWFSPrint("nwfs: volume %s is missing one or more segments\n", volume->VolumeName); + return -5; + } + + if (VolumeMountedTable[volume->VolumeNumber]) + { + NWFSPrint("nwfs: volume %s disk(%d) already mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; + } + + NWFSPrint("Mounting FAT Tables Volume %s\n", volume->VolumeName); + + if (nwvp_vpartition_open(volume->nwvp_handle) != 0) + { + NWFSPrint("nwfs: volume %s could not attach to NVMP\n", + volume->VolumeName); + return -1; + } + + month = day = year = hour = minute = second = 0; + GetNWTime(NWFSSystemToNetwareTime(NWFSGetSystemTime()), + &second, &minute, &hour, &day, &month, &year); + NWFSPrint("Mounting Volume %s %02d/%02d/%02d %02d:%02d:%02d\n", + volume->VolumeName, + (int)month, (int)day, (int)year, + (int)hour, (int)minute, (int)second); + + volume->SuballocCount = 0; + volume->SuballocChainComplete = 0; + for (i=0; i < 5; i++) + volume->SuballocChainFlag[i] = 0; + + volume->DirectoryCount = 0; + volume->FreeDirectoryCount = 0; + volume->FreeDirectoryBlockCount = 0; + volume->VolumeAllocatedClusters = 0; + volume->VolumeFreeClusters = 0; + volume->DeletedDirNo = 0; + + volume->MinimumFATBlocks = MIN_FAT_LRU_BLOCKS; + volume->MaximumFATBlocks = MAX_FAT_LRU_BLOCKS; + + volume->MountedNumberOfSegments = volume->NumberOfSegments; + volume->MountedVolumeClusters = volume->VolumeClusters; + + if (InitializeFAT_LRU(volume)) + { + retCode = -2; + goto FATInitFailed; + } + + if (InitializeClusterFreeList(volume)) + { + retCode = -2; + goto FreeBlockInitFailed; + } + + if (InitializeClusterAssignedList(volume)) + { + retCode = -2; + goto AssignedBlockInitFailed; + } + + retCode = ReadFATTable(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error reading FAT tables\n"); + goto ReadFATInitFailed; + } + + if (volume->VolumeFlags & SUB_ALLOCATION_ON) + { + retCode = NWCreateSuballocRecords(volume); + if (retCode) + { + NWFSPrint("nwfs: error creating suballoc tables (%d)\n", + (int)retCode); + retCode = -2; + goto ReadSuballocInitFailed; + } + + if (!volume->SuballocChainComplete) + { + retCode = -2; + NWFSPrint("nwfs: suballoc tables are malformed (um)\n"); + goto ReadSuballocInitFailed; + } + } + + retCode = BuildChainAssignment(volume, volume->FirstDirectory, 0); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error checking primary directory chain\n"); + goto ReadSuballocInitFailed; + } + + retCode = BuildChainAssignment(volume, volume->SecondDirectory, 0); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error checking mirror directory chain\n"); + goto ReadSuballocInitFailed; + } + + // this function will free all unused clusters from a volume. + retCode = AdjustAllocatedClusters(volume); + if (retCode) + NWFSPrint("%d clusters have been freed\n", (int)retCode); + + volume->MountTime = NWFSGetSystemTime(); + volume->FileSeed = 0; + volume->AllocSegment = 0; + VolumeMountedTable[volume->VolumeNumber] = TRUE; + + NWFSPrint("Volume %s FAT Tables Mounted\n", volume->VolumeName); + + return 0; + +// error exit code paths + +ReadSuballocInitFailed:; + // free any suballoc directory records + for (i=0; i < MAX_SUBALLOC_NODES; i++) + { + if (volume->SuballocChain[i]) + NWFSFree(volume->SuballocChain[i]); + volume->SuballocChain[i] = 0; + } + + // release suballoc free lists + for (i=0; i < volume->SuballocListCount; i++) + { + if (volume->FreeSuballoc[i]) + { + retCode = FreeBitBlockList(volume->FreeSuballoc[i]); + if (retCode) + NWFSPrint("nwfs: could not free suballoc bit list (%d)\n", (int)i); + NWFSFree(volume->FreeSuballoc[i]); + } + volume->FreeSuballoc[i] = 0; + } + +ReadFATInitFailed:; + FreeClusterAssignedList(volume); + +AssignedBlockInitFailed:; + FreeClusterFreeList(volume); + +FreeBlockInitFailed:; + FreeFAT_LRU(volume); + FlushVolumeLRU(volume); + +FATInitFailed:; + FreeWorkspaceMemory(volume); + FreeNSWorkspaceMemory(volume); + nwvp_vpartition_close(volume->nwvp_handle); + + return retCode; + +} + +ULONG DismountUtilityVolume(VOLUME *volume) +{ + register ULONG i, retCode; + extern void FreeVolumeNamespaces(VOLUME *volume); + + if (!VolumeMountedTable[volume->VolumeNumber]) + { + NWFSPrint("Volume %s disk(%d) is not mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; + } + + NWFSPrint("Dismounting FAT Tables Volume %s\n", volume->VolumeName); + + FreeFAT_LRU(volume); + FlushVolumeLRU(volume); + + FreeClusterAssignedList(volume); + FreeClusterFreeList(volume); + + // free any suballoc directory records + for (i=0; i < MAX_SUBALLOC_NODES; i++) + { + if (volume->SuballocChain[i]) + NWFSFree(volume->SuballocChain[i]); + volume->SuballocChain[i] = 0; + } + + // release suballoc free lists + for (i=0; i < volume->SuballocListCount; i++) + { + if (volume->FreeSuballoc[i]) + { + retCode = FreeBitBlockList(volume->FreeSuballoc[i]); + if (retCode) + NWFSPrint("nwfs: could not free suballoc bit list (%d)\n", (int)i); + NWFSFree(volume->FreeSuballoc[i]); + } + volume->FreeSuballoc[i] = 0; + } + FreeWorkspaceMemory(volume); + FreeNSWorkspaceMemory(volume); + nwvp_vpartition_close(volume->nwvp_handle); + + VolumeMountedTable[volume->VolumeNumber] = 0; + + return 0; + +} + +// This mount routine is used to mount a volume with damaged directory +// files after the FAT tables have been scanned and any mirror mismatches +// dealt with, and the directory file needs to be repaired. It is also +// used to add namespaces to a volume from utility mode as well. This +// routine only mounts the FAT tables, and allows you to access the +// NetWare volume meta-data as a collection of files with NWReadFile +// and NWWriteFile. + +ULONG MountRawVolume(VOLUME *volume) +{ + register ULONG retCode, i; + extern ULONG ReadFATTable(VOLUME *volume); + extern ULONG ReadSuballocTable(VOLUME *volume); + ULONG month, day, year, hour, minute, second; + + if (!volume->VolumePresent) + { + NWFSPrint("nwfs: volume %s is missing one or more segments\n", volume->VolumeName); + return -5; + } + + if (VolumeMountedTable[volume->VolumeNumber]) + { + NWFSPrint("nwfs: volume %s disk(%d) already mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; + } + +#if (VERBOSE) + NWFSPrint("Mounting Raw Volume %s\n", volume->VolumeName); +#endif + + month = day = year = hour = minute = second = 0; + GetNWTime(NWFSSystemToNetwareTime(NWFSGetSystemTime()), + &second, &minute, &hour, &day, &month, &year); + NWFSPrint("Mounting Volume %s %02d/%02d/%02d %02d:%02d:%02d\n", + volume->VolumeName, + (int)month, (int)day, (int)year, + (int)hour, (int)minute, (int)second); + + if (nwvp_vpartition_open(volume->nwvp_handle) != 0) + { + NWFSPrint("nwfs: volume %s could not attach to NVMP\n", + volume->VolumeName); + return -1; + } + + volume->SuballocCount = 0; + volume->SuballocChainComplete = 0; + for (i=0; i < 5; i++) + volume->SuballocChainFlag[i] = 0; + + volume->DirectoryCount = 0; + volume->FreeDirectoryCount = 0; + volume->FreeDirectoryBlockCount = 0; + volume->VolumeAllocatedClusters = 0; + volume->VolumeFreeClusters = 0; + volume->DeletedDirNo = 0; + + volume->MinimumFATBlocks = MIN_FAT_LRU_BLOCKS; + volume->MaximumFATBlocks = MAX_FAT_LRU_BLOCKS; + + volume->MountedNumberOfSegments = volume->NumberOfSegments; + volume->MountedVolumeClusters = volume->VolumeClusters; + + if (InitializeFAT_LRU(volume)) + { + retCode = -2; + goto FATInitFailed; + } + + if (InitializeClusterFreeList(volume)) + { + retCode = -2; + goto FreeBlockInitFailed; + } + + if (InitializeClusterAssignedList(volume)) + { + retCode = -2; + goto AssignedBlockInitFailed; + } + + retCode = ReadFATTable(volume); + if (retCode) + { + retCode = -2; + NWFSPrint("nwfs: error reading FAT tables\n"); + goto ReadFATInitFailed; + } + + retCode = ReadSuballocTable(volume); + if (retCode) + NWFSPrint("nwfs: error reading suballoc tables\n"); + + if (volume->VolumeFlags & SUB_ALLOCATION_ON) + { + if (!volume->VolumeSuballocRoot) + retCode = NWCreateSuballocRecords(volume); + if (retCode) + NWFSPrint("nwfs: error creating suballoc tables (%d)\n", + (int)retCode); + + if (!volume->SuballocChainComplete) + NWFSPrint("nwfs: suballoc tables are malformed (raw)\n"); + } + + retCode = BuildChainAssignment(volume, volume->FirstDirectory, 0); + if (retCode) + NWFSPrint("nwfs: error checking primary directory chain\n"); + + retCode = BuildChainAssignment(volume, volume->SecondDirectory, 0); + if (retCode) + NWFSPrint("nwfs: error checking mirror directory chain\n"); + + volume->MountTime = NWFSGetSystemTime(); + volume->FileSeed = 0; + volume->AllocSegment = 0; + VolumeMountedTable[volume->VolumeNumber] = TRUE; + +#if (VERBOSE) + NWFSPrint("Raw Volume %s Mounted\n", volume->VolumeName); +#endif + + return 0; + +// error exit code paths + +ReadFATInitFailed:; + FreeClusterAssignedList(volume); + +AssignedBlockInitFailed:; + FreeClusterFreeList(volume); + +FreeBlockInitFailed:; + FreeFAT_LRU(volume); + FlushVolumeLRU(volume); + +FATInitFailed:; + FreeWorkspaceMemory(volume); + FreeNSWorkspaceMemory(volume); + nwvp_vpartition_close(volume->nwvp_handle); + + return retCode; + +} + +ULONG DismountRawVolume(VOLUME *volume) +{ + register ULONG i, retCode; + extern void FreeVolumeNamespaces(VOLUME *volume); + + if (!VolumeMountedTable[volume->VolumeNumber]) + { + NWFSPrint("Volume %s disk(%d) is not mounted\n", + volume->VolumeName, (int)volume->VolumeDisk); + return -1; + } + +#if (VERBOSE) + NWFSPrint("Dismounting Raw Volume %s\n", volume->VolumeName); +#endif + + FreeFAT_LRU(volume); + FlushVolumeLRU(volume); + + FreeClusterAssignedList(volume); + FreeClusterFreeList(volume); + + // free any suballoc directory records + for (i=0; i < MAX_SUBALLOC_NODES; i++) + { + if (volume->SuballocChain[i]) + NWFSFree(volume->SuballocChain[i]); + volume->SuballocChain[i] = 0; + } + + // release suballoc free lists + for (i=0; i < volume->SuballocListCount; i++) + { + if (volume->FreeSuballoc[i]) + { + retCode = FreeBitBlockList(volume->FreeSuballoc[i]); + if (retCode) + NWFSPrint("nwfs: could not free suballoc bit list (%d)\n", (int)i); + NWFSFree(volume->FreeSuballoc[i]); + } + volume->FreeSuballoc[i] = 0; + } + FreeWorkspaceMemory(volume); + FreeNSWorkspaceMemory(volume); + nwvp_vpartition_close(volume->nwvp_handle); + + VolumeMountedTable[volume->VolumeNumber] = 0; + + return 0; + +} + +ULONG CreateNWFSVolume(ULONG nwvp_handle, nwvp_vpartition_info *vpinfo) +{ + extern ULONG get_block_value(ULONG Type); + register ULONG i, DirNo, j, k; + register VOLUME *volume; + register BYTE *Buffer; + BYTE FoundNameSpace[MAX_NAMESPACES]; + + for (volume = 0, i=0; i < MaximumNumberOfVolumes; i++) + { + volume = VolumeTable[i]; + if (volume) + { + if (volume->nwvp_handle == nwvp_handle) + { + volume->ScanFlag = 0; + volume->volume_segments_ok_flag = (vpinfo->volume_valid_flag == 0xFFFFFFFF) ? 0 : 0xFFFFFFFF; + volume->fat_mirror_ok_flag = (vpinfo->volume_valid_flag == 1) ? 0 : 0xFFFFFFFF; + if (volume->VolumePresent == TRUE) + { + volume->VolumeClusters = vpinfo->cluster_count; + volume->VolumeSectors = volume->VolumeClusters * volume->SectorsPerCluster; + volume->NumberOfSegments = vpinfo->segment_count; + volume->NumberOfFATEntries = volume->VolumeClusters; + volume->MirrorFlag = vpinfo->mirror_flag; + + for(j=0; j < vpinfo->segment_count; j++) + { + volume->SegmentClusterStart[j] = vpinfo->segments[j].relative_cluster_offset; + volume->SegmentClusterSize[j] = vpinfo->segments[j].segment_block_count / vpinfo->blocks_per_cluster; + } + return 0; + } + break; + } + } + } + + for (i=0; i < MAX_VOLUMES; i++) + { + if (!VolumeTable[i]) + { + volume = NWFSAlloc(sizeof(VOLUME), VOLUME_TAG); + if (!volume) + { + NWFSPrint("out of memory in CreateNWFSVolume\n"); + return (ULONG) -1; + } + NWFSSet(volume, 0, sizeof(VOLUME)); + + NumberOfVolumes++; + if (NumberOfVolumes > MaximumNumberOfVolumes) + MaximumNumberOfVolumes = NumberOfVolumes; + + VolumeTable[i] = volume; + volume->VolumeNumber = i; + volume->nwvp_handle = nwvp_handle; + volume->VolumeNameLength = vpinfo->volume_name[0]; + NWFSCopy(volume->VolumeName, &vpinfo->volume_name[1], vpinfo->volume_name[0]); + break; + } + } + + volume->VolumeClusters = vpinfo->cluster_count; + volume->ClusterSize = IO_BLOCK_SIZE * vpinfo->blocks_per_cluster; + volume->BlockSize = IO_BLOCK_SIZE; + volume->SectorsPerCluster = volume->ClusterSize / 512; + volume->SectorsPerBlock = volume->BlockSize / 512; + volume->VolumeSectors = volume->VolumeClusters * volume->SectorsPerCluster; + + volume->BlocksPerCluster = vpinfo->blocks_per_cluster; + volume->NumberOfSegments = vpinfo->segment_count; + volume->FirstFAT = vpinfo->FAT1; + volume->SecondFAT = vpinfo->FAT2; + volume->FirstDirectory = vpinfo->Directory1; + volume->SecondDirectory = vpinfo->Directory2; + volume->NumberOfFATEntries = volume->VolumeClusters; + volume->MirrorFlag = vpinfo->mirror_flag; + volume->DeletedDirNo = 0; + + for(i=0; i < vpinfo->segment_count; i++) + { + volume->SegmentClusterStart[i] = vpinfo->segments[i].relative_cluster_offset; + volume->SegmentClusterSize[i] = vpinfo->segments[i].segment_block_count / vpinfo->blocks_per_cluster; + } + + volume->volume_segments_ok_flag = (vpinfo->volume_valid_flag == 0xFFFFFFFF) ? 0 : 0xFFFFFFFF; + volume->fat_mirror_ok_flag = (vpinfo->volume_valid_flag == 1) ? 0 : 0xFFFFFFFF; + + if (vpinfo->volume_valid_flag == 0) + { + volume->VolumePresent = TRUE; + + Buffer = NWFSIOAlloc(IO_BLOCK_SIZE, ALIGN_BUF_TAG); + if (Buffer) + { + register DOS *dos; + register ROOT *root; + register ROOT3X *root3x; + register ULONG DirCount, retCode; + + nwvp_vpartition_open(volume->nwvp_handle); + + retCode = nwvp_vpartition_block_read(volume->nwvp_handle, + (volume->FirstDirectory * + volume->BlocksPerCluster), + 1, + Buffer); + if (retCode == 0) + { + DirCount = IO_BLOCK_SIZE / 128; + for (DirNo=0; DirNo < DirCount; DirNo++) + { + dos = (DOS *) &Buffer[DirNo * 128]; + if ((dos->Subdirectory == ROOT_NODE) && (!dos->NameSpace)) + { + root = (ROOT *) dos; +#if (VOLUME_DUMP) + dumpRecord((BYTE *)root, sizeof(ROOT)); + dumpRecordBytes((BYTE *)root, sizeof(ROOT)); +#endif + volume->VolumeFlags = root->VolumeFlags; + volume->ExtDirectory1 = root->ExtendedDirectoryChain0; + volume->ExtDirectory2 = root->ExtendedDirectoryChain1; + + if ((volume->VolumeFlags & NDS_FLAG) || + (volume->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + volume->VolumeSerialNumber = root->CreateDateAndTime; + } + else + { + root3x = (ROOT3X *) root; + volume->VolumeSerialNumber = root3x->CreateDateAndTime; + } + + if (!root->NameSpaceCount) + { + volume->NameSpaceCount = 1; + volume->NameSpaceID[0] = DOS_NAME_SPACE; + } + else + { + volume->NameSpaceCount = root->NameSpaceCount; + + // check if a 4.x/5.x volume + + NWFSSet(&FoundNameSpace[0], 0, MAX_NAMESPACES); + if ((volume->VolumeFlags & NDS_FLAG) || + (volume->VolumeFlags & NEW_TRUSTEE_COUNT)) + { + volume->VolumeSuballocRoot = root->SubAllocationList; + for (j=0, k=0; j < volume->NameSpaceCount; j++) + { + if (j & 1) + volume->NameSpaceID[j] = + (root->SupportedNameSpacesNibble[k++] >> 4) & 0xF; + else + volume->NameSpaceID[j] = + root->SupportedNameSpacesNibble[k] & 0xF; + + if (!j && volume->NameSpaceID[j]) + { + NWFSPrint("nwfs: dos namespace not present\n"); + volume->VolumePresent = FALSE; + NWFSFree(Buffer); + nwvp_vpartition_close(volume->nwvp_handle); + return -1; + } + + if (j && (FoundNameSpace[volume->NameSpaceID[j] & 0xF])) + { + NWFSPrint("nwfs: duplicate root namespaces detected (4x/5x)\n"); + NWFSFree(Buffer); + nwvp_vpartition_close(volume->nwvp_handle); + return -1; + } + FoundNameSpace[volume->NameSpaceID[j] & 0xF] = TRUE; + } + } + else + { + // default to 3.x volume layout + volume->VolumeSuballocRoot = 0; + root3x = (ROOT3X *) root; + for (j=0; j < volume->NameSpaceCount; j++) + { + volume->NameSpaceID[j] = + root3x->NameSpaceTable[j] & 0xF; + + if (!j && volume->NameSpaceID[j]) + { + NWFSPrint("nwfs: dos namespace not present\n"); + volume->VolumePresent = FALSE; + NWFSFree(Buffer); + nwvp_vpartition_close(volume->nwvp_handle); + return -1; + } + + if (j && (FoundNameSpace[volume->NameSpaceID[j] & 0xF])) + { + NWFSPrint("nwfs: duplicate root namespaces detected (3x)\n"); + NWFSFree(Buffer); + nwvp_vpartition_close(volume->nwvp_handle); + return -1; + } + FoundNameSpace[volume->NameSpaceID[j] & 0xF] = TRUE; + } + } + } + } + } + } + else + NWFSPrint("read failed in CreateNWFSVolume\n"); + + NWFSFree(Buffer); + nwvp_vpartition_close(volume->nwvp_handle); + } + else + NWFSPrint("alloc failed in CreateNWFSVolume\n"); + } + else + NWFSPrint("nwfs: invalid volume definition [%s] detected\n", volume->VolumeName); + return 0; +} + +void NWFSVolumeClose(void) +{ + nwvp_unscan_routine(); +} + +void NWFSVolumeScan(void) +{ + register VOLUME *volume; + register ULONG j, i; + ULONG handles[7]; + nwvp_payload payload; + nwvp_vpartition_info vpinfo; + + NWLockScan(); + + MaximumDisks = TotalDisks = 0; + for (volume = 0, i=0; i < MaximumNumberOfVolumes; i++) + { + volume = VolumeTable[i]; + if (volume) + volume->ScanFlag = TRUE; + } + + nwvp_scan_routine(0); + payload.payload_object_count = 0; + payload.payload_index = 0; + payload.payload_object_size_buffer_size = (7 << 20) + sizeof(handles); + payload.payload_buffer = (BYTE *) &handles[0]; + do + { + register ULONG ccode; + + nwvp_vpartition_scan(&payload); + for (j=0; j < payload.payload_object_count; j++) + { + ccode = nwvp_vpartition_return_info(handles[j], &vpinfo); + if (!ccode) + { + CreateNWFSVolume(handles[j], &vpinfo); + } + } + } while ((payload.payload_index != 0) && (payload.payload_object_count != 0)); + + for (volume = 0, i=0; i < MaximumNumberOfVolumes; i++) + { + volume = VolumeTable[i]; + if (volume) + { + if (volume->ScanFlag == TRUE) + { + if (VolumeMountedTable[volume->VolumeNumber]) + { + DismountFileVolume(volume, TRUE); + VolumeMountedTable[volume->VolumeNumber] = 0; + } + VolumeTable[i] = 0; + NWFSFree(volume); + } + } + } + + NWUnlockScan(); + return; +} + +// +// 0 - Netware 3.x, 1 - Netware 4.x/5.x +// +// NOTE: if LINUX_UTIL is set, we create the NFS namespace by default, +// otherwise, we create the DOS and LONG namespace only by default. +// At present, we are always creating Netware 4.x/5.x volumes with +// the following default flags: +// +// SUB_ALLOCATION_ON, FILE_COMPRESISON_ON, AUDITING_OFF +// DATA_MIGRATION_OFF, NDS_PRESENT +// + +ULONG CreateRootDirectory(BYTE *Buffer, ULONG size, ULONG Flags, ULONG ClusterSize) +{ + register ULONG i, j, Version, VolumeFlags; + register DOS *dos; + register ROOT *root, *volume_root; + register ROOT3X *root3x; + register LONGNAME *longname; +#if (LINUX_UTIL) + register NFS *nfs; +#endif + register SUBALLOC *suballoc; + register ULONG SuballocListCount, SuballocCount; + + if (size != IO_BLOCK_SIZE || !Buffer) + return -1; + + // set default volume type to 4.x/5.x + Version = TRUE; + + // mask volume flags + VolumeFlags = (Flags & 0x3F); + + // create 3.x volume if set + if (Flags & 0x80000000) + Version = 0; + + volume_root = (ROOT *) &Buffer[0]; + for (i=0; i < (IO_BLOCK_SIZE / sizeof(ROOT)); i++) + { + switch (i) + { + case 0: + // create DOS_NAME_SPACE root directory record + if (Version) + { + // create for 4.x/5.x NetWare + root = (ROOT *) &Buffer[i * sizeof(ROOT)]; + NWFSSet(root, 0, sizeof(ROOT)); + root->Subdirectory = ROOT_NODE; + root->Flags = SUBDIRECTORY_FILE | PRIMARY_NAMESPACE; + root->NameSpace = DOS_NAME_SPACE; +#if (LINUX_UTIL) + root->NameSpaceCount = 3; + root->SupportedNameSpacesNibble[0] = (BYTE)((LONG_NAME_SPACE << 4) | + (DOS_NAME_SPACE & 0x0F)); + root->SupportedNameSpacesNibble[1] = (BYTE)(UNIX_NAME_SPACE & 0x0F); +#else + root->NameSpaceCount = 2; + root->SupportedNameSpacesNibble[0] = (BYTE)((LONG_NAME_SPACE << 4) | + (DOS_NAME_SPACE & 0x0F)); +#endif + root->FileAttributes = SUBDIRECTORY; + root->VolumeFlags = (BYTE)(VolumeFlags | NEW_TRUSTEE_COUNT | NDS_FLAG); + root->CreateDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + root->OwnerID = SUPERVISOR; + root->LastModifiedDateAndTime = root->CreateDateAndTime; + root->NameList = 1; + } + else + { + // create for 3.x NetWare + root3x = (ROOT3X *) &Buffer[i * sizeof(ROOT)]; + + NWFSSet(root3x, 0, sizeof(ROOT)); + root3x->Subdirectory = ROOT_NODE; + root3x->Flags = SUBDIRECTORY_FILE | PRIMARY_NAMESPACE; + root3x->NameSpace = DOS_NAME_SPACE; +#if (LINUX_UTIL) + root3x->NameSpaceCount = 3; + root3x->NameSpaceTable[0] = DOS_NAME_SPACE; + root3x->NameSpaceTable[1] = LONG_NAME_SPACE; + root3x->NameSpaceTable[2] = UNIX_NAME_SPACE; +#else + root3x->NameSpaceCount = 2; + root3x->NameSpaceTable[0] = DOS_NAME_SPACE; + root3x->NameSpaceTable[1] = LONG_NAME_SPACE; +#endif + root3x->FileAttributes = SUBDIRECTORY; + root3x->VolumeFlags = (BYTE) VolumeFlags; + root3x->CreateDateAndTime = NWFSSystemToNetwareTime(NWFSGetSystemTime()); + root3x->OwnerID = SUPERVISOR; + root3x->LastModifiedDateAndTime = root3x->CreateDateAndTime; + root3x->NameList = 1; + } + break; + + case 1: + // create LONG_NAME_SPACE root directory record + longname = (LONGNAME *) &Buffer[i * sizeof(ROOT)]; + NWFSSet(longname, 0, sizeof(LONGNAME)); + longname->Subdirectory = ROOT_NODE; + longname->NameSpace = LONG_NAME_SPACE; + longname->Flags = SUBDIRECTORY_FILE; +#if (LINUX_UTIL) + longname->NameList = 2; +#else + longname->NameList = 0; +#endif + break; + +#if (LINUX_UTIL) + case 2: + // create UNIX_NAME_SPACE root directory record + nfs = (NFS *) &Buffer[i * sizeof(ROOT)]; + NWFSSet(nfs, 0, sizeof(NFS)); + nfs->Subdirectory = ROOT_NODE; + nfs->NameSpace = UNIX_NAME_SPACE; + nfs->Flags = SUBDIRECTORY_FILE; + nfs->flags = 6; + nfs->nlinks = 2; + break; +#endif + + // NOTE: Netware does *NOT* create suballocation records during + // volume creation. Instead, Netware creates these records + // the first time the volume is mounted. We create these + // suballoc chains by default during volume create if the + // SUBALLOCATION_ON flags is set to allow R/O volumes to + // be mounted under NT. + + case 9: + if (Version && (volume_root->VolumeFlags & SUB_ALLOCATION_ON)) + { + SuballocListCount = (ClusterSize / SUBALLOC_BLOCK_SIZE) - 1; + SuballocCount = (SuballocListCount + 27) / 28; + + // initialize the suballoc root; + volume_root->SubAllocationList = i; + + for (j=0; j < (SuballocCount - 1); j++) + { + // store the DirNo for next record into SuballocationList + suballoc = (SUBALLOC *) &Buffer[(j + i) * sizeof(ROOT)]; + NWFSSet(suballoc, 0, sizeof(SUBALLOC)); + suballoc->Flag = SUBALLOC_NODE; + suballoc->SubAllocationList = (j + i) + 1; + suballoc->SequenceNumber = (BYTE) j; + } + + // null terminate last suballoc directory record + suballoc = (SUBALLOC *) &Buffer[(j + i) * sizeof(ROOT)]; + NWFSSet(suballoc, 0, sizeof(SUBALLOC)); + suballoc->Flag = SUBALLOC_NODE; + suballoc->SubAllocationList = 0; + suballoc->SequenceNumber = (BYTE) j; + i = (j + i); + break; + }; + // fall through if suballocation is disabled or we are creating + // a Netware 3.x volume. + + default: + // mark all other entries as free + dos = (DOS *) &Buffer[i * sizeof(DOS)]; + NWFSSet(dos, 0, sizeof(DOS)); + dos->Subdirectory = (ULONG) -1; + break; + } + } + return 0; + +} + +BYTE *get_ns_string(ULONG ns) +{ + switch (ns) + { + case 0: + return "DOS "; + + case 1: + return "MAC "; + + case 2: + return "NFS "; + + case 3: + return "FTAM "; + + case 4: + return "LONG "; + + case 5: + return "NT "; + + case 6: + return "FEN "; + + default: + return ""; + } + +} + +void ReportVolumes(void) +{ + register ULONG i, TotalVolumes, TotalSegments; + extern ULONG TotalDisks; + + for (TotalSegments = TotalVolumes = 0, i = 0; i < MAX_VOLUMES; i++) + { + if (VolumeTable[i]) + { + if (VolumeTable[i]->VolumePresent) + { + TotalVolumes++; + TotalSegments += VolumeTable[i]->NumberOfSegments; + } + } + } + NWFSPrint("%d NetWare volume(s) located, %d volume segment(s), %d disk(s)\n", + (int)TotalVolumes, + (int)TotalSegments, + (int)TotalDisks); + return; +} + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/proc/array.c linux-2.4.20-wolk4.7-fullkernel/fs/proc/array.c --- linux-2.4.20-wolk4.6-fullkernel/fs/proc/array.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/proc/array.c 2003-08-17 21:31:30.000000000 +0200 @@ -475,6 +475,7 @@ int proc_pid_stat(struct task_struct *ta } #endif #ifdef CONFIG_GRKERNSEC_HIDESYM + wchan = 0; eip = 0; esp = 0; #endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/reiserfs/inode.c linux-2.4.20-wolk4.7-fullkernel/fs/reiserfs/inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/reiserfs/inode.c 2003-05-09 01:12:14.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/reiserfs/inode.c 2003-08-17 21:31:43.000000000 +0200 @@ -2575,6 +2575,10 @@ void sd_attrs_to_i_attrs( __u16 sd_attrs else inode -> i_flags &= ~S_IMMUTABLE; #endif /* CONFIG_SCONTEXTS */ + if( sd_attrs & REISERFS_APPEND_FL ) + inode -> i_flags |= S_APPEND; + else + inode -> i_flags &= ~S_APPEND; if( sd_attrs & REISERFS_NOATIME_FL ) inode -> i_flags |= S_NOATIME; else diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/reiserfs/ioctl.c linux-2.4.20-wolk4.7-fullkernel/fs/reiserfs/ioctl.c --- linux-2.4.20-wolk4.6-fullkernel/fs/reiserfs/ioctl.c 2003-05-03 02:36:47.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/reiserfs/ioctl.c 2003-08-17 21:31:43.000000000 +0200 @@ -61,9 +61,9 @@ int reiserfs_ioctl (struct inode * inode return -EFAULT; #ifdef CONFIG_SCONTEXTS - if ( ( flags & (REISERFS_IMMUTABLE_FILE_FL | REISERFS_IMMUTABLE_LINK_FL) ) && + if ( ( ( flags ^ inode->u.reiserfs_i.i_attrs) & ( REISERFS_IMMUTABLE_FILE_FL | REISERFS_IMMUTABLE_LINK_FL | REISERFS_APPEND_FL)) && #else - if ( ( flags & REISERFS_IMMUTABLE_FL ) && + if ( ( ( flags ^ inode->u.reiserfs_i.i_attrs) & ( REISERFS_IMMUTABLE_FL | REISERFS_APPEND_FL)) && #endif /* CONFIG_SCONTEXTS */ !capable( CAP_LINUX_IMMUTABLE ) ) return -EPERM; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/Changelog linux-2.4.20-wolk4.7-fullkernel/fs/shfs/Changelog --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/Changelog 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/Changelog 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,80 @@ +shfs (0.32pre1) unstable; urgency=low + + * speed improvement: use socket instead of pair of pipes + * rpm depmod call fixed (thanks to Nathaniel Gray ) + * Install ln -fs fix (thanks to Brett Kuskie ) + * DEBUG variable fixes + * 32bit uid/gid fix + * rpm build fix + * compiler warning fixed + * docs typos fixed (thanks to Makis Marmaridis ) + * rpm build fix (thanks to richard lucassen ) + * inode attributes fix + * does not use release numbers + * build fixes (does not require root) + + -- Miroslav Spousta Sat, 10 May 2003 9:23:08 +0200 + -- merged into wolk4.6 by Michael Gebetsroither + +shfs (0.31-1) unstable; urgency=low + + * top Makefile DEBUG variable added + * user mounts fully supported (thanks to Grzegorz Jasko) + * shfsumount command added + * suid, nosuid, dev, nodev, exec, noexec mount options added + * doc updates + + -- Miroslav Spousta Sat, 10 May 2003 9:23:08 +0200 + +shfs (0.30-1) unstable; urgency=low + + * linux 2.4.19+ stale NFS handle fix + * OSF1 support added (thanks to ) + + -- Miroslav Spousta Tue, 6 May 2003 15:09:08 +0200 + +shfs (0.29-2) unstable; urgency=low + + * rc 2 + * IRIX64 symlink fix + * create () should respect given access mode now + * shell protocol fixes + * gcc 3.x compilation fixes + + -- Miroslav Spousta Fri, 31 Jan 2003 10:16:00 +0100 + +shfs (0.29-1) unstable; urgency=low + + * release candidate 1 :-) + * shell protocol rewritten to use shell functions + * removed dentry ops -> nasty invalid symlink bug (Oops) fixed + * write does not invalidate parent dir cache entry + * dcache validity improvements + * no more kmem alloc for dir entries -> (SLAB) name_cache + * docs update + + -- Miroslav Spousta Sun, 26 Jan 2003 20:06:51 +0100 + +shfs (0.28) unstable; urgency=low + + * Makefiles cleanup & rewrite + * shfsmount rewritten, options changed and added + * debian package support + * rpm package support + * readahead cache speedup for small files + * "write to full disk" error detection and recovery + * file append fix (file_commitwrite()) + * clean garbage fix + * remote timezone fix + * invalid dd usage (locale) in read fixed + * directory traversal fix (no more "find: changed during execution") + * create symlink fix + + -- Miroslav Spousta Thu, 1 Aug 2002 10:15:11 +0200 + +shfs (0.27) unstable; urgency=low + + * Version 0.27 released (first public) + + -- Miroslav Spousta Sat, 8 Jun 2002 08:00:00 +0200 + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/Makefile linux-2.4.20-wolk4.7-fullkernel/fs/shfs/Makefile --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/Makefile 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,33 @@ +# +# Makefile for the linux shfs-filesystem routines. +# +# written by Michael Gebetsroither to patch +# shfs direct into WOLK v4.6s + +O_TARGET := shfs.o + +obj-y := dcache.o dir.o fcache.o file.o inode.o proc.o proto.o symlink.o +obj-m := $(O_TARGET) + +# just if you want debug output +# there are 4 DEBUG modes (see shfs_debug.h): +# DEBUG_LEVEL = 0 => DEBUG deaktivated +# DEBUG_LEVEL = 1 => VERBOSE +# DEBUG_LEVEL = 2 => ALLOC_DEBUG +# DEBUG_LEVEL = 3 => real DEBUG +# +ifdef CONFIG_SH_FS_DEBUG0 + DEBUG_LEVEL=0 +endif +ifdef CONFIG_SH_FS_DEBUG1 + DEBUG_LEVEL=1 +endif +ifdef CONFIG_SH_FS_DEBUG2 + DEBUG_LEVEL=2 +endif +ifdef CONFIG_SH_FS_DEBUG3 + DEBUG_LEVEL=3 +endif + +include $(TOPDIR)/Rules.make + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/dcache.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/dcache.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/dcache.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/dcache.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,322 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include + +#include "shfs.h" +#include "shfs_dcache.h" +#include "shfs_proc.h" + +#define dir_cache info->dir_cache + +void +shfs_dcache_init(struct shfs_sb_info *info) { + memset(&dir_cache, 0, sizeof(struct shfs_dir_cache)); +} + +unsigned long +shfs_dcache_hash(char *name) { + unsigned long hash = 0; + int i; + + for (i = 0; i < strlen(name); i++) + hash += name[i]; + return hash % SHFS_DCACHE_HASH; +} + +int +shfs_dcache_deldir(struct shfs_sb_info *info, struct shfs_dir_hash_node *n) { + struct shfs_dir_list_node *p, *q; + unsigned long hsh; + + if (!n) + return -1; + + DEBUG("deleting a cache entry (%s)\n", n->directory.name); + hsh = shfs_dcache_hash(n->directory.name); + + for (p = n->directory.head; p; p = q) { + q = p->next; + KMEM_FREE("name", dir_name_cache, p->entry.name); + KMEM_FREE("dir", dir_list_cache, p); + } + + KMEM_FREE("name", dir_name_cache, n->directory.name); + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + if (n == dir_cache.hash[hsh]) + dir_cache.hash[hsh] = n->next; + + KMEM_FREE("hash", dir_hash_cache, n); + dir_cache.len[hsh]--; + + DEBUG("done\n"); + return 0; +} + +int +shfs_dcache_empty(struct shfs_sb_info *info) +{ + int i; + + DEBUG("closing cache...\n"); + for (i = 0; i < SHFS_DCACHE_HASH; i++) { + DEBUG("closing hash bucket %d (%d)...\n", i, dir_cache.len[i]); + while (dir_cache.len[i]) + shfs_dcache_deldir(info, dir_cache.hash[i]); + } + DEBUG(" OK\n"); + return 0; +} + +int +shfs_dcache_infront(struct shfs_sb_info *info, struct shfs_dir_hash_node *n) +{ + unsigned long hsh; + + DEBUG("bringing in front %s\n", n->directory.name); + if (n->prev) { + hsh = shfs_dcache_hash(n->directory.name); + + n->prev->next = n->next; + + if (n->next) + n->next->prev = n->prev; + + n->prev = NULL; + n->next = dir_cache.hash[hsh]; + if (n->next) + n->next->prev = n; + dir_cache.hash[hsh] = n; + } + return 0; +} + + +int +shfs_dcache_shrink(unsigned long hsh, struct shfs_sb_info *info) +{ + struct shfs_dir_hash_node *p; + + DEBUG("Shrinking hash bucket %u (%d)\n", (unsigned)hsh, dir_cache.len[hsh]); + + if (dir_cache.len[hsh] == 0) + return -1; + + for (p = dir_cache.hash[hsh]; p->next != NULL; p = p->next) + ; + shfs_dcache_deldir(info, p); + + return 0; +} + +int +shfs_dcache_add(struct shfs_sb_info *info, char *name, struct shfs_directory **dir) +{ + unsigned long hsh; + struct shfs_dir_hash_node *p; + int res; + + hsh = shfs_dcache_hash(name); + + while (dir_cache.len[hsh] >= SHFS_DCACHE_LEN) + shfs_dcache_shrink(hsh, info); + p = (struct shfs_dir_hash_node*)KMEM_ALLOC("hash", dir_hash_cache, GFP_KERNEL); + if (!p) { + VERBOSE("slab cache error!\n"); + res = -ENOMEM; + goto out; + } + + memset(p, 0, sizeof(struct shfs_dir_hash_node)); + p->directory.time = CURRENT_TIME; + if (strlen(name) + 1 > SHFS_PATH_MAX) { + VERBOSE("too long dir entry!\n"); + res = -ENAMETOOLONG; + goto out1; + } + + p->directory.name = (char *)KMEM_ALLOC("name", dir_name_cache, GFP_KERNEL); + if (!p->directory.name) { + VERBOSE("slab cache error!\n"); + res = -ENOMEM; + goto out1; + } + + strcpy(p->directory.name, name); + + DEBUG("loading dir...\n"); + if ((res = shfs_loaddir(info, name, &p->directory)) < 0) { + VERBOSE("Couldn't load directory!\n"); + goto out2; + } + p->prev = NULL; + p->next = dir_cache.hash[hsh]; + if (p->next) + p->next->prev = p; + dir_cache.hash[hsh] = p; + + dir_cache.len[hsh]++; + *dir = &p->directory; + return 0; +out2: + KMEM_FREE("name", dir_name_cache, p->directory.name); +out1: + KMEM_FREE("hash", dir_hash_cache, p); +out: + return res; +} + +int +shfs_dcache_get(struct shfs_sb_info *info, char *name, struct shfs_directory **dir) +{ + struct shfs_dir_hash_node *p; + unsigned long hsh; + + DEBUG("looking for %s\n", name); + hsh = shfs_dcache_hash(name); + for (p = dir_cache.hash[hsh]; p; p = p->next) { + if (!strcmp(name, p->directory.name)) { + DEBUG(" found in cache!\n"); + if (CURRENT_TIME - p->directory.time > SHFS_DCACHE_TTL) { + DEBUG(" cache entry too old!\n"); + if (shfs_dcache_deldir(info, p) < 0) + VERBOSE("cannot delete dir!\n"); + return shfs_dcache_add(info, name, dir); + } + shfs_dcache_infront(info, p); + *dir = &p->directory; + return 0; + } + } + DEBUG(" %s not found in cache. Adding...!\n", name); + return shfs_dcache_add(info, name, dir); +} + +static void +dcache_set_inode_attr(struct inode *inode, struct shfs_dir_entry *dir) +{ + inode->i_mode = dir->mode; + inode->i_uid = dir->uid; + inode->i_gid = dir->gid; + inode->i_ctime = dir->atime; + inode->i_atime = dir->atime; + inode->i_mtime = dir->atime; + inode->i_size = dir->size; +} + +int +shfs_dcache_revalidate(struct dentry *dentry, struct shfs_sb_info *info) +{ + char buf[SHFS_PATH_MAX]; + struct shfs_dir_hash_node *p; + struct shfs_dir_list_node *q; + struct shfs_directory *dir; + unsigned long hsh; + int loops = 10; + + if (shfs_get_name(dentry->d_parent, buf) < 0) + return 0; + + DEBUG("%s\n", buf); + hsh = shfs_dcache_hash(buf); + + while (loops) { + for (p = dir_cache.hash[hsh]; p != NULL; p = p->next) { + if (!strcmp(buf, p->directory.name)) { + if (CURRENT_TIME - p->directory.time > SHFS_DCACHE_TTL) + goto revalidate; + strcpy(buf, dentry->d_name.name); + for (q = p->directory.head; q; q = q->next) { + if (!strcmp(buf, q->entry.name)) { + DEBUG(" %s\n", q->entry.name); + if (q->entry.changed) { + if (!dentry->d_inode) + goto revalidate; + dcache_set_inode_attr(dentry->d_inode, &q->entry); + q->entry.changed = 0; + } + return 1; + } + } + } + } +revalidate: + if (shfs_dcache_deldir(info, p) < 0) + VERBOSE("cannot delete dir!\n"); + if (shfs_dcache_add(info, buf, &dir) != 0) + return 0; + loops--; + } + return 0; +} + +void +shfs_dcache_invalidate(struct dentry *dentry) +{ + struct super_block *sb = dentry->d_inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + struct shfs_dir_hash_node *p; + unsigned long hsh; + + if (shfs_get_name(dentry, buf) < 0) + return; + hsh = shfs_dcache_hash(buf); + DEBUG(" \n"); + + for (p = dir_cache.hash[hsh]; p != NULL; p = p->next) { + if (!strcmp(buf, p->directory.name)) { + shfs_dcache_deldir(info, p); + return; + } + } +} + +void +shfs_dcache_update_fattr(struct dentry *dentry, struct iattr *attr) +{ + struct super_block *sb = dentry->d_inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + struct shfs_dir_hash_node *p; + struct shfs_dir_list_node *q; + unsigned long hsh; + + if (shfs_get_name(dentry->d_parent, buf) < 0) + return; + hsh = shfs_dcache_hash(buf); + for (p = dir_cache.hash[hsh]; p; p = p->next) { + if (!strcmp(buf, p->directory.name)) { + strcpy(buf, dentry->d_name.name); + DEBUG("%s\n", buf); + for (q = p->directory.head; q; q = q->next) { + if (!strcmp(buf, q->entry.name)) { + if (attr->ia_valid & ATTR_MODE) + q->entry.mode = attr->ia_mode; + if (attr->ia_valid & ATTR_UID) + q->entry.uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + q->entry.gid = attr->ia_gid; + if (attr->ia_valid & ATTR_SIZE) { + q->entry.size = attr->ia_size; + q->entry.blocksize = 4096; + q->entry.blocks = (attr->ia_size + 4095) >> 11; + q->entry.atime = CURRENT_TIME; + DEBUG("size changed to: %llu\n", attr->ia_size); + } + q->entry.changed = 1; + return; + } + } + shfs_dcache_deldir(info, p); + return; + } + } +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/dir.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/dir.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/dir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/dir.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,440 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include + +#include "shfs.h" +#include "shfs_proc.h" + +static int shfs_lookup_validate(struct dentry*, int); + +static struct dentry_operations shfs_dentry_operations = { + d_revalidate: shfs_lookup_validate +}; + +static int shfs_readdir(struct file*, void*, filldir_t); +static int shfs_dir_open(struct inode*, struct file*); + +struct file_operations shfs_dir_operations = { + read: generic_read_dir, + readdir: shfs_readdir, + open: shfs_dir_open, +}; + +static struct dentry *shfs_lookup(struct inode*, struct dentry*); +static int shfs_mkdir(struct inode*, struct dentry*, int); +static int shfs_create(struct inode*, struct dentry*, int); +static int shfs_rmdir(struct inode*, struct dentry*); +static int shfs_rename(struct inode*, struct dentry*, struct inode*, struct dentry*); +static int shfs_unlink(struct inode*, struct dentry*); +static int shfs_link(struct dentry*, struct inode*, struct dentry*); +static int shfs_symlink(struct inode*, struct dentry*, const char*); + +struct inode_operations shfs_dir_inode_operations = { + create: shfs_create, + lookup: shfs_lookup, + link: shfs_link, + unlink: shfs_unlink, + symlink: shfs_symlink, + mkdir: shfs_mkdir, + rmdir: shfs_rmdir, + rename: shfs_rename, + setattr: shfs_notify_change, +}; + +static int +shfs_lookup_validate(struct dentry *dentry, int flags) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb; + struct shfs_sb_info *info; + int valid; + + lock_kernel(); + if (!inode) { + valid = 1; + goto out; + } + if (is_bad_inode(inode)) { + valid = 0; + goto out; + } + sb = inode->i_sb; + if (sb->s_magic != SHFS_SUPER_MAGIC) { + valid = 1; + goto out; + } + info = (struct shfs_sb_info*)sb->u.generic_sbp; + if (!shfs_lock(info)) { + valid = 0; + goto out; + } + valid = shfs_dcache_revalidate(dentry, info); + shfs_unlock(info); +out: + unlock_kernel(); + DEBUG("%d\n", valid); + return valid; +} + +static int +shfs_dir_open(struct inode* inode, struct file* f) +{ + struct dentry *dentry = f->f_dentry; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + int res; + struct shfs_directory *dir; + + if ((res = shfs_get_name(dentry, buf)) < 0) { + VERBOSE("shfs_get_name failed! (%d)\n", res); + return -ENOMEM; + } + DEBUG("%s\n", buf); + if (!shfs_lock(info)) + return -EINTR; + res = shfs_dcache_get(info, buf, &dir); + shfs_unlock(info); + if (res < 0) { + VERBOSE(" shfs_dcache_get failed! (%d)\n", res); + return -ENOENT; + } + return 0; +} + +static int +shfs_readdir(struct file* f, void* dirent, filldir_t filldir) +{ + struct dentry *dentry = f->f_dentry; + struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + int pos, res; + + struct shfs_directory *dir; + struct shfs_dir_list_node *file; + + if (!info->mnt.mount_point[0]) { + if (shfs_get_name(f->f_vfsmnt->mnt_mountpoint, info->mnt.mount_point) < 0) { + VERBOSE("Name too long!\n"); + return -1; + } + } + + DEBUG(" reading %s, f_pos=%d\n", dentry->d_name.name, (unsigned int)f->f_pos); + if ((res = shfs_get_name(dentry, buf)) < 0) { + VERBOSE(" shfs_get_name failed! (%d)\n", res); + return -1; + } + + switch ((unsigned int) f->f_pos) { + case 0: + DEBUG("f_pos=0\n"); + if ((res = filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) < 0) + goto out; + f->f_pos = 1; + case 1: + DEBUG("f_pos=1\n"); + if ((res = filldir(dirent, "..", 2, 1, dentry->d_parent->d_inode->i_ino, DT_DIR)) < 0) + goto out; + f->f_pos = 2; + default: + DEBUG(" \n"); + if (!shfs_lock(info)) + return -EINTR; + res = shfs_dcache_get(info, buf, &dir); + if (res < 0) { + shfs_unlock(info); + VERBOSE(" shfs_dcache_get failed! (%d)\n", res); + goto out; + } + pos = 2; + for (file = dir->head; file != NULL; file = file->next) { + if ((pos == f->f_pos)) { + struct qstr qname; + unsigned long ino; + qname.name = file->entry.name; + qname.len = strlen(qname.name); + ino = find_inode_number(dentry, &qname); + if (!ino) +// ino = iunique(dentry->d_sb, 2); + ino = file->entry.ino; + if (filldir(dirent, qname.name, qname.len, f->f_pos, ino, DT_UNKNOWN) >= 0) + f->f_pos++; + } + pos++; + } + shfs_unlock(info); + } + return 0; +out: + return shfs_remove_sigpipe(res); +} + +static struct dentry* +shfs_lookup(struct inode *dir, struct dentry *dentry) +{ + struct shfs_fattr fattr; + struct inode *inode; + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + int res; + + DEBUG(" dname:%s\n", dentry->d_name.name); + if (!shfs_lock(info)) + return ERR_PTR(-EINTR); + res = shfs_get_attr(dentry, &fattr, (struct shfs_sb_info*)dir->i_sb->u.generic_sbp); + shfs_unlock(info); + if (res < 0) { + DEBUG(" file not found!\n"); + inode = NULL; + dentry->d_op = &shfs_dentry_operations; + d_add(dentry, inode); + res = shfs_remove_sigpipe(res); + if (res == -EINTR) + return ERR_PTR(res); + return NULL; + } + +// fattr.f_ino = iunique(dentry->d_sb, 2); + inode = shfs_iget(dir->i_sb, &fattr); + + if (inode) { + dentry->d_op = &shfs_dentry_operations; + d_add(dentry, inode); + } + + return NULL; +} + +static int +shfs_instantiate(struct dentry* dentry) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + struct shfs_fattr fattr; + struct inode *inode; + int res; + + DEBUG(" \n"); + if (!shfs_lock(info)) + return -EINTR; + res = shfs_get_attr(dentry, &fattr, info); + shfs_unlock(info); + if (res < 0) { + VERBOSE(" shfs_get_attr failed! (%d)\n", res); + return shfs_remove_sigpipe(res); + } + +// fattr.f_ino = iunique(dentry->d_sb, 2); + inode = shfs_iget(dentry->d_sb, &fattr); + if (!inode) + return -EACCES; + + d_instantiate(dentry, inode); + + return 0; +} + +static int +shfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + int res; + + DEBUG("\n"); + + if (info->mnt.readonly) + return -EROFS; + + if (shfs_get_name(dentry, buf) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if ((res = shfs_proc_mkdir(info, buf)) < 0) { + VERBOSE("mkdir failed!\n"); + return shfs_remove_sigpipe(res); + } + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(dentry->d_parent); + shfs_unlock(info); + return shfs_instantiate(dentry); +} + +static int +shfs_create(struct inode* dir, struct dentry *dentry, int mode) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + int res; + + DEBUG("\n"); + if (info->mnt.readonly) + return -EROFS; + + if (shfs_get_name(dentry, buf) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if ((res = shfs_proc_create(info, buf, mode)) < 0) { + VERBOSE(" Create failed!\n"); + return shfs_remove_sigpipe(res); + } + + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(dentry->d_parent); + shfs_unlock(info); + return shfs_instantiate(dentry); +} + +static int +shfs_rmdir(struct inode* dir, struct dentry *dentry) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + + DEBUG(" \n"); + if (info->mnt.readonly) + return -EROFS; + + if (!d_unhashed(dentry)) + return -EBUSY; + + if (shfs_get_name(dentry, buf) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(dentry->d_parent); + shfs_unlock(info); + return shfs_remove_sigpipe(shfs_proc_rmdir(info, buf)); +} + +static int +shfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)old_dentry->d_sb->u.generic_sbp; + char buf1[SHFS_PATH_MAX], buf2[SHFS_PATH_MAX]; + int res; + + DEBUG(" \n"); + + if (info->mnt.readonly) + return -EROFS; + + if (shfs_get_name(old_dentry, buf1) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + if (shfs_get_name(new_dentry, buf2) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if (new_dentry->d_inode) { + d_delete(new_dentry); + } + + if ((res = shfs_proc_rename(info, buf1, buf2)) < 0) + return shfs_remove_sigpipe(res); + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(old_dentry->d_parent); + shfs_dcache_invalidate(new_dentry->d_parent); + shfs_unlock(info); + + return 0; +} + +static int +shfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + char buf[SHFS_PATH_MAX]; + + DEBUG(" \n"); + if (info->mnt.readonly) + return -EROFS; + + if (shfs_get_name(dentry, buf) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(dentry->d_parent); + shfs_unlock(info); + return shfs_remove_sigpipe(shfs_proc_unlink(info, buf)); +} + +static int +shfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)old_dentry->d_sb->u.generic_sbp; + char old[SHFS_PATH_MAX], new[SHFS_PATH_MAX]; + int res; + + DEBUG(" \n"); + if (info->mnt.readonly) + return -EROFS; + + if (shfs_get_name(old_dentry, old) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + if (shfs_get_name(new_dentry, new) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if ((res = shfs_proc_link(info, old, new)) < 0) + return shfs_remove_sigpipe(res); + + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(old_dentry->d_parent); + shfs_dcache_invalidate(new_dentry->d_parent); + shfs_unlock(info); + + return shfs_instantiate(new_dentry); +} + +static int +shfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + char new[SHFS_PATH_MAX]; + int res; + + DEBUG(" \n"); + if (info->mnt.readonly) + return -EROFS; + + if (shfs_get_name(dentry, new) < 0) { + VERBOSE("Name too long!\n"); + return -ENAMETOOLONG; + } + + if ((res = shfs_proc_symlink(info, oldname, new)) < 0) + return shfs_remove_sigpipe(res); + + DEBUG(" \n"); + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_invalidate(dentry->d_parent); + shfs_unlock(info); + return shfs_instantiate(dentry); +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/fcache.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/fcache.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/fcache.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/fcache.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,352 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include + +#include "shfs.h" +#include "shfs_fcache.h" +#include "shfs_proc.h" + +#define file_cache info->file_cache + +void +shfs_fcache_init(struct shfs_sb_info *info) +{ + memset(&file_cache, 0, sizeof(struct shfs_file_cache)); +} + +int +shfs_fcache_empty(struct shfs_sb_info *info) +{ + int i; + + DEBUG("closing file cache...\n"); + for (i = 0; i < SHFS_FCACHE_HASH; i++) { + if (file_cache.hash[i]) + VERBOSE("Aieeee.. file cache not empty!\n"); + } + DEBUG(" OK\n"); + return 0; +} + +static inline unsigned long +shfs_file_cache_hash(unsigned long i) +{ + return i % SHFS_FCACHE_HASH; +} + +int +shfs_fcache_add(struct file *f) +{ + struct inode *inode; + struct super_block *sb; + struct shfs_sb_info *info; + unsigned long hsh; + struct shfs_file_hash_node *p; + + DEBUG("Adding file to rw-cache.\n"); + + if (f && f->f_dentry && (inode = f->f_dentry->d_inode)) { + sb = inode->i_sb; + DEBUG("ino: %lu\n", inode->i_ino); + info = (struct shfs_sb_info*)sb->u.generic_sbp; + hsh = shfs_file_cache_hash(inode->i_ino); + for (p = file_cache.hash[hsh]; p; p = p->next) { + if ((p->buf.ino == inode->i_ino) + && (p->buf.name_hash == f->f_dentry->d_name.hash)) + break; + } + if (p) { + DEBUG("opened: %d times before\n", p->buf.used); + p->buf.used++; + if (!p->buf.used) + VERBOSE("File usage counter overflow!\n"); + } else { + p = (struct shfs_file_hash_node*)KMEM_ALLOC("fcache", file_hash_cache, GFP_KERNEL); + if (!p) { + VERBOSE("slab cache error!\n"); + return -1; + } + p->buf.data = vmalloc(SHFS_FCACHE_SIZE); + if (!p->buf.data) { + VERBOSE("slab cache error!\n"); + KMEM_FREE("fcache", file_hash_cache, p); + return -1; + } + p->buf.ino = inode->i_ino; + p->buf.used = 1; + p->buf.name_hash = f->f_dentry->d_name.hash; + p->buf.offset = 0; + p->buf.count = 0; + p->buf.type = SHFS_FCACHE_READ; + DEBUG("ino: %lu (hash: %u)\n", p->buf.ino, p->buf.name_hash); + + hsh = shfs_file_cache_hash(inode->i_ino); + p->prev = NULL; + p->next = file_cache.hash[hsh]; + if (p->next) + p->next->prev = p; + file_cache.hash[hsh] = p; + file_cache.len[hsh]++; + } + return 0; + } + VERBOSE("Invalid file!\n"); + return -1; +} + + +int +shfs_fcache_remove(struct file *f) +{ + struct inode *inode; + struct super_block *sb; + struct shfs_sb_info *info; + unsigned long hsh; + struct shfs_file_hash_node *p; + + DEBUG("Removing file from rw-cache.\n"); + + if (f && f->f_dentry && (inode = f->f_dentry->d_inode)) { + DEBUG("ino: %lu\n", inode->i_ino); + sb = inode->i_sb; + info = (struct shfs_sb_info*)sb->u.generic_sbp; + hsh = shfs_file_cache_hash(inode->i_ino); + for (p = file_cache.hash[hsh]; p; p = p->next) { + if ((p->buf.ino == inode->i_ino) + && (p->buf.name_hash == f->f_dentry->d_name.hash)) + break; + } + if (!p) { + VERBOSE("File not found!\n"); + return -1; + } + DEBUG("ino: %lu (hash: %u)\n", p->buf.ino, p->buf.name_hash); + + p->buf.used--; + if (!p->buf.used) { + DEBUG("used count 0, releasing..\n"); + if (p->buf.count && p->buf.type == SHFS_FCACHE_WRITE) + shfs_proc_write(f->f_dentry, p->buf.offset, p->buf.count, p->buf.data); + vfree(p->buf.data); + + if (p->prev) + p->prev->next = p->next; + else + file_cache.hash[hsh] = p->next; + if (p->next) + p->next->prev = p->prev; + KMEM_FREE("fcache", file_hash_cache, p); + file_cache.len[hsh]--; + } + return 0; + } + VERBOSE("Invalid file!\n"); + return -1; +} + +int +shfs_fcache_sync(struct file *f) +{ + struct inode *inode; + struct super_block *sb; + struct shfs_sb_info *info; + unsigned long hsh; + struct shfs_file_hash_node *p; + + DEBUG("Sync file in rw-cache.\n"); + + if (f && f->f_dentry && (inode = f->f_dentry->d_inode)) { + DEBUG("ino: %lu\n", inode->i_ino); + sb = inode->i_sb; + info = (struct shfs_sb_info*)sb->u.generic_sbp; + hsh = shfs_file_cache_hash(inode->i_ino); + for (p = file_cache.hash[hsh]; p; p = p->next) { + if ((p->buf.ino == inode->i_ino) + && (p->buf.name_hash == f->f_dentry->d_name.hash)) + break; + } + if (!p) { + VERBOSE("File not found!\n"); + return -1; + } + DEBUG("ino: %lu (hash: %u)\n", p->buf.ino, p->buf.name_hash); + + if (p->buf.count && p->buf.type == SHFS_FCACHE_WRITE) { + DEBUG("Syncing..\n"); + shfs_proc_write(f->f_dentry, p->buf.offset, p->buf.count, p->buf.data); + p->buf.type = SHFS_FCACHE_READ; + p->buf.count = 0; + } + return 0; + } + VERBOSE("Invalid file!\n"); + return -1; +} + +int +shfs_fcache_read(struct dentry *d, unsigned offset, unsigned count, char *buffer) +{ + struct inode *inode = d->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + unsigned long hsh, ino; + unsigned readahead, c, o, x, y, z, read = 0; + struct shfs_file_hash_node *p; + int res; + + DEBUG("Reading file: offset: %u, count: %u\n", offset, count); + + if (d->d_inode && d->d_inode->i_ino) { + ino = d->d_inode->i_ino; + DEBUG("ino: %lu\n", ino); + hsh = shfs_file_cache_hash(ino); + for (p = file_cache.hash[hsh]; p; p = p->next) { + if ((p->buf.ino == ino) + && (p->buf.name_hash == d->d_name.hash)) + break; + } + if (!p) { + VERBOSE("File not found!\n"); + return -1; + } + DEBUG("ino: %lu (hash: %u)\n", p->buf.ino, p->buf.name_hash); + + /* hit? */ + if (offset >= p->buf.offset && offset < (p->buf.offset + p->buf.count)) { + o = offset - p->buf.offset; + c = count > p->buf.count - o ? p->buf.count - o : count; + memcpy(buffer, p->buf.data + o, c); + buffer += c; + offset += c; + count -= c; + read += c; + } + + if (count && p->buf.type == SHFS_FCACHE_WRITE) { + shfs_proc_write(d, p->buf.offset, p->buf.count, p->buf.data); + p->buf.type = SHFS_FCACHE_READ; + p->buf.offset = offset; + p->buf.count = 0; + } + + while (count) { + o = offset & PAGE_MASK; + x = offset - o; + if (p->buf.offset + p->buf.count == offset) + readahead = p->buf.count; + else { + p->buf.offset = o; + p->buf.count = 0; + readahead = 0; + } + if (readahead < (x + count)) + readahead = x + count; + readahead = (readahead+PAGE_SIZE-1) & PAGE_MASK; + if (readahead > SHFS_FCACHE_SIZE) + readahead = SHFS_FCACHE_SIZE; + if (o % readahead) { /* HD */ + y = o, z = readahead; + while (y && z) + if (y > z) y %= z; else z %= y; + readahead = y > z ? y : z; + } + if (p->buf.count + readahead > SHFS_FCACHE_SIZE) { + p->buf.offset = o; + p->buf.count = 0; + } + DEBUG("rw cache read: offset: %u, size %u\n", o, readahead); + res = shfs_proc_read(d, o, readahead, p->buf.data+p->buf.count); + if (res < 0) { + p->buf.count = 0; + return res; + } + + c = res - x; + if (c > count) + c = count; + memcpy(buffer, p->buf.data + p->buf.count + x, c); + buffer += c; + offset += c; + count -= c; + read += c; + p->buf.count += res; + } + return read; + } + VERBOSE("Invalid file!\n"); + return -1; +} + +int +shfs_fcache_write(struct dentry *d, unsigned offset, unsigned count, char *buffer) +{ + struct inode *inode = d->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + unsigned long hsh, ino; + unsigned o, c, wrote = 0; + struct shfs_file_hash_node *p; + int res = 0; + + DEBUG("Writing to file: offset: %u, count: %u\n", offset, count); + + if (d->d_inode && d->d_inode->i_ino) { + ino = d->d_inode->i_ino; + DEBUG("ino: %lu\n", ino); + hsh = shfs_file_cache_hash(ino); + for (p = file_cache.hash[hsh]; p; p = p->next) { + if ((p->buf.ino == ino) + && (p->buf.name_hash == d->d_name.hash)) + break; + } + if (!p) { + VERBOSE("File not found!\n"); + return -1; + } + DEBUG("ino: %lu (hash: %u)\n", p->buf.ino, p->buf.name_hash); + + if (p->buf.type == SHFS_FCACHE_READ) { + p->buf.offset = offset; + p->buf.count = 0; + p->buf.type = SHFS_FCACHE_WRITE; + } + + DEBUG("1 cache: offset: %u, count: %u\n", p->buf.offset, p->buf.count); + if (offset >= p->buf.offset && offset < (p->buf.offset + SHFS_FCACHE_SIZE)) { + o = offset - p->buf.offset; + c = count > SHFS_FCACHE_SIZE - o ? SHFS_FCACHE_SIZE - o : count; + memcpy(p->buf.data + o, buffer, c); + if (o + c > p->buf.count) + p->buf.count = o + c; + buffer += c; + offset += c; + count -= c; + wrote += c; + } + DEBUG("2 cache: offset: %u, count: %u\n", p->buf.offset, p->buf.count); + while (count) { + if ((res = shfs_proc_write(d, p->buf.offset, p->buf.count, p->buf.data)) < 0) + break; + c = count > SHFS_FCACHE_SIZE ? SHFS_FCACHE_SIZE : count; + memcpy(p->buf.data, buffer, c); + p->buf.offset = offset; + p->buf.count = c; + buffer += c; + offset += c; + count -= c; + wrote += c; + } + DEBUG("3 cache: offset: %u, count: %u\n", p->buf.offset, p->buf.count); + + return res >= 0 ? wrote : res; + } + VERBOSE("Invalid file!\n"); + return -1; +} + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/file.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/file.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/file.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/file.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,262 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include +#include + +#include "shfs.h" +#include "shfs_proc.h" + +static int shfs_file_readpage(struct file*, struct page*); +static int shfs_file_writepage(struct page*); +static int shfs_file_preparewrite(struct file*, struct page*, unsigned, unsigned); +static int shfs_file_commitwrite(struct file*, struct page*, unsigned, unsigned); +static int shfs_file_permission(struct inode*, int); +static int shfs_file_open(struct inode*, struct file*); +static int shfs_file_flush(struct file*); +static int shfs_file_release(struct inode*, struct file*); + +struct file_operations shfs_file_operations = { + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, + open: shfs_file_open, + flush: shfs_file_flush, + release: shfs_file_release, +}; + +struct inode_operations shfs_file_inode_operations = { + permission: shfs_file_permission, + setattr: shfs_notify_change, +}; + +struct address_space_operations shfs_file_aops = { + readpage: shfs_file_readpage, + writepage: shfs_file_writepage, + prepare_write: shfs_file_preparewrite, + commit_write: shfs_file_commitwrite +}; + +static int +shfs_file_readpage(struct file *f, struct page *p) +{ + struct dentry *dentry = f->f_dentry; + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + char *buffer; + unsigned long offset, count; + int result; + + get_page(p); + + buffer = page_address(p); + offset = p->index << PAGE_CACHE_SHIFT; + count = PAGE_SIZE; + + lock_kernel(); + do { + DEBUG(" \n"); + if (!shfs_lock(info)) { + VERBOSE("Interrupted\n"); + unlock_kernel(); + result = -EINTR; + goto io_error; + + } + if (!info->mnt.disable_fcache) + result = shfs_fcache_read(dentry, offset, count, buffer); + else + result = shfs_proc_read(dentry, offset, count, buffer); + shfs_unlock(info); + if (result < 0) { + VERBOSE(" IO error! (%d)\n", result); + unlock_kernel(); + goto io_error; + } + count -= result; + offset += result; + buffer += result; + dentry->d_inode->i_atime = CURRENT_TIME; + if (!result) + break; + } while (count); + + unlock_kernel(); + memset(buffer, 0, count); + flush_dcache_page(p); + SetPageUptodate(p); + result = 0; +io_error: + UnlockPage(p); + put_page(p); + return shfs_remove_sigpipe(result); +} + +static int +shfs_file_writepage(struct page *p) +{ + VERBOSE(" This should't happen!!\n"); + return -EFAULT; +} + +static int +shfs_file_preparewrite(struct file *f, struct page *p, unsigned offset, unsigned to) +{ + DEBUG("page: %p, offset: %u, to: %u\n", p, offset, to); + kmap(p); + return 0; +} + +static int +shfs_file_commitwrite(struct file *f, struct page *p, unsigned offset, unsigned to) +{ + struct dentry *dentry = f->f_dentry; + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + struct inode *inode = p->mapping->host; + char *buffer = page_address(p) + offset; + int written = 0, result; + unsigned count = to - offset; + + DEBUG("page: %p, offset: %u, to: %u\n", p, offset, to); + offset += p->index << PAGE_CACHE_SHIFT; + + lock_kernel(); + + if (info->mnt.readonly) { + result = -EROFS; + goto error; + } + + do { + if (!shfs_lock(info)) { + VERBOSE("Interrupted\n"); + result = -EINTR; + goto error; + } + if (!info->mnt.disable_fcache) + result = shfs_fcache_write(dentry, offset, count, buffer); + else + result = shfs_proc_write(dentry, offset, count, buffer); + shfs_unlock(info); + if (result < 0) { + VERBOSE(" IO error! (%d)\n", result); + goto error; + } + + count -= result; + offset += result; + buffer += result; + written += result; + dentry->d_inode->i_mtime = dentry->d_inode->i_atime = CURRENT_TIME; + if (!result) + break; + + } while (count); + +// memset(buffer, 0, count); + result = 0; +error: + unlock_kernel(); + kunmap(p); + + DEBUG("offset: %u, i_size: %lld\n", offset, inode->i_size); + if (offset > inode->i_size) { + struct iattr attr = { + ia_valid: ATTR_SIZE, + ia_size: offset + }; + inode->i_size = offset; + mark_inode_dirty(inode); + if (!shfs_lock(info)) { + VERBOSE("Interrupted\n"); + return -EINTR; + } + shfs_dcache_update_fattr(dentry, &attr); + shfs_unlock(info); + } + + return shfs_remove_sigpipe(result); +} + +static int +shfs_file_permission(struct inode *inode, int mask) +{ + int mode = inode->i_mode; + + mode >>= 6; + if ((mode & 7 & mask) != mask) + return -EACCES; + return 0; +} + +static int +shfs_file_open(struct inode *inode, struct file *f) +{ + struct dentry *dentry = f->f_dentry; + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + int flags = f->f_flags & O_ACCMODE; + int res; + + DEBUG(" %s\n", dentry->d_name.name); + res = 0; + if (!info->mnt.disable_fcache) { +// lock_kernel(); + if (!shfs_lock(info)) { + VERBOSE("Interrupted\n"); + return -EINTR; + } + if (flags == O_RDONLY || flags == O_RDWR) + res = shfs_proc_read(f->f_dentry, 0, 0, NULL); + if ((res >= 0 && (flags == O_WRONLY || flags == O_RDWR))) { + res = info->mnt.readonly ? -EROFS : shfs_proc_write(f->f_dentry, 0, 0, NULL); + } + if (res >= 0) + shfs_fcache_add(f); + shfs_unlock(info); +// unlock_kernel(); + } + return res; +} + +static int +shfs_file_flush(struct file *f) +{ + struct dentry *dentry = f->f_dentry; + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + int res; + + DEBUG(" %s\n", dentry->d_name.name); + res = 0; + if (!info->mnt.disable_fcache) { + if (!shfs_lock(info)) { + VERBOSE("Interrupted\n"); + return -EINTR; + } + res = shfs_fcache_sync(f); + shfs_unlock(info); + } + return shfs_remove_sigpipe(res); +} + +static int +shfs_file_release(struct inode *inode, struct file *f) +{ + struct dentry *dentry = f->f_dentry; + struct shfs_sb_info *info = (struct shfs_sb_info*)dentry->d_sb->u.generic_sbp; + int res; + + DEBUG(" %s\n", dentry->d_name.name); + res = 0; + if (atomic_read(&dentry->d_count) == 1 && !info->mnt.disable_fcache) { + /* no way to return error */ + shfs_locku(info); + res = shfs_fcache_remove(f); + shfs_dcache_invalidate(dentry->d_parent); + shfs_unlock(info); + } + return shfs_remove_sigpipe(res); +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/inode.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/inode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/inode.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,272 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "shfs.h" +#include "shfs_proc.h" + +MODULE_AUTHOR("Zemljanka core team"); +MODULE_DESCRIPTION("Shell File System"); + +extern struct inode_operations shfs_dir_inode_operations; +extern struct file_operations shfs_dir_operations; +extern struct inode_operations shfs_file_inode_operations; +extern struct file_operations shfs_file_operations; +extern struct address_space_operations shfs_file_aops; +extern struct inode_operations shfs_symlink_inode_operations; + +static void shfs_delete_inode(struct inode*); +static void shfs_put_super(struct super_block*); +static int shfs_statfs(struct super_block*, struct statfs*); +static void shfs_set_inode_attr(struct inode*, struct shfs_fattr*); + +kmem_cache_t *dir_hash_cache = NULL; +kmem_cache_t *dir_list_cache = NULL; +kmem_cache_t *dir_name_cache = NULL; +kmem_cache_t *file_hash_cache = NULL; + +static struct super_operations shfs_sops = { + put_inode: force_delete, + delete_inode: shfs_delete_inode, + put_super: shfs_put_super, + statfs: shfs_statfs, +}; + +#ifdef SHFS_ALLOC_DEBUG + unsigned long alloc; +#endif + +struct inode* +shfs_iget(struct super_block *sb, struct shfs_fattr *fattr) +{ + struct inode *res; + + DEBUG("\n"); + + res = new_inode(sb); + if(!res) + return NULL; + res->i_ino = fattr->f_ino; + shfs_set_inode_attr(res, fattr); + + if (S_ISDIR(res->i_mode)) { + DEBUG(" It's a directory\n"); + res->i_op = &shfs_dir_inode_operations; + res->i_fop = &shfs_dir_operations; + } else if (S_ISLNK(res->i_mode)) { + DEBUG(" It's a link\n"); + res->i_op = &shfs_symlink_inode_operations; + } else if (S_ISREG(res->i_mode)) { + DEBUG(" It's a file\n"); + res->i_op = &shfs_file_inode_operations; + res->i_fop = &shfs_file_operations; + res->i_data.a_ops = &shfs_file_aops; + } + + insert_inode_hash(res); + return res; +} + +static void +shfs_set_inode_attr(struct inode *inode, struct shfs_fattr *fattr) +{ + inode->i_mode = fattr->f_mode; + inode->i_nlink = fattr->f_nlink; + inode->i_uid = fattr->f_uid; + inode->i_gid = fattr->f_gid; + inode->i_rdev = fattr->f_rdev; + inode->i_ctime = fattr->f_ctime; + inode->i_atime = fattr->f_atime; + inode->i_mtime = fattr->f_mtime; + inode->i_blksize= fattr->f_blksize; + inode->i_blocks = fattr->f_blocks; + inode->i_size = fattr->f_size; +} + +static void +shfs_delete_inode(struct inode *inode) +{ +// lock_kernel(); + clear_inode(inode); +// unlock_kernel(); +} + +static void +shfs_put_super(struct super_block *sb) +{ + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + + fput(info->mnt.pin); + fput(info->mnt.pout); + if (!shfs_lock(info)) { + VERBOSE("Cannot free caches! Memory leak will occur!\n"); + return; + } + shfs_dcache_empty(info); + shfs_fcache_empty(info); + shfs_unlock(info); + kfree(info->mnt.printf_buffer); + kfree(info->mnt.readln_buffer); + kfree(info); + VERBOSE("Super block discarded!\n"); +} + +static int +shfs_statfs(struct super_block *sb, struct statfs *attr) +{ + DEBUG("\n"); + + attr->f_type = SHFS_SUPER_MAGIC; + attr->f_bsize = 4096; + attr->f_blocks = 0; + attr->f_bfree = 0; + attr->f_bavail = 0; + attr->f_files = 1; + attr->f_bavail = 1; + attr->f_namelen = SHFS_PATH_MAX; + + return 0; +} + +struct super_block* +shfs_read_super(struct super_block *sb, void *opts, int silent) +{ + struct shfs_sb_info *info; + struct shfs_fattr root; + struct inode *root_inode; + + info = (struct shfs_sb_info*)kmalloc(sizeof(struct shfs_sb_info), GFP_KERNEL); + if (!info) { + VERBOSE("Not enough kmem to allocate info!!\n"); + goto out; + } + + memset(info, 0, sizeof(struct shfs_sb_info)); + + sb->u.generic_sbp = info; + sb->s_blocksize = 4096; + sb->s_blocksize_bits = 12; + sb->s_magic = SHFS_SUPER_MAGIC; + sb->s_op = &shfs_sops; + sb->s_flags = 0; + + /* fill-in default values */ + info->mnt.version = SHFS_VERSION; + info->mnt.disable_fcache = 0; + info->mnt.generic_host = 0; + info->mnt.preserve_own = 0; + info->mnt.root_mode = (S_IRUSR | S_IWUSR | S_IXUSR | S_IFDIR); + info->mnt.uid = current->uid; + info->mnt.gid = current->gid; + info->mnt.readonly = 0; + info->mnt.garbage = 0; + info->mnt.garbage_read = 0; + info->mnt.garbage_write = 0; + info->mnt.printf_buffer = (char *)kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + if (!info->mnt.printf_buffer) { + VERBOSE("Not enough kmem to allocate printf buffer!\n"); + goto out_no_mem; + } + info->mnt.readln_buffer_len = 0; + info->mnt.readln_buffer = (char *)kmalloc(READLN_BUFFER_SIZE, GFP_KERNEL); + if (!info->mnt.readln_buffer) { + VERBOSE("Not enough kmem to allocate readln buffer!\n"); + kfree(info->mnt.printf_buffer); + goto out_no_mem; + } + init_MUTEX(&info->sem); + + info->mnt.mount_point[0] = 0; + + shfs_dcache_init(info); + shfs_fcache_init(info); + + if(shfs_parse_options(info, opts) < 0) { + VERBOSE("Invalid options!\n"); + goto out_no_opts; + } + + DEBUG("uid %d, gid %d, root=%s, ro: %d\n", + info->mnt.uid, info->mnt.gid, info->mnt.root, info->mnt.readonly); + + if (shfs_get_system(info) < 0) { + VERBOSE("Broken pipe, cannot connect!\n"); + goto out_no_opts; + } + + shfs_init_root_dirent(info, &root); + root_inode = shfs_iget(sb, &root); + if (!root_inode) + goto out_no_root; + sb->s_root = d_alloc_root(root_inode); + if (!sb->s_root) + goto out_no_root; + + DEBUG("Mount succeded!\n"); + return sb; + +out_no_root: + iput(root_inode); +out_no_opts: + kfree(info->mnt.printf_buffer); + kfree(info->mnt.readln_buffer); +out_no_mem: + kfree(info); +out: + DEBUG("Mount failed!!\n"); + return NULL; +} + +static DECLARE_FSTYPE (sh_fs_type, "shfs", shfs_read_super, 0); + +static int __init +init_sh_fs(void) +{ + VERBOSE("shfs file system, (c) 2002, 2003 Miroslav Spousta\n"); + dir_hash_cache = kmem_cache_create("shfs_dir_hash", sizeof(struct shfs_dir_hash_node), 0, 0, NULL, NULL); + dir_list_cache = kmem_cache_create("shfs_dir_list", sizeof(struct shfs_dir_list_node), 0, 0, NULL, NULL); + dir_name_cache = kmem_cache_create("shfs_name_cache", SHFS_PATH_MAX, 0, 0, NULL, NULL); + file_hash_cache = kmem_cache_create("shfs_file_hash", sizeof(struct shfs_file_hash_node), 0, 0, NULL, NULL); + DEBUG("dir_hash_cache: %p\n", dir_hash_cache); + DEBUG("dir_list_cache: %p\n", dir_list_cache); + DEBUG("dir_name_cache: %p\n", dir_name_cache); + DEBUG("file_hash_cache: %p\n", file_hash_cache); +#ifdef SHFS_ALLOC_DEBUG + alloc = 0; +#endif + return register_filesystem(&sh_fs_type); +} + +static void __exit +exit_sh_fs(void) +{ + VERBOSE("Unregistering shfs.\n"); +#ifdef SHFS_ALLOC_DEBUG + if (alloc) + VERBOSE("Memory leak (%lu)!", alloc); +#endif + unregister_filesystem(&sh_fs_type); + kmem_cache_destroy(file_hash_cache); + kmem_cache_destroy(dir_name_cache); + kmem_cache_destroy(dir_list_cache); + kmem_cache_destroy(dir_hash_cache); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_sh_fs); +module_exit(exit_sh_fs); + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,10)) + MODULE_LICENSE("GPL"); +#endif + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/proc.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/proc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/proc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/proc.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,1455 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define SHFS_DEBUG_HERE + +#include "shfs.h" +#include "shfs_proc.h" +#include "shfs_proto.h" + +void +shfs_init_root_dirent(struct shfs_sb_info *server, struct shfs_fattr *fattr) +{ + memset(fattr, 0, sizeof(*fattr)); + fattr->f_nlink = 1; + fattr->f_uid = server->mnt.uid; + fattr->f_gid = server->mnt.gid; + fattr->f_blksize = 512; + + fattr->f_ino = 2; + fattr->f_mtime = CURRENT_TIME; + fattr->f_mode = server->mnt.root_mode; + fattr->f_size = 512; + fattr->f_blocks = 0; +} + +static int +shfs_parse_mode(char *mode) +{ + return ((mode[0]-'0')<<6) + ((mode[1]-'0')<<3) + (mode[2]-'0'); +} + +int +shfs_parse_options(struct shfs_sb_info *info, void *opts) +{ + char *p, *q; + int i; + + strcpy(info->mnt.root, ""); + info->mnt.pin = info->mnt.pout = NULL; + info->mnt.fmask = 00177777; + + if (!opts) + return -1; + + for (p = strtok(opts, ","); p; p = strtok(NULL, ",")) { + if (strncmp(p, "root=", 5) == 0) { + if (strlen(p+5) > SHFS_PATH_MAX) + goto ugly_opts; + strcpy(info->mnt.root, p+5); + } else if (strncmp(p, "ro", 2) == 0) { + info->mnt.readonly = 1; + } else if (strncmp(p, "rw", 2) == 0) { + info->mnt.readonly = 0; + } else if (strncmp(p, "suid", 4) == 0) { + info->mnt.fmask |= S_ISUID|S_ISGID; + } else if (strncmp(p, "nosuid", 6) == 0) { + info->mnt.fmask &= ~(S_ISUID|S_ISGID); + } else if (strncmp(p, "dev", 3) == 0) { + info->mnt.fmask |= S_IFCHR|S_IFBLK; + } else if (strncmp(p, "nodev", 5) == 0) { + info->mnt.fmask &= ~(S_IFCHR|S_IFBLK); + } else if (strncmp(p, "exec", 4) == 0) { + info->mnt.fmask |= S_IXUSR|S_IXGRP|S_IXOTH; + } else if (strncmp(p, "noexec", 6) == 0) { + info->mnt.fmask &= ~(S_IXUSR|S_IXGRP|S_IXOTH); + } else if (strncmp(p, "nocache", 7) == 0) { + info->mnt.disable_fcache = 1; + } else if (strncmp(p, "generic", 7) == 0) { + info->mnt.generic_host = 1; + } else if (strncmp(p, "preserve", 8) == 0) { + info->mnt.preserve_own = 1; + } else if (strncmp(p, "uid=", 4) == 0) { + if (strlen(p+4) > 10) + goto ugly_opts; + q = p+4; + i = simple_strtoul(q, &q, 10); + info->mnt.uid = i; + } else if (strncmp(p, "gid=", 4) == 0) { + if (strlen(p+4) > 10) + goto ugly_opts; + q = p+4; + i = simple_strtoul(q, &q, 10); + info->mnt.gid = i; + } else if (strncmp(p, "rmode=", 6) == 0) { + if (strlen(p+6) > 3) + goto ugly_opts; + info->mnt.root_mode = S_IFDIR | (shfs_parse_mode(p+6) & (S_IRWXU | S_IRWXG | S_IRWXO)); + } else if (strncmp(p, "fdi=", 4) == 0) { + if (strlen(p+4) > 5) + goto ugly_opts; + q = p+4; + i = simple_strtoul(q, &q, 10); + VERBOSE("fdi=%d\n", i); + info->mnt.pin = fget(i); + } else if (strncmp(p, "fdo=", 4) == 0) { + if (strlen(p+4) > 5) + goto ugly_opts; + q = p+4; + i = simple_strtoul(q, &q, 10); + VERBOSE("fdo=%d\n", i); + info->mnt.pout = fget(i); + } + } + if (!info->mnt.pin || !info->mnt.pout) + goto ugly_opts; + return 0; + +ugly_opts: + VERBOSE("Your options sucks!\n"); + return -1; +} + +static int clear_garbage(struct shfs_sb_info *); + +static int +pipe_write(struct shfs_sb_info *info, const void *buf, int len) +{ + int bytes, wr = 0; + int res; + struct file *f = info->mnt.pout; + mm_segment_t fs; + + if (info->mnt.garbage) + if ((res = clear_garbage(info)) < 0) + return res; + + fs = get_fs(); + set_fs(get_ds()); + bytes = len; +retry: + while (bytes && ((wr = f->f_op->write(f, buf, bytes, &f->f_pos)) > 0)) { + DEBUG("Wrote: %d\n", wr); + buf += wr; + bytes -= wr; + } + if (wr == -EAGAIN) + goto retry; + set_fs(fs); + + if (wr < 0) { + info->mnt.garbage = 1; + info->mnt.garbage_write = bytes; + return wr; + } + return len; +} + +int +shfs_pipe_printf(struct shfs_sb_info *info, const char *fmt, ...) +{ + va_list ap; + int res; + + if (info->mnt.garbage) + if ((res = clear_garbage(info)) < 0) + return res; + + va_start(ap, fmt); + /* shfs is locked, we can write to printf_buffer safely */ + vsnprintf(info->mnt.printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); + va_end(ap); + + DEBUG("Write line: %s\n", info->mnt.printf_buffer); + return pipe_write(info, (void *)info->mnt.printf_buffer, strlen(info->mnt.printf_buffer)); +} + +#define BUFFER info->mnt.readln_buffer +#define LEN info->mnt.readln_buffer_len + +static int +pipe_read(struct shfs_sb_info *info, void *buf, int len) +{ + int bytes, c, res, rd = 0; + struct file *f = info->mnt.pin; + mm_segment_t fs; + + if (info->mnt.garbage) + if ((res = clear_garbage(info)) < 0) + return res; + + if (LEN > 0) { + c = len > LEN ? LEN : len; + memcpy(buf, BUFFER, c); + buf+= c; + LEN -= c; + len -= c; + if (LEN > 0) + memmove(BUFFER, BUFFER+c, LEN); + } + + fs = get_fs(); + set_fs(get_ds()); + bytes = len; + while (bytes && ((rd = f->f_op->read(f, buf, bytes, &f->f_pos)) > 0)) { + buf += rd; + bytes -= rd; + } + set_fs(fs); + + if (rd < 0) { + info->mnt.garbage = 1; + info->mnt.garbage_read = bytes; + return rd; + } + return len; +} + +int +shfs_pipe_readln(struct shfs_sb_info *info, char *buf, int len) +{ + struct file *f = info->mnt.pin; + int c, res, l = 0, rd = 0; + char *str; + mm_segment_t fs; + + if (info->mnt.garbage) + if ((res = clear_garbage(info)) < 0) + return res; + + do { + str = memchr(BUFFER, '\n', LEN); + if (str) { + DEBUG("hit!\n"); + *str = '\0'; + strncpy(buf, BUFFER, len-1); + buf[len-1] = '\0'; + c = LEN-(str-BUFFER+1); + memmove(BUFFER, str+1, c); + LEN = c; + } else { + DEBUG("miss, size: %d\n", LEN); + c = READLN_BUFFER_SIZE - LEN; + if (c > 0) { + fs = get_fs(); + set_fs(get_ds()); + rd = f->f_op->read(f, BUFFER+LEN, c, &f->f_pos); + DEBUG("rd: %d\n", rd); + set_fs(fs); + if (rd == -EAGAIN) + continue; + if (rd < 0) { + info->mnt.garbage = 1; + info->mnt.garbage_read = 0; + return rd; + } + LEN += rd; + } else { + BUFFER[READLN_BUFFER_SIZE-1] = '\n'; + } + } + /* do not lock while reading 0 bytes */ + if (l++ > READLN_BUFFER_SIZE && LEN == 0) + return -1; + } while (!str); + + DEBUG("size: %d\n", LEN); + DEBUG("Read line(%d): %s\n", strlen(buf), buf); + return strlen(buf); +} + +static int +reply(char *s) +{ + if (strncmp(s, "### ", 4)) + return 0; + return simple_strtoul(s+4, NULL, 10); +} + +static int +clear_garbage(struct shfs_sb_info *info) +{ + char line[SHFS_LINE_MAX]; + static unsigned long seq = 12345; + int i, state, c, garbage; + int res; + + DEBUG(" start\n"); + garbage = info->mnt.garbage_write; + if (garbage) + memset(line, ' ', SHFS_LINE_MAX); + while (garbage > 0) { + c = garbage < SHFS_LINE_MAX ? garbage : SHFS_LINE_MAX; + info->mnt.garbage = 0; + res = pipe_write(info, line, c); + if (res < 0) { + info->mnt.garbage_write = garbage; + goto error; + } + garbage -= res; + } + info->mnt.garbage_write = 0; + garbage = info->mnt.garbage_read; + while (garbage > 0) { + c = garbage < SHFS_LINE_MAX ? garbage : SHFS_LINE_MAX; + info->mnt.garbage = 0; + res = pipe_read(info, line, c); + if (res < 0) { + info->mnt.garbage_read = garbage; + goto error; + } + garbage -= res; + } + info->mnt.garbage_read = 0; + + info->mnt.garbage = 0; + if ((res = do_ping(info, seq++)) < 0) + goto error; + DEBUG("reading..\n"); + state = 0; + for (i = 0; i < 100000; i++) { + info->mnt.garbage = 0; + if ((res = shfs_pipe_readln(info, line, SHFS_LINE_MAX)) < 0) + goto error; + if (((state == 0) || (state == 1)) && reply(line) == REP_PRELIM) { + state = 1; + } else if (state == 1 && simple_strtoul(line, NULL, 10) == (seq-1)) { + state = 2; + } else if (state == 2 && reply(line) == REP_NOP) { + DEBUG(" cleared.\n"); + return 0; + } else { + state = 0; + } + } +error: + info->mnt.garbage = 1; + DEBUG(" failure!\n"); + return res; +} + + + +unsigned int +shfs_get_this_year(void) +{ + unsigned long s_per_year = 365*24*3600; + unsigned long delta_s = 24*3600; + + unsigned int year = CURRENT_TIME / (s_per_year + delta_s/4); + return 1970 + year; +} + +unsigned int +shfs_get_this_month() { + int month = -1; + long secs = CURRENT_TIME % (365*24*3600+24*3600/4); + static long days_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (shfs_get_this_year() % 4) { + days_month[1] = 28; + } else { + days_month[1] = 29; + } + while (month < 11 && secs >= 0) { + month++; + secs-=24*3600*days_month[month]; + } + return (unsigned int)month; +} + +unsigned int +shfs_get_month(char *mon) +{ + static char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + unsigned int i; + + for (i = 0; i<12; i++) + if(strcmp(mon, months[i]) == 0) { + DEBUG("%s: %u\n", mon, i); + return i; + } + + return 0; +} + +static int +shfs_parse_dir(char *s, char **col) +{ + int c = 0; + int is_space = 1; + int device = 0; + + while (*s) { + if (c == DIR_COLS) + break; + + if (*s == ' ') { + if (!is_space) { + if ((c-1 == DIR_SIZE) && device) { + while (*s && (*s == ' ')) + s++; + while (*s && (*s != ' ')) + s++; + } + *s = '\0'; + is_space = 1; + } + } else { + if (is_space) { + /* (b)lock/(c)haracter device hack */ + col[c++] = s; + is_space = 0; + if ((c-1 == DIR_PERM) && ((*s == 'b')||(*s == 'c'))) { + device = 1; + } + + } + } + s++; + } + return c; +} + +int +shfs_loaddir(struct shfs_sb_info* info, char* name, struct shfs_directory* dir) +{ + char line[SHFS_LINE_MAX]; + char path[SHFS_PATH_MAX]; + char *col[DIR_COLS]; + char *b, *s; + struct shfs_dir_list_node *p, *q; + umode_t mode; + unsigned int year, mon, day, hour, min, this_year, this_month; + int device; + int namelen; + int res; + + DEBUG(" reading %s\n", name); + + this_year = shfs_get_this_year(); + this_month = shfs_get_this_month(); + + if (strlen(info->mnt.root) + strlen(name) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + if ((res = do_lsdir(info, name)) < 0) { + VERBOSE("ls request failed!\n"); + return res; + } + + while ((res = shfs_pipe_readln(info, line, SHFS_LINE_MAX)) > 0) { + switch (reply(line)) { + case REP_COMPLETE: + return 0; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + case REP_ERROR: + return -EIO; + } + + res = shfs_parse_dir(line, col); + if (res != DIR_COLS) + continue; /* skip `total xx' line */ + + s = col[DIR_NAME]; + if ((strcmp(s, ".") != 0) && (strcmp(s, "..") != 0)) { + p = (struct shfs_dir_list_node*)KMEM_ALLOC("dir", dir_list_cache, GFP_KERNEL); + if (!p) { + VERBOSE(" slab cache alloc error!\n"); + res = -1; + goto out; + } + memset(p, 0, sizeof(struct shfs_dir_list_node)); + + namelen = strlen(s) + 1; + + if(strstr(s, "->")){ + char *ss = strstr(s, "->"); + if(*(ss + 3) == '/') + namelen += strlen(info->mnt.mount_point); + } + + if (namelen + 1 > SHFS_PATH_MAX) { + VERBOSE("too long entry!\n"); + KMEM_FREE("dir", dir_list_cache, p); + res = -1; + goto out; + } + p->entry.name = (char *)KMEM_ALLOC("name", dir_name_cache, GFP_KERNEL); + if (!p->entry.name) { + VERBOSE("slab cache alloc error!\n"); + KMEM_FREE("dir", dir_list_cache, p); + res = -1; + goto out; + } + + strcpy(p->entry.name, s); + + s = col[DIR_PERM]; + mode = 0; device = 0; + switch(s[0]) { + case 'b': + device = 1; + if ((info->mnt.fmask & S_IFMT) & S_IFBLK) + mode = S_IFBLK; + else + mode = S_IFREG; + break; + case 'c': + device = 1; + if ((info->mnt.fmask & S_IFMT) & S_IFCHR) + mode = S_IFCHR; + else + mode = S_IFREG; + break; + case 's': + case 'S': /* IRIX64 socket */ + mode = S_IFSOCK; + break; + case 'd': + mode = S_IFDIR; + break; + case 'l': + mode = S_IFLNK; + break; + case '-': + mode = S_IFREG; + break; + case 'p': + mode = S_IFIFO; + break; + } + if (s[1] == 'r') mode |= S_IRUSR; + if (s[2] == 'w') mode |= S_IWUSR; + if (s[3] == 'x') mode |= S_IXUSR; + if (s[3] == 's') mode |= S_IXUSR | S_ISUID; + if (s[3] == 'S') mode |= S_ISUID; + if (s[4] == 'r') mode |= S_IRGRP; + if (s[5] == 'w') mode |= S_IWGRP; + if (s[6] == 'x') mode |= S_IXGRP; + if (s[6] == 's') mode |= S_IXGRP | S_ISGID; + if (s[6] == 'S') mode |= S_ISGID; + if (s[7] == 'r') mode |= S_IROTH; + if (s[8] == 'w') mode |= S_IWOTH; + if (s[9] == 'x') mode |= S_IXOTH; + if (s[9] == 't') mode |= S_ISVTX | S_IXOTH; + if (s[9] == 'T') mode |= S_ISVTX; + p->entry.mode = (mode & S_IFMT) == S_IFREG ? mode & info->mnt.fmask : mode; + + p->entry.ino = simple_strtoul(col[DIR_INODE], NULL, 10); +// p->entry.ino = iunique(info->sb, 2); + p->entry.uid = simple_strtoul(col[DIR_UID], NULL, 10); + p->entry.gid = simple_strtoul(col[DIR_GID], NULL, 10); + + if (!device) { + p->entry.size = simple_strtoul(col[DIR_SIZE], NULL, 10); + } else { + unsigned short major, minor; + p->entry.size = 0; + major = (unsigned short) simple_strtoul(col[DIR_SIZE], &s, 10); + while (*s && (!isdigit(*s))) + s++; + minor = (unsigned short) simple_strtoul(s, NULL, 10); + p->entry.rdev = MKDEV(major, minor); + } + p->entry.nlink = simple_strtoul(col[DIR_NLINK], NULL, 10); + p->entry.blocksize = 4096; + p->entry.blocks = (p->entry.size + 4095) >> 11; + + mon = shfs_get_month(col[DIR_MONTH]); + day = simple_strtoul(col[DIR_DAY], NULL, 10); + + s = col[DIR_YEAR]; + if (!strchr(s, ':')) { + year = simple_strtoul(s, NULL, 10); + hour = 12; + min = 0; + } else { + year = this_year; + if (mon > this_month) + year--; + b = strchr(s, ':'); + *b = 0; + hour = simple_strtoul(s, NULL, 10); + min = simple_strtoul(++b, NULL, 10); + } + p->entry.atime = mktime(year, mon + 1, day, hour, min, 0); + p->entry.changed = 1; + + /* symlink hack */ + if (((mode & S_IFMT) == S_IFLNK) && (strstr(p->entry.name, "->"))) { + char *ss = strstr(p->entry.name, "->"); + + *(ss - 1) = 0; + if ((*(ss + 3) == '/') && (strlen(info->mnt.mount_point) + strlen(ss + 3) + 1 < SHFS_PATH_MAX)) { + strcpy(path, ss+3); + sprintf(ss+3, "%s%s", info->mnt.mount_point, path); + } + } + DEBUG("Name: %s, mode: %o, inode: %lu, size: %lu, nlink: %d, month: %d, day: %d, year: %d, hour: %d, min: %d (time: %lu)\n", p->entry.name, p->entry.mode, p->entry.ino, p->entry.size, p->entry.nlink, mon, day, year, hour, min, p->entry.atime); + + p->prev = NULL; + p->next = dir->head; + dir->head = p; + } + } +out: + for (p = dir->head; p; p = q) { + q = p->next; + KMEM_FREE("name", dir_name_cache, p->entry.name); + KMEM_FREE("dir", dir_list_cache, p); + } + info->mnt.garbage_read = 0; + info->mnt.garbage = 1; + return res; +} + +/* aaa'aaa -> aaa'\''aaa */ +static int +replace_quote(char *name) +{ + char *s; + char *r = name; + int q = 0; + + while (*r) { + if (*r == '\'') + q++; + r++; + } + s = r+(3*q); + if ((s-name+1) > SHFS_PATH_MAX) + return -1; + + *(s--) = '\0'; + r--; + while (q) { + if (*r == '\'') { + s -= 3; + s[0] = '\''; + s[1] = '\\'; + s[2] = '\''; + s[3] = '\''; + q--; + } else { + *s = *r; + } + s--; + r--; + } + return 0; +} + +int +shfs_get_name(struct dentry *d, char *name) +{ + int len = 0; + struct dentry *p; + + for (p = d; p != p->d_parent; p = p->d_parent) + len += p->d_name.len + 1; + + if (len + 1 > SHFS_PATH_MAX) + return -1; + if (len == 0) { + name[0] = '/'; + name[1] = '\0'; + return 0; + } + + name[len] = 0; + for (p = d; p != p->d_parent; p = p->d_parent) { + len -= p->d_name.len; + strncpy(&(name[len]), p->d_name.name, p->d_name.len); + len--; + name[len] = '/'; + } + + return replace_quote(name); +} + +inline int +shfs_lock(struct shfs_sb_info *info) +{ + int res; + DEBUG("Locking...\n"); + res = down_interruptible(&(info->sem)); + DEBUG("Locked.\n"); + return (res != -EINTR); +} + +inline void +shfs_locku(struct shfs_sb_info *info) +{ + DEBUG("Locking...\n"); + down(&(info->sem)); + DEBUG("Locked.\n"); +} + +inline void +shfs_unlock(struct shfs_sb_info *info) +{ + DEBUG("Unlocking...\n"); + up(&(info->sem)); + DEBUG("Unlocked.\n"); +} + +inline int +shfs_remove_sigpipe(int result) +{ + switch (result) { +// case -ERESTARTSYS: +// result = -EINTR; +// goto cont; + case -EPIPE: + result = -EIO; +// cont: + if (sigismember(¤t->pending.signal, SIGPIPE)) { + sigdelset(¤t->pending.signal, SIGPIPE); + current->sigpending--; + } + break; + } + return result; +} + +int +shfs_get_attr(struct dentry *dentry, struct shfs_fattr *fattr, struct shfs_sb_info *info){ + struct shfs_directory *dir; + char buf[SHFS_LINE_MAX]; + struct shfs_dir_list_node *file; + int res; + + if (shfs_get_name(dentry->d_parent, buf) < 0) + return -ENAMETOOLONG; + res = shfs_dcache_get(info, buf, &dir); + + if (res < 0) { + VERBOSE(" shfs_cache_get failed!\n"); + return res; + } + + for (file = dir->head; file != NULL; file = file->next) + if (strcmp(dentry->d_name.name, file->entry.name) == 0) + break; + + if (!file) { + DEBUG(" file not found in parent dir cache!\n"); + return -ENOENT; + } + + fattr->f_mode = file->entry.mode; +/* if (S_ISDIR(file->entry.mode)) + fattr->f_mode |= info->mnt.dir_mode; + else if (S_ISREG(file->entry.mode)) + fattr->f_mode |= info->mnt.file_mode; +*/ + + fattr->f_ino = file->entry.ino; + fattr->f_size = file->entry.size; + fattr->f_rdev = file->entry.rdev; + fattr->f_blksize = file->entry.blocksize; + fattr->f_blocks = file->entry.blocks; + fattr->f_nlink = file->entry.nlink; + fattr->f_atime = file->entry.atime; + + /*Any way to get the real mtime, ctime?*/ + fattr->f_mtime = file->entry.atime; + fattr->f_ctime = file->entry.atime; + if (info->mnt.preserve_own) { + fattr->f_uid = file->entry.uid; + fattr->f_gid = file->entry.gid; + } else { + fattr->f_uid = info->mnt.uid; + fattr->f_gid = info->mnt.gid; + } + return 0; +} + +/* data should belaigned (offset % count == 0) */ +int +shfs_proc_read(struct dentry *dentry, unsigned offset, unsigned count, char *buffer){ + struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char file[SHFS_PATH_MAX + 6]; + char line[SHFS_LINE_MAX]; + int res; + + if (shfs_get_name(dentry, file) < 0) + return -ENAMETOOLONG; + DEBUG(" %s, off %u, %u bytes\n", file, (unsigned)offset, (unsigned)count); + if (count && offset % count) + VERBOSE("Reading unaligned data, could hang!\n"); + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + if ((res = do_read(info, file, offset, count)) < 0) { + VERBOSE("Can't send read command!\n"); + return res; + } + if ((res = shfs_pipe_readln(info, line, SHFS_LINE_MAX)) < 0) { + VERBOSE("Can't see read response!\n"); + info->mnt.garbage = 1; + info->mnt.garbage_read = count; + return res; + } + + switch (reply(line)) { + case REP_PRELIM: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + info->mnt.garbage = 1; + return -EIO; + } + if ((res = pipe_read(info, buffer, count)) < 0) { + VERBOSE("Read: no data!\n"); + return res; + } + if ((res = shfs_pipe_readln(info, line, SHFS_LINE_MAX)) < 0) { + VERBOSE("Can't see read response!\n"); + return res; + } + + switch (reply(line)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + info->mnt.garbage = 1; + return -EIO; + } + + DEBUG(" received %u bytes\n", count); + return count; +} + +int +shfs_proc_write(struct dentry *dentry, unsigned offset, unsigned count, char *buffer){ + struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char file[SHFS_PATH_MAX]; + char line[SHFS_LINE_MAX]; + int res; + + if (strlen(file) + strlen(info->mnt.root) + 1 > SHFS_PATH_MAX) { + VERBOSE(" Path too long!\n"); + return -1; + } + +// if (!count) +// return 0; + + if (shfs_get_name(dentry, file) < 0) + return -ENAMETOOLONG; + DEBUG(" %s, off %u, %u bytes\n", file, offset, count); + + if ((res = do_write(info, file, offset, count)) < 0) { + VERBOSE("Couldn't send write command!\n"); + goto out; + } + if ((res = shfs_pipe_readln(info, line, SHFS_LINE_MAX)) < 0) { + VERBOSE("Cannot read response!\n"); + info->mnt.garbage = 1; + info->mnt.garbage_write = count; + goto out; + } + switch (reply(line)) { + case REP_PRELIM: + break; + case REP_EPERM: + res = -EPERM; + goto out; + case REP_ENOENT: + res = -ENOENT; + goto out; + default: + info->mnt.garbage = 1; + res = -EIO; + goto out; + } + + if ((res = pipe_write(info, buffer, count)) < 0) { + VERBOSE("Couldn't write file!\n"); + goto out; + } + if ((res = shfs_pipe_readln(info, line, SHFS_LINE_MAX)) < 0) { + VERBOSE("Cannot read response!\n"); + goto out; + } + + switch (reply(line)) { + case REP_COMPLETE: + break; + case REP_EPERM: + res = -EPERM; + goto out; + case REP_ENOENT: + res = -ENOENT; + goto out; + case REP_ENOSPC: + res = -ENOSPC; + info->mnt.garbage = 1; + info->mnt.garbage_write = count; + goto out; + default: + info->mnt.garbage = 1; + res = -EIO; + goto out; + } + + DEBUG(" sent %u bytes\n", count); + /* shfs_dcache_invalidate is called in file.c */ + return count; +out: + shfs_dcache_invalidate(dentry->d_parent); + return res; +} + +int +shfs_proc_mkdir(struct shfs_sb_info *info, char *dir){ + int res; + char buf[SHFS_LINE_MAX]; + + if (strlen(info->mnt.root) + strlen(dir) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Creating directory: %s%s\n", info->mnt.root, dir); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_mkdir(info, dir)) < 0) { + VERBOSE("Could'n create directory!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_rmdir(struct shfs_sb_info *info, char *dir){ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(dir) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Removing directory: %s%s\n", info->mnt.root, buf); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_rmdir(info, dir)) < 0) { + VERBOSE("Couldn't remove directory!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_rename(struct shfs_sb_info *info, char *old, char *new){ + char buf[SHFS_LINE_MAX]; + int res; + + if ((strlen(info->mnt.root) + strlen(new) + 1 > SHFS_PATH_MAX) + || (strlen(info->mnt.root) + strlen(old) + 1 > SHFS_PATH_MAX)) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Rename %s%s -> %s%s\n", info->mnt.root, old, info->mnt.root, new); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_mv(info, old, new)) < 0) { + VERBOSE("Couldn't rename!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_unlink(struct shfs_sb_info *info, char *file){ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Removing file: %s%s\n", info->mnt.root, file); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_rm(info, file)) < 0) { + VERBOSE("Couldn't remove file!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_create(struct shfs_sb_info *info, char *file, int mode) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Creating file: %s%s\n", info->mnt.root, file); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_creat(info, file, mode & S_IALLUGO)) < 0) { + VERBOSE("Couldn't remove file!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_link(struct shfs_sb_info *info, char *old, char *new) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if ((strlen(info->mnt.root) + strlen(new) + 1 > SHFS_PATH_MAX) + ||(strlen(info->mnt.root) + strlen(old) + 1 > SHFS_PATH_MAX)) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Link %s%s -> %s%s\n", info->mnt.root, old, info->mnt.root, new); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_ln(info, old, new)) < 0) { + VERBOSE("Couldn't make link!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_symlink(struct shfs_sb_info *info, const char *old, const char *new) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if ((strlen(info->mnt.root) + strlen(new) + 1 > SHFS_PATH_MAX) + ||(strlen(info->mnt.root) + strlen(old) + 1 > SHFS_PATH_MAX)) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Symlink %s%s -> %s\n", info->mnt.root, old, new); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_sln(info, old, new)) < 0) { + VERBOSE("Couldn't make symlink!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_chmod(struct shfs_sb_info *info, char *file, umode_t mode) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Chmod %o %s%s\n", mode, info->mnt.root, file); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_chmod(info, file, mode & S_IALLUGO)) < 0) { + VERBOSE("Couldn't do chmod!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_chown(struct shfs_sb_info *info, char *file, uid_t user) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Chown %u %s%s\n", user, info->mnt.root, file); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_chown(info, file, user)) < 0) { + VERBOSE("Couldn't do chown!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_chgrp(struct shfs_sb_info *info, char *file, gid_t group) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Chown %u %s%s\n", group, info->mnt.root, file); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_chgrp(info, file, group)) < 0) { + VERBOSE("Couldn't do chgrp!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_proc_trunc(struct shfs_sb_info *info, char *file, loff_t size) +{ + char buf[SHFS_LINE_MAX]; + int res; + + if (strlen(info->mnt.root) + strlen(file) + 1 > SHFS_PATH_MAX) { + VERBOSE("Path too long!\n"); + return -1; + } + + DEBUG("Truncate %s%s %u\n", info->mnt.root, file, (unsigned)size); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_trunc(info, file, size)) < 0) { + VERBOSE("Couldn't do truncate!\n"); + shfs_unlock(info); + return res; + } + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + shfs_unlock(info); + + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + case REP_ENOENT: + return -ENOENT; + default: + return -EIO; + } + return 0; +} + +int +shfs_get_system(struct shfs_sb_info *info) +{ + char buf[SHFS_LINE_MAX]; + char *s, *r, *system, *release; + int i; + int res; + + DEBUG("Uname\n"); + + if (!shfs_lock(info)) + return -EINTR; + if ((res = do_uname(info)) < 0) { + VERBOSE("Couldn't get uname!\n"); + goto error; + } + + if ((res = shfs_pipe_readln(info, buf, SHFS_LINE_MAX)) < 0) { + VERBOSE("Error reading response!\n"); + goto error; + } + + DEBUG("system: %s\n", buf); + if ((r = strchr(buf, ' '))) + *(r++) = '\0'; + s = buf; + i = 0; + system = shfs_system[i].system; + release = shfs_system[i].release; + while (system || release) { + if (!info->mnt.generic_host && !strncmp(s, system, strlen(system))) { + if (!release || (!strncmp(r, release, strlen(release)))) + break; + } + i++; + system = shfs_system[i].system; + release = shfs_system[i].release; + } + + if (system) + printk(KERN_INFO "shfs: remote peer: %s (%s)\n", system, release ? release : "generic"); + else + printk(KERN_INFO "shfs: remote peer: generic\n"); + + shfs_pipe_readln(info, buf, SHFS_LINE_MAX); + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + res = -EPERM; + goto error; + default: + res = -EIO; + goto error; + } + + if ((res = do_init(info, i)) < 0) { + VERBOSE("Cannot send init!\n"); + goto error; + } + + if (shfs_pipe_readln(info, buf, SHFS_LINE_MAX) < 0) { + VERBOSE("Error reading response!\n"); + goto error; + } + shfs_unlock(info); + switch (reply(buf)) { + case REP_COMPLETE: + break; + case REP_EPERM: + return -EPERM; + default: + return -EIO; + } + return 0; +error: + shfs_unlock(info); + return res; +} + +int +shfs_notify_change(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = (struct shfs_sb_info*)sb->u.generic_sbp; + char file[SHFS_PATH_MAX]; + int res = 0; + + if (shfs_get_name(dentry, file) < 0) + return -ENAMETOOLONG; + + DEBUG(" \n"); + + if (attr->ia_valid & ATTR_MODE) { + if ((res = shfs_proc_chmod(info, file, attr->ia_mode)) < 0) + goto error; + } + if (attr->ia_valid & ATTR_UID) { + if ((res = shfs_proc_chown(info, file, attr->ia_uid)) < 0) + goto error; + } + if (attr->ia_valid & ATTR_GID) { + if ((res = shfs_proc_chgrp(info, file, attr->ia_gid)) < 0) + goto error; + } + if (attr->ia_valid & ATTR_SIZE) { + if ((res = shfs_proc_trunc(info, file, attr->ia_size)) < 0) + goto error; + if (!shfs_lock(info)) + return -EINTR; + inode->i_size = 0; + mark_inode_dirty(inode); + shfs_dcache_update_fattr(dentry, attr); + shfs_unlock(info); + return res; + } +error: + if (!shfs_lock(info)) + return -EINTR; + shfs_dcache_update_fattr(dentry, attr); + shfs_unlock(info); + return res; +} + + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/proto.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/proto.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/proto.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/proto.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,345 @@ +#include +#include + +#include "shfs.h" +#include "shfs_proc.h" +#include "shfs_proto.h" + +/* Generic file operations */ + +char *generic_lsdir = "s_lsdir () { \ +if TZ=GMT LC_ALL=POSIX ls -lani \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE;\ +else\ + if test -d \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +/* Some dd implementations do not like count=0 */ + +char *generic_read = "s_read () { \ +if test \"$3\" = 0; then\ + if test -r \"$s_ROOT$1\"; then\ + echo $s_PRELIM; echo $s_COMPLETE;\ + else\ + echo $s_EPERM; \ + fi \ +else\ + if x=`LC_ALL=POSIX dd if=\"$s_ROOT$1\" bs=$4 skip=$5 count=1 2>&1 >/dev/null`; then\ + if echo $s_PRELIM; [ `echo $x|cut -c1-3` = 0+0 ]; then\ + echo $s_COMPLETE;\ + elif dd if=\"$s_ROOT$1\" bs=$4 skip=$5 count=$6 conv=sync 2>/dev/null; then\ + echo $s_COMPLETE;\ + else\ + echo $s_ERROR;\ + fi; \ + else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi\ + fi \ +fi; }\n"; + +char *generic_write = "s_write () { \ +if test -w \"$s_ROOT$1\"; then\ + echo $s_PRELIM;\ + if test \"$3\" = 0; then\ + echo $s_COMPLETE;\ + else\ + if dd of=\"$s_ROOT$1\" bs=1 seek=$2 count=$3 conv=notrunc 2>/dev/null; then\ + echo $s_COMPLETE;\ + else\ + echo $s_ENOSPC; dd of=/dev/null bs=1 count=$3 2>/dev/null;\ + fi\ + fi \ +else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM; \ + else\ + echo $s_ENOENT;\ + fi; \ +fi; }\n"; + +char *generic_mkdir = "s_mkdir () { \ +if mkdir \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + echo $s_EPERM; \ +fi; }\n"; + +char *generic_rmdir = "s_rmdir () { \ +if test -d \"$s_ROOT$1\"; then\ + if rmdir \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE;\ + else\ + echo $s_EPERM;\ + fi \ +else\ + echo $_ENOENT; \ +fi; }\n"; + +char *generic_mv = "s_mv () { \ +if mv -f \"$s_ROOT$1\" \"$s_ROOT$2\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +char *generic_rm = "s_rm () { \ +if rm -f \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +char *generic_creat = "s_creat () { \ +if ( >\"$s_ROOT$1\"; chmod $2 \"$s_ROOT$1\" ) 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + echo $s_EPERM; \ +fi; }\n"; + +char *generic_ln = "s_ln () { \ +if ln -f \"$s_ROOT$1\" \"$s_ROOT$2\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + echo $s_EPERM; \ +fi; }\n"; + +char *generic_sln = "s_sln () { \ +if ln -s -f \"$1\" \"$s_ROOT$2\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + echo $s_EPERM; \ +fi; }\n"; + +char *generic_chmod = "s_chmod () { \ +if chmod $2 \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +char *generic_chown = "s_chown () { \ +if chown $2 \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +char *generic_chgrp = "s_chgrp () { \ +if chgrp $2 \"$s_ROOT$1\" 2>/dev/null; then\ + echo $s_COMPLETE; \ +else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +/* some dd implementations do not like count=0 */ + +char *generic_trunc = "s_trunc () { \ +if test \"$3\" = 0; then\ + if ( >\"$s_ROOT$1\" ) 2>/dev/null; then\ + echo $s_COMPLETE; \ + else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi\ + fi \ +else\ + if dd if=/dev/zero of=\"$s_ROOT$1\" bs=$2 seek=$3 count=0 2>/dev/null; then\ + echo $s_COMPLETE; \ + else\ + if test -f \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi\ + fi \ +fi; }\n"; + +/* Linux specific operations */ + +char *linux_read = "s_read () { \ +if x=`LC_ALL=POSIX dd if=\"$s_ROOT$1\" bs=1 skip=$2 count=1 2>&1 >/dev/null`; then\ + if echo $s_PRELIM; test `echo $x|cut -c1-3` = 0+0; then\ + echo $s_COMPLETE;\ + elif dd if=\"$s_ROOT$1\" bs=$4 skip=$5 count=$6 conv=sync 2>/dev/null; then\ + echo $s_COMPLETE;\ + else\ + echo $s_ERROR;\ + fi; \ +else\ + if test -e \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi \ +fi; }\n"; + +/* We should have head command (OSF1 has one too) */ + +char *linux_write = "s_write () { \ +if printf '' >\"$s_ROOT$1\"._shfs_ 2>/dev/null; then\ + echo $s_PRELIM;\ + if head -c $3 >\"$s_ROOT$1\"._shfs_ 2>/dev/null; then\ + if dd if=\"$s_ROOT$1\"._shfs_ of=\"$s_ROOT$1\" bs=$4 seek=$5 conv=notrunc 2>/dev/null; then\ + echo $s_COMPLETE;\ + else\ + if test -e \"$s_ROOT$1\"; then\ + echo $s_EPERM;\ + else\ + echo $s_ENOENT;\ + fi\ + fi;\ + else\ + echo $s_ENOSPC; dd of=/dev/null bs=1 count=$3 2>/dev/null;\ + fi;\ + rm -f \"$s_ROOT$1\"._shfs_ 2>/dev/null; \ +else\ + echo $s_EPERM; \ +fi; }\n"; + +/* more specific first! */ + +struct shfs_system_t shfs_system[] = { + { + "Linux", NULL, { + &generic_lsdir, + &linux_read, + &linux_write, + &generic_mkdir, + &generic_rmdir, + &generic_mv, + &generic_rm, + &generic_creat, + &generic_ln, + &generic_sln, + &generic_chmod, + &generic_chown, + &generic_chgrp, + &generic_trunc, + } + }, { + "OSF1", NULL, { + &generic_lsdir, + &generic_read, + &linux_write, + &generic_mkdir, + &generic_rmdir, + &generic_mv, + &generic_rm, + &generic_creat, + &generic_ln, + &generic_sln, + &generic_chmod, + &generic_chown, + &generic_chgrp, + &generic_trunc, + } + }, { + NULL, NULL, { + &generic_lsdir, + &generic_read, + &generic_write, + &generic_mkdir, + &generic_rmdir, + &generic_mv, + &generic_rm, + &generic_creat, + &generic_ln, + &generic_sln, + &generic_chmod, + &generic_chown, + &generic_chgrp, + &generic_trunc, + } + } +}; + +/* + +Protocol NOTES: + +* All operations should redirect stderr to /dev/null. +* You *MUST* quote strings with single quotes (expansion ' -> '\'' + is done in filenames). +* Read & write must work correctly when count == 0 (return zero bytes) + +*/ + +/* Machine independent operations */ + +int +do_uname(struct shfs_sb_info *info) +{ + return shfs_pipe_printf(info, "if LC_ALL=POSIX uname -s -r 2>/dev/null; then echo '### %d'; else echo '### %d'; fi\n", REP_COMPLETE, REP_ERROR); +} + +int +do_ping(struct shfs_sb_info *info, unsigned long seq) +{ + return shfs_pipe_printf(info, "\n\necho; echo '### %d'; echo %lu; echo '### %d'\n", REP_PRELIM, seq, REP_NOP); +} + +int +do_init(struct shfs_sb_info *info, int sys) +{ + int res, r; + char **s; + int i; + + res = shfs_pipe_printf(info,\ +"s_ROOT='%s';\n" +"s_PRELIM='### %d'; s_COMPLETE='### %d'; s_NOP='### %d';\n" +"s_CONTINUE='### %d'; s_TRANSIENT='### %d';\n" +"s_ERROR='### %d'; s_EPERM='### %d'; s_ENOSPC='### %d'; s_ENOENT='### %d';\n", +info->mnt.root,\ +REP_PRELIM, REP_COMPLETE, REP_NOP,\ +REP_CONTINUE, REP_TRANSIENT,\ +REP_ERROR, REP_EPERM, REP_ENOSPC, REP_ENOENT); + + if (res < 0) + return res; + + for (i = 0; i < SHFS_OPS; i++) { + s = shfs_system[sys].ops[i]; + r = shfs_pipe_printf(info, *s); + if (r < 0) + return r; + res += r; + } + + r = shfs_pipe_printf(info, "echo '### %d'\n", REP_COMPLETE); + if (r < 0) + return r; + + return res+r; +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs.h linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs.h --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs.h 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,63 @@ +#ifndef _SHFS_H_ +#define _SHFS_H_ + +#include + +#define SHFS_SUPER_MAGIC 0xD0D0 +#define SHFS_VERSION 0x01 + +#define SHFS_LINE_MAX 512 +#define SHFS_PATH_MAX 1024 + +#include "shfs_debug.h" +#include "shfs_dcache.h" +#include "shfs_fcache.h" + +struct shfs_mount_data { + int version; + int preserve_own; + int disable_fcache; + int generic_host; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_mode_t root_mode; + __kernel_mode_t fmask; + char root[SHFS_PATH_MAX]; + char mount_point[SHFS_PATH_MAX]; + struct file *pin; + struct file *pout; + struct shfs_system_t *system; + char *printf_buffer; + char *readln_buffer; + int readln_buffer_len; + int readonly; + int garbage; + int garbage_read; + int garbage_write; +}; + +struct shfs_sb_info { + struct shfs_mount_data mnt; +// struct super_block *sb; /* silly, needed by iunique */ + struct semaphore sem; + struct shfs_dir_cache dir_cache; + struct shfs_file_cache file_cache; +}; + +struct shfs_fattr { + unsigned long f_ino; + umode_t f_mode; + nlink_t f_nlink; + uid_t f_uid; + gid_t f_gid; + kdev_t f_rdev; + off_t f_size; + time_t f_atime; + time_t f_mtime; + time_t f_ctime; + unsigned long f_blksize; + unsigned long f_blocks; +}; + + +#endif /* _SHFS_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_dcache.h linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_dcache.h --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_dcache.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_dcache.h 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,60 @@ +#ifndef _SHFS_DCACHE_H_ +#define _SHFS_DCACHE_H_ + +#define SHFS_DCACHE_LEN 5 +#define SHFS_DCACHE_HASH 10 +#define SHFS_DCACHE_TTL 30 + +#include +#include + +extern kmem_cache_t *dir_hash_cache; +extern kmem_cache_t *dir_list_cache; +extern kmem_cache_t *dir_name_cache; + +struct shfs_dir_entry { + umode_t mode; + char *name; + unsigned long ino; + uid_t uid; + gid_t gid; + off_t size; + kdev_t rdev; + nlink_t nlink; + unsigned long blocksize; + unsigned long blocks; + time_t atime; + int changed; +}; + +struct shfs_dir_list_node { + struct shfs_dir_list_node *prev, *next; + struct shfs_dir_entry entry; +}; + +struct shfs_directory { + struct shfs_dir_list_node *head; + time_t time; + char *name; +}; + +struct shfs_dir_hash_node { + struct shfs_dir_hash_node *prev, *next; + struct shfs_directory directory; +}; + +struct shfs_dir_cache { + struct shfs_dir_hash_node *hash[SHFS_DCACHE_HASH]; + unsigned len[SHFS_DCACHE_HASH]; +}; + +struct shfs_sb_info; + +void shfs_dcache_init(struct shfs_sb_info*); +int shfs_dcache_empty(struct shfs_sb_info*); +int shfs_dcache_get(struct shfs_sb_info*, char*, struct shfs_directory**); +int shfs_dcache_revalidate(struct dentry *, struct shfs_sb_info*); +void shfs_dcache_invalidate(struct dentry*); +void shfs_dcache_update_fattr(struct dentry*, struct iattr*); + +#endif /* _SHFS_DCACHE_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_debug.h linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_debug.h --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_debug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_debug.h 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,62 @@ +#ifndef _SHFS_DEBUG_H_ +#define _SHFS_DEBUG_H_ + +#if DEBUG_LEVEL >= 1 +# define SHFS_VERBOSE +#endif +#if DEBUG_LEVEL >= 2 +# define SHFS_ALLOC_DEBUG +#endif +#if DEBUG_LEVEL >= 3 +# define SHFS_DEBUG +#endif + +#ifdef SHFS_DEBUG +#define DEBUG(x...) do { printk(KERN_DEBUG "shfs: %s ", __FUNCTION__); printk(KERN_DEBUG x); } while (0) +#else +#define DEBUG(x...) ; +#endif + +#ifdef SHFS_VERBOSE +#define VERBOSE(x...) do { printk(KERN_NOTICE "shfs: %s ", __FUNCTION__); printk(KERN_NOTICE x); } while (0) +#else +#define VERBOSE(x...) ; +#endif + +#ifdef SHFS_ALLOC_DEBUG + +#include + +#ifdef SHFS_DEBUG_HERE +unsigned long alloc; + +void *__kmem_malloc_debug(char *s, kmem_cache_t *cache, int flags) +{ + void *x = kmem_cache_alloc(cache, flags); + alloc += (unsigned long) x; + DEBUG("alloc (%s): %p\n", s, x); + return x; +} + +void __kmem_free_debug(char *s, kmem_cache_t *cache, void *p) +{ + DEBUG("free (%s): %p\n", s, p); + alloc -= (unsigned long) p; + kmem_cache_free(cache, p); +} +#else +extern unsigned long alloc; + +void *__kmem_malloc_debug(char *s, kmem_cache_t *cache, int flags); +void __kmem_free_debug(char *s, kmem_cache_t *cache, void *p); +#endif + +#define KMEM_ALLOC(s, cache, flags) __kmem_malloc_debug(s, cache, flags); +#define KMEM_FREE(s, cache, p) __kmem_free_debug(s, cache, p); + +#else +#define KMEM_ALLOC(s, cache, flags) kmem_cache_alloc(cache, flags) +#define KMEM_FREE(s, cache, p) kmem_cache_free(cache, p) +#endif + +#endif /* _SHFS_DEBUG_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_fcache.h linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_fcache.h --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_fcache.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_fcache.h 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,46 @@ +#ifndef _SHFS_FCACHE_H_ +#define _SHFS_FCACHE_H_ + +#define SHFS_FCACHE_HASH 10 +#define SHFS_FCACHE_PAGES 16 /* should be 2^x */ +#define SHFS_FCACHE_SIZE ((unsigned)(SHFS_FCACHE_PAGES * PAGE_SIZE)) + +#include +#include + +extern kmem_cache_t *file_hash_cache; + +#define SHFS_FCACHE_READ 0 +#define SHFS_FCACHE_WRITE 1 + +struct shfs_file { + int type; + unsigned long ino; + unsigned used; + unsigned name_hash; + unsigned offset; + unsigned count; + char *data; +}; + +struct shfs_file_hash_node { + struct shfs_file_hash_node *prev, *next; + struct shfs_file buf; +}; + +struct shfs_file_cache { + struct shfs_file_hash_node *hash[SHFS_FCACHE_HASH]; + unsigned len[SHFS_FCACHE_HASH]; +}; + +struct shfs_sb_info; + +void shfs_fcache_init(struct shfs_sb_info*); +int shfs_fcache_empty(struct shfs_sb_info*); +int shfs_fcache_add(struct file*); +int shfs_fcache_remove(struct file*); +int shfs_fcache_sync(struct file*); +int shfs_fcache_read(struct dentry*, unsigned, unsigned, char*); +int shfs_fcache_write(struct dentry*, unsigned, unsigned, char*); + +#endif /* _SHFS_FCACHE_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_proc.h linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_proc.h --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_proc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_proc.h 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,39 @@ +#ifndef _SHFS_PROC_H_ +#define _SHFS_PROC_H_ + +#include "shfs_dcache.h" +#include "shfs_fcache.h" +#include "shfs.h" + +#define PRINTF_BUFFER_SIZE (SHFS_PATH_MAX * 10) +#define READLN_BUFFER_SIZE (SHFS_LINE_MAX * 10) + +void shfs_init_root_dirent(struct shfs_sb_info*, struct shfs_fattr*); +int shfs_parse_options(struct shfs_sb_info*, void*); +int shfs_pipe_printf(struct shfs_sb_info*, const char*, ...); +int shfs_pipe_readln(struct shfs_sb_info*, char*, int); +int shfs_loaddir(struct shfs_sb_info*, char*, struct shfs_directory*); +int shfs_get_name(struct dentry*, char*); +inline int shfs_lock(struct shfs_sb_info*); +inline void shfs_locku(struct shfs_sb_info*); +inline void shfs_unlock(struct shfs_sb_info*); +int shfs_remove_sigpipe(int result); +int shfs_get_attr(struct dentry*, struct shfs_fattr*, struct shfs_sb_info*); +struct inode* shfs_iget(struct super_block*, struct shfs_fattr*); +int shfs_proc_read(struct dentry*, unsigned, unsigned, char*); +int shfs_proc_write(struct dentry*, unsigned, unsigned, char*); +int shfs_proc_mkdir(struct shfs_sb_info*, char*); +int shfs_proc_rmdir(struct shfs_sb_info*, char*); +int shfs_proc_rename(struct shfs_sb_info*, char*, char*); +int shfs_proc_unlink(struct shfs_sb_info*, char*); +int shfs_proc_create(struct shfs_sb_info*, char*, int); +int shfs_proc_link(struct shfs_sb_info*, char*, char*); +int shfs_proc_symlink(struct shfs_sb_info*, const char*, const char*); +int shfs_proc_chmod(struct shfs_sb_info*, char*, umode_t); +int shfs_proc_chown(struct shfs_sb_info*, char*, uid_t user); +int shfs_proc_chgrp(struct shfs_sb_info*, char*, gid_t group); +int shfs_get_system(struct shfs_sb_info*); + +int shfs_notify_change(struct dentry*, struct iattr*); + +#endif /* _SHFS_PROC_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_proto.h linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_proto.h --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/shfs_proto.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/shfs_proto.h 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,154 @@ +#ifndef _SHFS_PROTO_H_ +#define _SHFS_PROTO_H_ + +#include +#include + +/* response code */ +#define REP_PRELIM 100 +#define REP_COMPLETE 200 +#define REP_NOP 201 +#define REP_CONTINUE 300 +#define REP_TRANSIENT 400 +#define REP_ERROR 500 +#define REP_EPERM 501 +#define REP_ENOSPC 502 +#define REP_ENOENT 503 + +/* directory list fields (ls -lani) */ +#define DIR_COLS 10 +#define DIR_INODE 0 +#define DIR_PERM 1 +#define DIR_NLINK 2 +#define DIR_UID 3 +#define DIR_GID 4 +#define DIR_SIZE 5 +#define DIR_MONTH 6 +#define DIR_DAY 7 +#define DIR_YEAR 8 +#define DIR_NAME 9 + +#define SHFS_OPS 14 + +struct shfs_system_t { + char *system; + char *release; + char **ops[SHFS_OPS]; +}; + +extern struct shfs_system_t shfs_system[]; + +/* Machine independent operations */ + +extern int do_uname(struct shfs_sb_info *); +extern int do_ping(struct shfs_sb_info *, unsigned long); +extern int do_init(struct shfs_sb_info *, int); + +/* Machine dependent ops */ + +static inline int +do_lsdir(struct shfs_sb_info *info, char *dir) +{ + return shfs_pipe_printf(info, "s_lsdir '%s'\n", dir); +} + +static inline int +do_read(struct shfs_sb_info *info, char *path, unsigned offset, unsigned count) +{ + unsigned bs = 1, offset2 = offset, count2 = count; + + /* read speedup if possible */ + if (count && !(offset % count)) { + bs = count; + offset2 = offset / count; + count2 = 1; + } + return shfs_pipe_printf(info, "s_read '%s' %u %u %u %u %u\n", path, offset, count, bs, offset2, count2); +} + +static inline int +do_write(struct shfs_sb_info *info, char *path, unsigned offset, unsigned count) +{ + unsigned offset2 = offset, bs = 1; + + if (offset % SHFS_FCACHE_SIZE == 0) { + offset2 = offset / SHFS_FCACHE_SIZE; + bs = SHFS_FCACHE_SIZE; + } + return shfs_pipe_printf(info, "s_write '%s' %u %u %u %u\n", path, offset, count, bs, offset2); +} + +static inline int +do_mkdir(struct shfs_sb_info *info, char *path) +{ + return shfs_pipe_printf(info, "s_mkdir '%s'\n", path); +} + +static inline int +do_rmdir(struct shfs_sb_info *info, char *path) +{ + return shfs_pipe_printf(info, "s_rmdir '%s'\n", path); +} + +static inline int +do_mv(struct shfs_sb_info *info, char *old, char *new) +{ + return shfs_pipe_printf(info, "s_mv '%s' '%s'\n", old, new); +} + +static inline int +do_rm(struct shfs_sb_info *info, char *path) +{ + return shfs_pipe_printf(info, "s_rm '%s'\n", path); +} + +static inline int +do_creat(struct shfs_sb_info *info, char *path, umode_t mode) +{ + return shfs_pipe_printf(info, "s_creat '%s' %o\n", path, mode); +} + +static inline int +do_ln(struct shfs_sb_info *info, char *old, char *new) +{ + return shfs_pipe_printf(info, "s_ln '%s' '%s'\n", old, new); +} + +static inline int +do_sln(struct shfs_sb_info *info, const char *old, const char *new) +{ + return shfs_pipe_printf(info, "s_sln '%s' '%s'\n", old, new); +} + +static inline int +do_chmod(struct shfs_sb_info *info, char *path, umode_t mode) +{ + return shfs_pipe_printf(info, "s_chmod '%s' %o\n", path, mode); +} + +static inline int +do_chown(struct shfs_sb_info *info, char *path, uid_t uid) +{ + return shfs_pipe_printf(info, "s_chown '%s' %u\n", path, uid); +} + +static inline int +do_chgrp(struct shfs_sb_info *info, char *path, gid_t gid) +{ + return shfs_pipe_printf(info, "s_chgrp '%s' %u\n", path, gid); +} + +static inline int +do_trunc(struct shfs_sb_info *info, char *path, loff_t size) +{ + unsigned seek = 1; + + /* dd doesn't like bs=0 */ + if (size == 0) { + seek = 0; + size = 1; + } + return shfs_pipe_printf(info, "s_trunc '%s' %u %u\n", path, (unsigned) size, seek); +} + +#endif /* _SHFS_PROTO_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/shfs/symlink.c linux-2.4.20-wolk4.7-fullkernel/fs/shfs/symlink.c --- linux-2.4.20-wolk4.6-fullkernel/fs/shfs/symlink.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/fs/shfs/symlink.c 2003-08-17 21:31:42.000000000 +0200 @@ -0,0 +1,116 @@ +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include + +#include "shfs.h" +#include "shfs_proc.h" + +static int shfs_readlink(struct dentry*, char*, int); +static int shfs_follow_link(struct dentry*, struct nameidata*); + +struct inode_operations shfs_symlink_inode_operations = { + readlink: shfs_readlink, + follow_link: shfs_follow_link, + setattr: shfs_notify_change, +}; + +static int +shfs_readlink(struct dentry *dentry, char *buffer, int bufflen) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = sb->u.generic_sbp; + + char buf[SHFS_PATH_MAX]; + struct shfs_directory *dir; + struct shfs_dir_list_node *file; + char *real_name; + int res; + + if (shfs_get_name(dentry->d_parent, buf) < 0) + return -ENAMETOOLONG; + DEBUG("%s\n", buf); + +// lock_kernel(); + if (!shfs_lock(info)) + return -EINTR; + res = shfs_dcache_get(info, buf, &dir); + if (res < 0) { + VERBOSE(" shfs_cache_get failed!\n"); + goto error; + } + + for (file = dir->head; file != NULL; file = file->next) + if (strcmp(file->entry.name, dentry->d_name.name) == 0) + break; + if (!file) { + VERBOSE(" file not found in cache!!?!\n"); + res = -1; + goto error; + } + + real_name = file->entry.name + strlen(file->entry.name) + 4; + shfs_unlock(info); +// unlock_kernel(); + + return vfs_readlink(dentry, buffer, bufflen, real_name); + +error: + shfs_unlock(info); +// unlock_kernel(); + return shfs_remove_sigpipe(res); +} + +static int +shfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct shfs_sb_info *info = sb->u.generic_sbp; + + char buf[SHFS_PATH_MAX]; + struct shfs_directory *dir; + struct shfs_dir_list_node *file; + char *real_name; + int res; + + if (shfs_get_name(dentry->d_parent, buf) < 0) + return -ENAMETOOLONG; + DEBUG(" %s/%s\n", buf, dentry->d_name.name); + +// lock_kernel(); + if (!shfs_lock(info)) + return -EINTR; + res = shfs_dcache_get(info, buf, &dir); + + if (res < 0) { + VERBOSE(" shfs_dcache_get failed!\n"); + goto error; + } + + for (file = dir->head; file != NULL; file = file->next) + if (strcmp(file->entry.name, dentry->d_name.name) == 0) + break; + if (!file) { + VERBOSE(" file not found in cache!!?!\n"); + res = -1; + goto error; + } + + real_name = file->entry.name + strlen(file->entry.name) + 4; + DEBUG("real name: %s\n", real_name); + shfs_unlock(info); +// unlock_kernel(); + return vfs_follow_link(nd, real_name); + +error: + shfs_unlock(info); +// unlock_kernel(); + return shfs_remove_sigpipe(res); +} + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/stat.c linux-2.4.20-wolk4.7-fullkernel/fs/stat.c --- linux-2.4.20-wolk4.6-fullkernel/fs/stat.c 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/stat.c 2003-08-17 21:31:44.000000000 +0200 @@ -43,6 +43,8 @@ static int cp_old_stat(struct inode * in struct __old_kernel_stat tmp; loff_t i_size; + memset(&tmp, 0, sizeof(struct __old_kernel_stat)); + if (warncount > 0) { warncount--; printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xattr.c linux-2.4.20-wolk4.7-fullkernel/fs/xattr.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xattr.c 2003-05-03 01:54:00.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xattr.c 2002-11-29 00:53:15.000000000 +0100 @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -16,7 +17,7 @@ /* * Extended attribute memory allocation wrappers, originally * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros. - * Values larger than a page are uncommon - extended attributes + * The vmalloc use here is very uncommon - extended attributes * are supposed to be small chunks of metadata, and it is quite * unusual to have very many extended attributes, so lists tend * to be quite short as well. The 64K upper limit is derived @@ -33,8 +34,10 @@ xattr_alloc(size_t size, size_t limit) if (!size) /* size request, no buffer is needed */ return NULL; - - ptr = kmalloc((unsigned long) size, GFP_KERNEL); + else if (size <= PAGE_SIZE) + ptr = kmalloc((unsigned long) size, GFP_KERNEL); + else + ptr = vmalloc((unsigned long) size); if (!ptr) return ERR_PTR(-ENOMEM); return ptr; @@ -43,8 +46,12 @@ xattr_alloc(size_t size, size_t limit) static void xattr_free(void *ptr, size_t size) { - if (size) /* for a size request, no buffer was needed */ + if (!size) /* size request, no buffer was needed */ + return; + else if (size <= PAGE_SIZE) kfree(ptr); + else + vfree(ptr); } /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_attr.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_attr.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_attr.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_attr.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,6 +30,9 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_bulkattr.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_bulkattr.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_bulkattr.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_bulkattr.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,6 +30,9 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_config.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_config.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_config.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_config.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,6 +30,9 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" int diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_dmattr.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_dmattr.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_dmattr.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_dmattr.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_event.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_event.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_event.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_event.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" /* The "rights" portion of the DMAPI spec is not currently implemented. A diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_handle.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_handle.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_handle.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_handle.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_hole.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_hole.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_hole.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_hole.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_io.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_io.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_io.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_io.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_mountinfo.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_mountinfo.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_mountinfo.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_mountinfo.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" #ifdef linux diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_private.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_private.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_private.h 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_private.h 2003-08-17 21:26:18.000000000 +0200 @@ -32,9 +32,6 @@ #ifndef _DMAPI_PRIVATE_H #define _DMAPI_PRIVATE_H -#include "xfs.h" -#include "dmapi.h" -#include "dmapi_kern.h" #ifdef CONFIG_PROC_FS #define DMAPI_PROCFS "fs/xfs_dmapi_v2" /* DMAPI device in /proc. */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_region.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_region.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_region.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_region.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_register.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_register.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_register.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_register.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,11 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" +#include "xfs_sb.h" #include #include #include diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_right.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_right.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_right.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_right.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,9 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_session.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_session.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_session.c 2003-05-03 01:54:00.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_session.c 2003-08-17 21:26:18.000000000 +0200 @@ -32,6 +32,9 @@ #include #include +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" dm_session_t *dm_sessions = NULL; /* head of session list */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_sysent.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_sysent.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_sysent.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_sysent.c 2003-08-17 21:26:18.000000000 +0200 @@ -46,6 +46,9 @@ #include +#include "xfs.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" kmem_cache_t *dm_fsreg_cachep = NULL; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_xfs.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_xfs.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/dmapi/dmapi_xfs.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/dmapi/dmapi_xfs.c 2003-08-17 21:26:19.000000000 +0200 @@ -34,6 +34,39 @@ #include #include #include + + +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_clnt.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_attr.h" +#include "xfs_inode_item.h" +#include "dmapi.h" +#include "dmapi_kern.h" #include "dmapi_private.h" #define MAXNAMLEN MAXNAMELEN @@ -967,7 +1000,12 @@ xfs_dm_get_allocinfo_rvp( if (copy_from_user( &startoff, offp, sizeof(startoff))) return(EFAULT); - if (startoff > XFS_MAX_FILE_OFFSET) + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + mp = ip->i_mount; + + if (startoff > XFS_MAXIOFFSET(mp)) return(EINVAL); if (nelem == 0) { @@ -976,18 +1014,13 @@ xfs_dm_get_allocinfo_rvp( return(E2BIG); } - XFS_BHV_LOOKUP(vp, xbdp); - - ip = XFS_BHVTOI(xbdp); - 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; + fsb_length = XFS_B_TO_FSB(mp, XFS_MAXIOFFSET(mp)) - fsb_offset; elem = 0; while (fsb_length && elem < nelem) { @@ -2749,7 +2782,7 @@ xfs_dm_mount( { struct bhv_desc *rootbdp; struct vnode *rootvp; - struct vfs *vfsp; + struct vfs *vfsp = bhvtovfs(bhv); int error = 0; PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error); @@ -2757,16 +2790,18 @@ xfs_dm_mount( return error; if (args->flags & XFSMNT_DMAPI) { - vfsp = bhvtovfs(bhv); VFS_ROOT(vfsp, &rootvp, error); if (!error) { - vfsp->vfs_flag |= VFS_DMI; rootbdp = vn_bhv_lookup_unlocked( VN_BHV_HEAD(rootvp), &xfs_vnodeops); VN_RELE(rootvp); - error = dm_send_mount_event(vfsp, DM_RIGHT_NULL, NULL, + if (rootbdp != NULL) { + vfsp->vfs_flag |= VFS_DMI; + error = dm_send_mount_event(vfsp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, rootbdp, DM_RIGHT_NULL, args->mtpt, args->fsname); + } } } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_aops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_aops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_aops.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_aops.c 2003-08-17 21:26:20.000000000 +0200 @@ -30,7 +30,27 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_trans.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_rw.h" #include STATIC void convert_page(struct inode *, struct page *, @@ -73,6 +93,7 @@ linvfs_unwritten_conv( XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); XFS_BUF_UNDATAIO(bp); + iput(LINVFS_GET_IP(vp)); pagebuf_iodone(bp, 0, 0); } @@ -355,7 +376,16 @@ map_unwritten( pb = pagebuf_lookup(mp->pbm_target, mp->pbm_offset, mp->pbm_bsize, 0); if (!pb) - return -ENOMEM; + return -EAGAIN; + + /* Take a reference to the inode to prevent it from + * being reclaimed while we have outstanding unwritten + * extent IO on it. + */ + if ((igrab(inode)) != inode) { + pagebuf_free(pb); + return -EAGAIN; + } /* Set the count to 1 initially, this will stop an I/O * completion callout which happens before we have started @@ -413,8 +443,7 @@ map_unwritten( if (page) { nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); - convert_page(inode, page, - mp, pb, 1, all_bh); + convert_page(inode, page, mp, pb, 1, all_bh); } } } @@ -578,11 +607,11 @@ cluster_write( STATIC int page_state_convert( + struct inode *inode, struct page *page, int startio, int unmapped) /* also implies page uptodate */ { - struct inode *inode = page->mapping->host; struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; page_buf_bmap_t *mp, map; unsigned long p_offset = 0, end_index; @@ -939,7 +968,6 @@ count_page_state( * the page, we have to check the process flags first, if we * are already in a transaction or disk I/O during allocations * is off, we need to fail the writepage and redirty the page. - * We also need to set PF_NOIO ourselves. */ STATIC int @@ -950,6 +978,7 @@ linvfs_writepage( int need_trans; int delalloc, unmapped, unwritten; struct inode *inode = page->mapping->host; + xfs_pflags_t pflags; /* * We need a transaction if: @@ -976,7 +1005,7 @@ linvfs_writepage( * as is. */ - if ((current->flags & (PF_FSTRANS|PF_NOIO)) && need_trans) + if ((PFLAGS_TEST_FSTRANS() || PFLAGS_TEST_NOIO()) && need_trans) goto out_fail; /* @@ -991,10 +1020,10 @@ linvfs_writepage( * to real space and flush out to disk. */ if (need_trans) - current->flags |= PF_NOIO; - error = page_state_convert(page, 1, unmapped); + PFLAGS_SET_NOIO(&pflags); + error = page_state_convert(inode, page, 1, unmapped); if (need_trans) - current->flags &= ~PF_NOIO; + PFLAGS_RESTORE(&pflags); if (error == -EAGAIN) goto out_fail; @@ -1035,6 +1064,7 @@ linvfs_release_page( struct page *page, int gfp_mask) { + struct inode *inode = page->mapping->host; int delalloc, unmapped, unwritten; count_page_state(page, &delalloc, &unmapped, &unwritten); @@ -1050,7 +1080,7 @@ linvfs_release_page( * Never need to allocate space here - we will always * come back to writepage in that case. */ - return (page_state_convert(page, 0, 0) == 0) ? 1 : 0; + return (page_state_convert(inode, page, 0, 0) == 0) ? 1 : 0; } STATIC int @@ -1075,12 +1105,11 @@ linvfs_prepare_write( STATIC int linvfs_direct_IO( int rw, - struct file *file, + struct inode *inode, struct kiobuf *iobuf, - sector_t blocknr, + unsigned long blocknr, int blocksize) { - struct inode *inode; struct page **maplist; size_t page_offset; page_buf_t *pb; @@ -1092,12 +1121,11 @@ linvfs_direct_IO( size_t map_size, size; vnode_t *vp = LINVFS_GET_VP(inode); - inode = file->f_dentry->d_inode; - maplist = iobuf->maplist; - total = length = iobuf->length; offset = blocknr; offset <<= inode->i_blkbits; + + maplist = iobuf->maplist; page_offset = iobuf->offset; map_flags = (rw ? BMAP_WRITE : BMAP_READ) | BMAP_DIRECT; @@ -1160,6 +1188,8 @@ linvfs_direct_IO( XFS_BUF_DATAIO(pb); if (map.pbm_flags & PBMF_UNWRITTEN) { + if ((igrab(inode)) != inode) + BUG(); XFS_BUF_SET_FSPRIVATE(pb, vp); XFS_BUF_SET_IODONE_FUNC(pb, linvfs_unwritten_conv); } @@ -1168,6 +1198,8 @@ linvfs_direct_IO( pagebuf_rele(pb); if (error) { + if (map.pbm_flags & PBMF_UNWRITTEN) + iput(inode); if (error > 0) error = -error; break; @@ -1211,7 +1243,7 @@ struct address_space_operations linvfs_a .commit_write = generic_commit_write, #ifndef HAVE_SECTOR_T .bmap = (bmap_proc *)linvfs_bmap, - .direct_IO = (direct_IO_proc *)linvfs_direct_IO, + .direct_IO = linvfs_direct_IO, #else .bmap = linvfs_bmap, .direct_IO = linvfs_direct_IO, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_behavior.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_behavior.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_behavior.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_behavior.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ * */ -#include +#include "xfs.h" /* * Source file used to associate/disassociate behaviors with virtualized diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_file.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_file.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_file.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_file.c 2003-08-17 21:26:20.000000000 +0200 @@ -30,7 +30,29 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_trans.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_rw.h" +#include + #include #include /* for PROT_WRITE */ @@ -251,6 +273,7 @@ linvfs_file_mmap( } vma->vm_ops = &linvfs_file_vm_ops; + vma->vm_flags &= ~VM_IO; VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); return 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_fs_subr.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_fs_subr.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_fs_subr.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_fs_subr.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" /* * Stub for no-op vnode operations that return error status. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_globals.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_globals.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_globals.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_globals.c 2003-08-17 21:26:19.000000000 +0200 @@ -35,7 +35,12 @@ * somewhere else in IRIX. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_bmap_btree.h" +#include "xfs_bit.h" +#include "xfs_rw.h" /* * System memory size - used to scale certain data structures in XFS. @@ -46,7 +51,19 @@ unsigned long xfs_physmem; * Tunable XFS parameters. xfs_params is required even when CONFIG_SYSCTL=n, * other XFS code uses these values. */ -xfs_param_t xfs_params = { 128, 32, 0, 1, 0, 0, 0, 3 }; + +xfs_param_t xfs_params = { + /* MIN DFLT MAX */ + .refcache_size = { 0, 128, XFS_REFCACHE_SIZE_MAX }, + .refcache_purge = { 0, 32, XFS_REFCACHE_SIZE_MAX }, + .restrict_chown = { 0, 1, 1 }, + .sgid_inherit = { 0, 0, 1 }, + .symlink_mode = { 0, 0, 1 }, + .panic_mask = { 0, 0, 127 }, + .error_level = { 0, 3, 11 }, + .sync_interval = { HZ, 30*HZ, 60*HZ }, + .stats_clear = { 0, 0, 1 }, +}; /* * Global system credential structure. @@ -60,3 +77,83 @@ EXPORT_SYMBOL(xfs_bmbt_get_all); #if ARCH_CONVERT != ARCH_NOCONVERT EXPORT_SYMBOL(xfs_bmbt_disk_get_all); #endif + +#if defined(CONFIG_XFS_DEBUG) +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_imap.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dir2_data.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_buf_item.h" +#include "xfs_rw.h" +#include "xfs_error.h" +#include "xfs_utils.h" +#include "xfs_dir2_trace.h" +#include "xfs_quota.h" +#include "xfs_mac.h" +#include "xfs_acl.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_dir2_sf.h" +#include "xfs_dir2_trace.h" +#include "xfs_attr.h" +#include "xfs_attr_leaf.h" + +extern ktrace_t *xfs_alloc_trace_buf; + +EXPORT_SYMBOL(xfs_fsb_to_agbno); +EXPORT_SYMBOL(xfs_dir2_data_unused_tag_p_arch); +EXPORT_SYMBOL(xfs_attr_leaf_name_remote); +EXPORT_SYMBOL(xfs_lic_slot); +EXPORT_SYMBOL(xfs_dir2_sf_firstentry); +EXPORT_SYMBOL(xfs_ino_to_agno); +EXPORT_SYMBOL(xfs_dir2_sf_get_inumber_arch); +EXPORT_SYMBOL(xfs_ifork_q); +EXPORT_SYMBOL(xfs_dir2_data_entry_tag_p); +EXPORT_SYMBOL(xfs_dir2_sf_inumberp); +EXPORT_SYMBOL(xfs_dir2_data_entsize); +EXPORT_SYMBOL(xfs_lic_isfree); +EXPORT_SYMBOL(xfs_attr_leaf_name_local); +EXPORT_SYMBOL(xfs_bmap_broot_ptr_addr); +EXPORT_SYMBOL(xfs_dir_sf_get_dirino_arch); +EXPORT_SYMBOL(xfs_alloc_trace_buf); +EXPORT_SYMBOL(xfs_ino_to_agbno); +EXPORT_SYMBOL(xfs_fsb_to_agno); +EXPORT_SYMBOL(xfs_dir2_leaf_bests_p_arch); +EXPORT_SYMBOL(xfs_dir2_sf_get_offset_arch); +EXPORT_SYMBOL(startblockval); +EXPORT_SYMBOL(xfs_attr_sf_nextentry); +EXPORT_SYMBOL(xfs_bmap_broot_key_addr); +EXPORT_SYMBOL(xfs_dir2_block_leaf_p_arch); +EXPORT_SYMBOL(xfs_mtovfs); +EXPORT_SYMBOL(xfs_dir_leaf_namestruct); +EXPORT_SYMBOL(xfs_ino_to_offset); +EXPORT_SYMBOL(xfs_itobhv); +EXPORT_SYMBOL(xfs_ifork_ptr); +EXPORT_SYMBOL(isnullstartblock); +EXPORT_SYMBOL(xfs_lic_are_all_free); +EXPORT_SYMBOL(xfs_dir_sf_nextentry); +EXPORT_SYMBOL(xfs_dir2_sf_nextentry); +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_ioctl.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_ioctl.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_ioctl.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_ioctl.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,9 +30,43 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include -#include +#include "xfs.h" + +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_utils.h" +#include "xfs_dfrag.h" +#include "xfs_fsops.h" + #include #include diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_iomap.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_iomap.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_iomap.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_iomap.c 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,43 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_trans_space.h" +#include "xfs_utils.h" #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ << mp->m_writeio_log) @@ -136,8 +172,11 @@ xfs_iomap( BUG(); } + ASSERT(offset <= mp->m_maxioffset); + if ((xfs_fsize_t)offset + count > mp->m_maxioffset) + count = mp->m_maxioffset - offset; + end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); offset_fsb = XFS_B_TO_FSBT(mp, offset); - end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); error = XFS_BMAPI(mp, NULL, io, offset_fsb, (xfs_filblks_t)(end_fsb - offset_fsb) , diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_iops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_iops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_iops.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_iops.c 2003-08-17 21:26:20.000000000 +0200 @@ -30,7 +30,42 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_utils.h" + #include @@ -122,10 +157,10 @@ linvfs_mknod( if (S_ISCHR(mode) || S_ISBLK(mode)) ip->i_rdev = to_kdev_t(rdev); - validate_fields(dir); + else if (S_ISDIR(mode)) + validate_fields(ip); d_instantiate(dentry, ip); - mark_inode_dirty_sync(ip); - mark_inode_dirty_sync(dir); + validate_fields(dir); } if (!error && have_default_acl) { @@ -213,7 +248,6 @@ linvfs_link( VN_HOLD(vp); validate_fields(ip); d_instantiate(dentry, ip); - mark_inode_dirty_sync(ip); } return -error; } @@ -234,8 +268,6 @@ linvfs_unlink( if (!error) { validate_fields(dir); /* For size only */ validate_fields(inode); - mark_inode_dirty_sync(inode); - mark_inode_dirty_sync(dir); } return -error; @@ -269,8 +301,6 @@ linvfs_symlink( d_instantiate(dentry, ip); validate_fields(dir); validate_fields(ip); /* size needs update */ - mark_inode_dirty_sync(ip); - mark_inode_dirty_sync(dir); } return -error; } @@ -288,8 +318,6 @@ linvfs_rmdir( if (!error) { validate_fields(inode); validate_fields(dir); - mark_inode_dirty_sync(inode); - mark_inode_dirty_sync(dir); } return -error; } @@ -319,7 +347,6 @@ linvfs_rename( validate_fields(odir); if (ndir != odir) validate_fields(ndir); - mark_inode_dirty(ndir); return 0; } @@ -490,7 +517,6 @@ linvfs_setattr( if (!error) { vn_revalidate(vp); - mark_inode_dirty_sync(inode); } return error; } @@ -561,7 +587,7 @@ STATIC int linvfs_setxattr( struct dentry *dentry, const char *name, - void *data, + const void *data, size_t size, int flags) { @@ -644,8 +670,10 @@ linvfs_getxattr( } /* Convert Linux syscall to XFS internal ATTR flags */ - if (!size) + if (!size) { xflags |= ATTR_KERNOVAL; + data = NULL; + } if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, xfs_namespaces[ROOT_NAMES].namelen) == 0) { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_linux.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_linux.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_linux.h 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_linux.h 2003-08-17 21:26:19.000000000 +0200 @@ -45,12 +45,15 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #ifndef HAVE_SECTOR_T typedef long sector_t; /* offset- or number- of disk blocks */ @@ -98,11 +101,15 @@ static inline void set_buffer_unwritten_ bh->b_end_io = linvfs_unwritten_done; } -#define restricted_chown xfs_params.restrict_chown -#define irix_sgid_inherit xfs_params.sgid_inherit -#define irix_symlink_mode xfs_params.symlink_mode -#define xfs_panic_mask xfs_params.panic_mask -#define xfs_error_level xfs_params.error_level +#define xfs_refcache_size xfs_params.refcache_size.val +#define xfs_refcache_purge_count xfs_params.refcache_purge.val +#define restricted_chown xfs_params.restrict_chown.val +#define irix_sgid_inherit xfs_params.sgid_inherit.val +#define irix_symlink_mode xfs_params.symlink_mode.val +#define xfs_panic_mask xfs_params.panic_mask.val +#define xfs_error_level xfs_params.error_level.val +#define xfs_syncd_interval xfs_params.sync_interval.val +#define xfs_stats_clear xfs_params.stats_clear.val #define NBPP PAGE_SIZE #define DPPSHFT (PAGE_SHIFT - 9) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_lrw.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_lrw.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_lrw.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_lrw.c 2003-08-17 21:26:19.000000000 +0200 @@ -34,7 +34,44 @@ * */ -#include +#include "xfs.h" + +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_inode_item.h" +#include "xfs_buf_item.h" +#include "xfs_utils.h" + #include @@ -137,7 +174,7 @@ xfs_read( } - n = XFS_MAX_FILE_OFFSET - *offset; + n = XFS_MAXIOFFSET(mp) - *offset; if ((n <= 0) || (size == 0)) return 0; @@ -344,7 +381,8 @@ xfs_zero_eof( } ASSERT(nimaps > 0); - if (imap.br_startblock == HOLESTARTBLOCK) { + if (imap.br_state == XFS_EXT_UNWRITTEN || + imap.br_startblock == HOLESTARTBLOCK) { /* * This loop handles initializing pages that were * partially initialized by the code below this @@ -417,7 +455,7 @@ xfs_write( ssize_t ret; int error = 0; xfs_fsize_t isize, new_size; - xfs_fsize_t n, limit = XFS_MAX_FILE_OFFSET; + xfs_fsize_t n, limit; xfs_iocore_t *io; vnode_t *vp; int iolock; @@ -463,6 +501,7 @@ xfs_write( xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); isize = xip->i_d.di_size; + limit = XFS_MAXIOFFSET(mp); if (file->f_flags & O_APPEND) *offset = isize; @@ -772,29 +811,23 @@ xfsbdstrat( return (xfs_bioerror_relse(bp)); } - -void -XFS_bflush(xfs_buftarg_t *target) -{ - pagebuf_delwri_flush(target, PBDF_WAIT, NULL); -} - /* - * If the underlying (log or data) device is readonly, there are some + * If the underlying (data/log/rt) device is readonly, there are some * operations that cannot proceed. */ int -xfs_dev_is_read_only(xfs_mount_t *mp, char *message) +xfs_dev_is_read_only( + xfs_mount_t *mp, + char *message) { - if (is_read_only(mp->m_ddev_targp->pbr_kdev) || - is_read_only(mp->m_logdev_targp->pbr_kdev) || - (mp->m_rtdev_targp && is_read_only(mp->m_rtdev_targp->pbr_kdev))) { + if (xfs_readonly_buftarg(mp->m_ddev_targp) || + xfs_readonly_buftarg(mp->m_logdev_targp) || + (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp))) { cmn_err(CE_NOTE, "XFS: %s required on read-only device.", message); cmn_err(CE_NOTE, "XFS: write access unavailable, cannot proceed."); return EROFS; } - return 0; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_stats.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_stats.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_stats.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_stats.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" #include struct xfsstats xfsstats; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_super.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_super.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_super.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_super.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,17 +30,52 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_clnt.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_utils.h" +#include "xfs_version.h" + #include #include -#include "xfs_version.h" STATIC struct quotactl_ops linvfs_qops; STATIC struct super_operations linvfs_sops; STATIC kmem_cache_t * linvfs_inode_cachep; STATIC struct xfs_mount_args * -args_allocate( +xfs_args_allocate( struct super_block *sb) { struct xfs_mount_args *args; @@ -59,6 +94,40 @@ args_allocate( return args; } +__uint64_t +xfs_max_file_offset( + unsigned int blockshift) +{ + unsigned int pagefactor = 1; + unsigned int bitshift = BITS_PER_LONG - 1; + + /* Figure out maximum filesize, on Linux this can depend on + * the filesystem blocksize (on 32 bit platforms). + * __block_prepare_write does this in an [unsigned] long... + * page->index << (PAGE_CACHE_SHIFT - bbits) + * So, for page sized blocks (4K on 32 bit platforms), + * this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is + * (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) + * but for smaller blocksizes it is less (bbits = log2 bsize). + * Note1: get_block_t takes a long (implicit cast from above) + * Note2: The Large Block Device (LBD and HAVE_SECTOR_T) patch + * can optionally convert the [unsigned] long from above into + * an [unsigned] long long. + */ + +#if BITS_PER_LONG == 32 +# if defined(HAVE_SECTOR_T) + ASSERT(sizeof(sector_t) == 8); + pagefactor = PAGE_CACHE_SIZE; + bitshift = BITS_PER_LONG; +# else + pagefactor = PAGE_CACHE_SIZE >> (PAGE_CACHE_SHIFT - blockshift); +# endif +#endif + + return (((__uint64_t)pagefactor) << bitshift) - 1; +} + STATIC __inline__ void xfs_set_inodeops( struct inode *inode) @@ -198,13 +267,27 @@ xfs_blkdev_put( } void -xfs_free_buftarg( +xfs_flush_buftarg( xfs_buftarg_t *btp) { pagebuf_delwri_flush(btp, PBDF_WAIT, NULL); +} + +void +xfs_free_buftarg( + xfs_buftarg_t *btp) +{ + xfs_flush_buftarg(btp); kmem_free(btp, sizeof(*btp)); } +int +xfs_readonly_buftarg( + xfs_buftarg_t *btp) +{ + return is_read_only(btp->pbr_kdev); +} + void xfs_relse_buftarg( xfs_buftarg_t *btp) @@ -265,20 +348,14 @@ xfs_alloc_buftarg( return btp; } -STATIC __inline__ unsigned int gfp_mask(void) -{ - /* If we're not in a transaction, FS activity is ok */ - if (current->flags & PF_FSTRANS) return GFP_NOFS; - return GFP_KERNEL; -} - STATIC struct inode * linvfs_alloc_inode( struct super_block *sb) { vnode_t *vp; - vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep, gfp_mask()); + vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep, + kmem_flags_convert(KM_SLEEP)); if (!vp) return NULL; return LINVFS_GET_IP(vp); @@ -291,6 +368,9 @@ linvfs_destroy_inode( kmem_cache_free(linvfs_inode_cachep, LINVFS_GET_VP(inode)); } +#define VNODE_SIZE \ + (sizeof(vnode_t) - sizeof(struct inode) + offsetof(struct inode, u)) + STATIC void init_once( void *data, @@ -300,15 +380,18 @@ init_once( vnode_t *vp = (vnode_t *)data; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) - inode_init_once(LINVFS_GET_IP(vp)); + SLAB_CTOR_CONSTRUCTOR) { + struct inode *inode = LINVFS_GET_IP(vp); + memset(vp, 0, VNODE_SIZE); + _inode_init_once(inode); + } } STATIC int init_inodecache( void ) { linvfs_inode_cachep = kmem_cache_create("linvfs_icache", - sizeof(vnode_t), 0, SLAB_HWCACHE_ALIGN, + VNODE_SIZE, 0, SLAB_HWCACHE_ALIGN, init_once, NULL); if (linvfs_inode_cachep == NULL) @@ -324,9 +407,10 @@ destroy_inodecache( void ) } /* - * We do not actually write the inode here, just mark the - * super block dirty so that sync_supers calls us and - * forces the flush. + * Attempt to flush the inode, this will actually fail + * if the inode is pinned, but we dirty the inode again + * at the point when it is unpinned after a log write, + * since this is when the inode itself becomes flushable. */ STATIC void linvfs_write_inode( @@ -341,8 +425,6 @@ linvfs_write_inode( if (sync) flags |= FLUSH_SYNC; VOP_IFLUSH(vp, flags, error); - if (error == EAGAIN) - inode->i_sb->s_dirt = 1; } } @@ -362,6 +444,68 @@ linvfs_clear_inode( } } + +#define SYNCD_FLAGS (SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR|SYNC_REFCACHE) + +STATIC int +syncd(void *arg) +{ + vfs_t *vfsp = (vfs_t *) arg; + int error; + + daemonize(); + reparent_to_init(); + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + sprintf(current->comm, "xfssyncd"); + + vfsp->vfs_sync_task = current; + wmb(); + wake_up(&vfsp->vfs_wait_sync_task); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(xfs_syncd_interval); + if (vfsp->vfs_flag & VFS_UMOUNT) + break; + if (vfsp->vfs_flag & VFS_RDONLY) + continue; + VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error); + } + + vfsp->vfs_sync_task = NULL; + wmb(); + wake_up(&vfsp->vfs_wait_sync_task); + + return 0; +} + +STATIC int +linvfs_start_syncd(vfs_t *vfsp) +{ + int pid; + + pid = kernel_thread(syncd, (void *) vfsp, + CLONE_VM | CLONE_FS | CLONE_FILES); + if (pid < 0) + return pid; + wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task); + return 0; +} + +STATIC void +linvfs_stop_syncd(vfs_t *vfsp) +{ + vfsp->vfs_flag |= VFS_UMOUNT; + wmb(); + + wake_up_process(vfsp->vfs_sync_task); + wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task); +} + STATIC void linvfs_put_super( struct super_block *sb) @@ -369,8 +513,9 @@ linvfs_put_super( vfs_t *vfsp = LINVFS_GET_VFS(sb); int error; + linvfs_stop_syncd(vfsp); VFS_SYNC(vfsp, SYNC_ATTR|SYNC_DELWRI, NULL, error); - if (error == 0) + if (!error) VFS_UNMOUNT(vfsp, 0, NULL, error); if (error) { printk("XFS unmount got error %d\n", error); @@ -388,10 +533,23 @@ linvfs_write_super( vfs_t *vfsp = LINVFS_GET_VFS(sb); int error; - sb->s_dirt = 0; - if (sb->s_flags & MS_RDONLY) + if (sb->s_flags & MS_RDONLY) { + sb->s_dirt = 0; /* paranoia */ return; - VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error); + } + /* Push the log and superblock a little */ + VFS_SYNC(vfsp, SYNC_FSDATA, NULL, error); + sb->s_dirt = 0; +} + +STATIC void +linvfs_sync_super( + struct super_block *sb) +{ + vfs_t *vfsp = LINVFS_GET_VFS(sb); + int error; + + VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_WAIT, NULL, error); } STATIC int @@ -403,7 +561,7 @@ linvfs_statfs( int error; VFS_STATVFS(vfsp, statp, NULL, error); - return error; + return -error; } STATIC int @@ -413,29 +571,24 @@ linvfs_remount( char *options) { vfs_t *vfsp = LINVFS_GET_VFS(sb); - struct xfs_mount_args *args = args_allocate(sb); + struct xfs_mount_args *args = xfs_args_allocate(sb); int error; VFS_PARSEARGS(vfsp, options, args, 1, error); - if (error) - goto out; - - VFS_MNTUPDATE(vfsp, flags, args, error); - -out: + if (!error) + VFS_MNTUPDATE(vfsp, flags, args, error); kmem_free(args, sizeof(*args)); - return error; + return -error; } STATIC void linvfs_freeze_fs( struct super_block *sb) { - vfs_t *vfsp; + vfs_t *vfsp = LINVFS_GET_VFS(sb); vnode_t *vp; int error; - vfsp = LINVFS_GET_VFS(sb); if (sb->s_flags & MS_RDONLY) return; VFS_ROOT(vfsp, &vp, error); @@ -447,11 +600,10 @@ STATIC void linvfs_unfreeze_fs( struct super_block *sb) { - vfs_t *vfsp; + vfs_t *vfsp = LINVFS_GET_VFS(sb); 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); VN_RELE(vp); @@ -625,7 +777,7 @@ linvfs_read_super( { vnode_t *rootvp; struct vfs *vfsp = vfs_allocate(); - struct xfs_mount_args *args = args_allocate(sb); + struct xfs_mount_args *args = xfs_args_allocate(sb); struct statfs statvfs; int error; @@ -642,7 +794,6 @@ linvfs_read_super( } sb_min_blocksize(sb, BBSIZE); - sb->s_maxbytes = XFS_MAX_FILE_OFFSET; sb->s_qcop = &linvfs_qops; sb->s_op = &linvfs_sops; @@ -657,9 +808,10 @@ linvfs_read_super( goto fail_unmount; sb->s_dirt = 1; - sb->s_magic = XFS_SB_MAGIC; + sb->s_magic = statvfs.f_type; sb->s_blocksize = statvfs.f_bsize; sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1; + sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); set_posix_acl_flag(sb); VFS_ROOT(vfsp, &rootvp, error); @@ -671,7 +823,8 @@ linvfs_read_super( goto fail_vnrele; if (is_bad_inode(sb->s_root->d_inode)) goto fail_vnrele; - + if (linvfs_start_syncd(vfsp)) + goto fail_vnrele; vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address); kmem_free(args, sizeof(*args)); @@ -702,6 +855,7 @@ STATIC struct super_operations linvfs_so .clear_inode = linvfs_clear_inode, .put_super = linvfs_put_super, .write_super = linvfs_write_super, + .sync_fs = linvfs_sync_super, .write_super_lockfs = linvfs_freeze_fs, .unlockfs = linvfs_unfreeze_fs, .statfs = linvfs_statfs, @@ -782,6 +936,6 @@ exit_xfs_fs( void ) module_init(init_xfs_fs); module_exit(exit_xfs_fs); -MODULE_AUTHOR("SGI "); +MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); MODULE_LICENSE("GPL"); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_super.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_super.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_super.h 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_super.h 2003-08-17 21:26:19.000000000 +0200 @@ -66,6 +66,12 @@ # define XFS_REALTIME_STRING #endif +#if XFS_BIG_FILESYSTEMS +# define XFS_BIGFS_STRING "big filesystems, " +#else +# define XFS_BIGFS_STRING +#endif + #ifdef CONFIG_XFS_VNODE_TRACING # define XFS_VNTRACE_STRING "VN-trace, " #else @@ -80,6 +86,7 @@ #define XFS_BUILD_OPTIONS XFS_ACL_STRING \ XFS_REALTIME_STRING \ + XFS_BIGFS_STRING \ XFS_VNTRACE_STRING \ XFS_DBG_STRING /* DBG must be last */ @@ -92,6 +99,8 @@ struct xfs_mount; struct pb_target; struct block_device; +extern __uint64_t xfs_max_file_offset(unsigned int); + extern struct inode *xfs_get_inode(bhv_desc_t *, xfs_ino_t, int); extern void xfs_initialize_vnode(bhv_desc_t *, vnode_t *, bhv_desc_t *, int); @@ -102,7 +111,8 @@ extern void xfs_blkdev_put(struct block_ extern struct pb_target *xfs_alloc_buftarg(struct block_device *); extern void xfs_relse_buftarg(struct pb_target *); extern void xfs_free_buftarg(struct pb_target *); - +extern void xfs_flush_buftarg(struct pb_target *); +extern int xfs_readonly_buftarg(struct pb_target *); extern void xfs_setsize_buftarg(struct pb_target *, unsigned int, unsigned int); extern unsigned int xfs_getsize_buftarg(struct pb_target *); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_sysctl.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_sysctl.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_sysctl.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_sysctl.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,16 +30,12 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_rw.h" #include #include -STATIC ulong xfs_min[XFS_PARAM] = { \ - 0, 0, 0, 0, 0, 0, 0, 0 }; -STATIC ulong xfs_max[XFS_PARAM] = { \ - XFS_REFCACHE_SIZE_MAX, XFS_REFCACHE_SIZE_MAX, 1, 1, 1, 1, 127, 11 }; - static struct ctl_table_header *xfs_table_header; @@ -63,13 +59,14 @@ xfs_refcache_resize_proc_handler( if (!ret && write && xfs_refcache_new_size != xfs_refcache_old_size) { xfs_refcache_resize(xfs_refcache_new_size); /* Don't purge more than size of the cache */ - if (xfs_refcache_new_size < xfs_params.refcache_purge) - xfs_params.refcache_purge = xfs_refcache_new_size; + if (xfs_refcache_new_size < xfs_refcache_purge_count) + xfs_refcache_purge_count = xfs_refcache_new_size; } return ret; } +#ifdef CONFIG_PROC_FS STATIC int xfs_stats_clear_proc_handler( ctl_table *ctl, @@ -89,44 +86,62 @@ xfs_stats_clear_proc_handler( vn_active = xfsstats.vn_active; memset(&xfsstats, 0, sizeof(xfsstats)); xfsstats.vn_active = vn_active; - xfs_params.stats_clear = 0; + xfs_stats_clear = 0; } return ret; } +#endif /* CONFIG_PROC_FS */ STATIC ctl_table xfs_table[] = { - {XFS_REFCACHE_SIZE, "refcache_size", &xfs_params.refcache_size, + {XFS_REFCACHE_SIZE, "refcache_size", &xfs_params.refcache_size.val, sizeof(ulong), 0644, NULL, &xfs_refcache_resize_proc_handler, - &sysctl_intvec, NULL, &xfs_min[0], &xfs_max[0]}, + &sysctl_intvec, NULL, + &xfs_params.refcache_size.min, &xfs_params.refcache_size.max}, - {XFS_REFCACHE_PURGE, "refcache_purge", &xfs_params.refcache_purge, + /* Note, the max here is different, it is the current refcache size */ + {XFS_REFCACHE_PURGE, "refcache_purge", &xfs_params.refcache_purge.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[1], &xfs_params.refcache_size}, + &sysctl_intvec, NULL, + &xfs_params.refcache_purge.min, &xfs_params.refcache_size.val}, - {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear, - sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler, - &sysctl_intvec, NULL, &xfs_min[2], &xfs_max[2]}, + {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown.val, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, + &xfs_params.restrict_chown.min, &xfs_params.restrict_chown.max}, - {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown, + {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[3], &xfs_max[3]}, + &sysctl_intvec, NULL, + &xfs_params.sgid_inherit.min, &xfs_params.sgid_inherit.max}, - {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit, + {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[4], &xfs_max[4]}, + &sysctl_intvec, NULL, + &xfs_params.symlink_mode.min, &xfs_params.symlink_mode.max}, - {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode, + {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[5], &xfs_max[5]}, + &sysctl_intvec, NULL, + &xfs_params.panic_mask.min, &xfs_params.panic_mask.max}, - {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask, + {XFS_ERRLEVEL, "error_level", &xfs_params.error_level.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[6], &xfs_max[6]}, + &sysctl_intvec, NULL, + &xfs_params.error_level.min, &xfs_params.error_level.max}, - {XFS_ERRLEVEL, "error_level", &xfs_params.error_level, + {XFS_SYNC_INTERVAL, "sync_interval", &xfs_params.sync_interval.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[7], &xfs_max[7]}, + &sysctl_intvec, NULL, + &xfs_params.sync_interval.min, &xfs_params.sync_interval.max}, + + /* please keep this the last entry */ +#ifdef CONFIG_PROC_FS + {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, + sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler, + &sysctl_intvec, NULL, + &xfs_params.stats_clear.min, &xfs_params.stats_clear.max}, +#endif /* CONFIG_PROC_FS */ {0} }; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_sysctl.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_sysctl.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_sysctl.h 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_sysctl.h 2003-08-17 21:26:19.000000000 +0200 @@ -39,18 +39,24 @@ * Tunable xfs parameters */ -#define XFS_PARAM (sizeof(struct xfs_param) / sizeof(ulong)) +typedef struct xfs_sysctl_val { + ulong min; + ulong val; + ulong max; +} xfs_sysctl_val_t; typedef struct xfs_param { - ulong refcache_size; /* Size of NFS reference cache. */ - ulong refcache_purge; /* # of entries to purge each time. */ - ulong stats_clear; /* Reset all XFS statistics to zero. */ - ulong restrict_chown; /* Root/non-root can give away files. */ - ulong sgid_inherit; /* Inherit ISGID bit if process' GID is */ - /* not a member of the parent dir GID. */ - ulong symlink_mode; /* Symlink creat mode affected by umask. */ - ulong panic_mask; /* bitmask to specify panics on errors. */ - ulong error_level; /* Degree of reporting for internal probs*/ + xfs_sysctl_val_t refcache_size; /* Size of NFS reference cache. */ + xfs_sysctl_val_t refcache_purge;/* # of entries to purge each time. */ + xfs_sysctl_val_t restrict_chown;/* Root/non-root can give away files.*/ + xfs_sysctl_val_t sgid_inherit; /* Inherit ISGID bit if process' GID + * is not a member of the parent dir + * GID */ + xfs_sysctl_val_t symlink_mode; /* Link creat mode affected by umask */ + xfs_sysctl_val_t panic_mask; /* bitmask to cause panic on errors. */ + xfs_sysctl_val_t error_level; /* Degree of reporting for problems */ + xfs_sysctl_val_t sync_interval; /* time between sync calls */ + xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */ } xfs_param_t; /* @@ -71,12 +77,13 @@ typedef struct xfs_param { enum { XFS_REFCACHE_SIZE = 1, XFS_REFCACHE_PURGE = 2, - XFS_STATS_CLEAR = 3, - XFS_RESTRICT_CHOWN = 4, - XFS_SGID_INHERIT = 5, - XFS_SYMLINK_MODE = 6, - XFS_PANIC_MASK = 7, - XFS_ERRLEVEL = 8, + XFS_RESTRICT_CHOWN = 3, + XFS_SGID_INHERIT = 4, + XFS_SYMLINK_MODE = 5, + XFS_PANIC_MASK = 6, + XFS_ERRLEVEL = 7, + XFS_SYNC_INTERVAL = 8, + XFS_STATS_CLEAR = 9, }; extern xfs_param_t xfs_params; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_version.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_version.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_version.h 2003-05-13 12:16:59.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_version.h 2003-08-17 21:26:23.000000000 +0200 @@ -39,6 +39,6 @@ #ifndef __XFS_VERSION_H__ #define __XFS_VERSION_H__ -#define XFS_VERSION_STRING "XFS v1.2 - CVS as of 2003-04-28" +#define XFS_VERSION_STRING "SGI XFS 1.3.0pre5 - Tuned for WOLK," #endif /* __XFS_VERSION_H__ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vfs.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vfs.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vfs.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vfs.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,22 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_macros.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_clnt.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_imap.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_quota.h" int vfs_mount( @@ -236,6 +251,7 @@ vfs_allocate( void ) vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP); bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); + init_waitqueue_head(&vfsp->vfs_wait_sync_task); return vfsp; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vfs.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vfs.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vfs.h 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vfs.h 2003-08-17 21:26:19.000000000 +0200 @@ -48,6 +48,8 @@ typedef struct vfs { 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; /* Linux superblock structure */ + struct task_struct *vfs_sync_task; + wait_queue_head_t vfs_wait_sync_task; } vfs_t; #define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */ @@ -78,14 +80,17 @@ typedef enum { #define VFS_RDONLY 0x0001 /* read-only vfs */ #define VFS_GRPID 0x0002 /* group-ID assigned from directory */ #define VFS_DMI 0x0004 /* filesystem has the DMI enabled */ -#define VFS_END 0x0004 /* max flag */ +#define VFS_UMOUNT 0x0008 /* unmount in progress */ +#define VFS_END 0x0008 /* max flag */ #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_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ +#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ +#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ #define IGET_NOALLOC 0x0001 /* vfs_get_inode may return NULL */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vnode.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vnode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vnode.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vnode.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" uint64_t vn_generation; /* vnode generation number */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vnode.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vnode.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/linux/xfs_vnode.h 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/linux/xfs_vnode.h 2003-08-17 21:26:18.000000000 +0200 @@ -564,8 +564,7 @@ static __inline__ void vn_flagclr(struct (LINVFS_GET_IP(vp)->i_mapping->i_mmap_shared != NULL)) #define VN_CACHED(vp) (LINVFS_GET_IP(vp)->i_mapping->nrpages) #define VN_DIRTY(vp) (!list_empty(&(LINVFS_GET_IP(vp)->i_dirty_data_buffers))) -#define VMODIFY(vp) { VN_FLAGSET(vp, VMODIFIED); \ - mark_inode_dirty(LINVFS_GET_IP(vp)); } +#define VMODIFY(vp) VN_FLAGSET(vp, VMODIFIED) #define VUNMODIFY(vp) VN_FLAGCLR(vp, VMODIFIED) /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/pagebuf/page_buf.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/pagebuf/page_buf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/pagebuf/page_buf.c 2003-05-03 01:54:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/pagebuf/page_buf.c 2003-08-17 21:26:20.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -64,6 +64,7 @@ #define NBBY 8 #define BBSHIFT 9 +#define BBMASK ((1 << BBSHIFT) - 1) #define BN_ALIGN_MASK ((1 << (PAGE_CACHE_SHIFT - BBSHIFT)) - 1) #ifndef GFP_READAHEAD @@ -104,11 +105,11 @@ */ #ifdef PAGEBUF_TRACE -static spinlock_t pb_trace_lock = SPIN_LOCK_UNLOCKED; +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)) +#define CIRC_INC(i) (((i) + 1) & (PB_TRACE_BUFSIZE - 1)) void pb_trace_func( @@ -120,7 +121,7 @@ pb_trace_func( int j; unsigned long flags; - if (!pb_params.p_un.debug) return; + if (!pb_params.debug.val) return; if (ra == NULL) ra = (void *)__builtin_return_address(0); @@ -176,10 +177,13 @@ STATIC void pagebuf_delwri_queue(page_bu * /proc/sys/vm/pagebuf */ -unsigned long pagebuf_min[P_PARAM] = { HZ/2, 1*HZ, 0, 0 }; -unsigned long pagebuf_max[P_PARAM] = { HZ*30, HZ*300, 1, 1 }; - -pagebuf_param_t pb_params = {{ HZ, 15 * HZ, 0, 0 }}; +pagebuf_param_t pb_params = { + /* MIN DFLT MAX */ + .flush_interval = { HZ/2, HZ, 30*HZ }, + .age_buffer = { 1*HZ, 15*HZ, 300*HZ }, + .stats_clear = { 0, 0, 1 }, + .debug = { 0, 0, 1 }, +}; /* * Pagebuf statistics variables @@ -228,7 +232,7 @@ _bhash( * dev_t is 16 bits, loff_t is always 64 bits */ base ^= dev; - for (bit = hval = 0; base != 0 && bit < sizeof(base) * 8; bit += NBITS) { + for (bit = hval = 0; base && bit < sizeof(base) * 8; bit += NBITS) { hval ^= (int)base & (NHASH-1); base >>= NBITS; } @@ -236,18 +240,18 @@ _bhash( } /* - * Mapping of multi-page buffers into contingous virtual space + * Mapping of multi-page buffers into contiguous virtual space */ STATIC void *pagebuf_mapout_locked(page_buf_t *); -STATIC spinlock_t as_lock = SPIN_LOCK_UNLOCKED; typedef struct a_list { - void *vm_addr; + void *vm_addr; struct a_list *next; } a_list_t; -STATIC a_list_t *as_free_head; -STATIC int as_list_len; +STATIC a_list_t *as_free_head; +STATIC int as_list_len; +STATIC spinlock_t as_lock = SPIN_LOCK_UNLOCKED; /* @@ -929,7 +933,7 @@ pagebuf_lookup( { page_buf_t *pb; - flags |= _PBF_PRIVATE_BH; + flags |= _PBF_PRIVATE_BH | _PBF_LOCKABLE; pb = pagebuf_allocate(flags); if (pb) { _pagebuf_initialize(pb, target, ioff, isize, flags); @@ -1501,27 +1505,29 @@ _pagebuf_page_io( cache_ok = !((pb->pb_flags & PBF_FORCEIO) || (rw == WRITE)); public_bh = multi_ok = 1; + sector = 1 << sector_shift; if (!page_has_buffers(page)) { if (!locking) { lock_page(page); if (!page_has_buffers(page)) create_empty_buffers(page, - pbr->pbr_kdev, - 1 << sector_shift); + pbr->pbr_kdev, sector); unlock_page(page); } else { - create_empty_buffers(page, pbr->pbr_kdev, - 1 << sector_shift); + create_empty_buffers(page, + pbr->pbr_kdev, sector); } } + i = sector >> BBSHIFT; + bn -= (pg_offset >> BBSHIFT); + /* Find buffer_heads belonging to just this pagebuf */ bh = head = page_buffers(page); do { if (buffer_uptodate(bh) && cache_ok) continue; - blk_length = i << sector_shift; if (blk_length < pg_offset) continue; if (blk_length >= pg_offset + pg_length) @@ -1529,10 +1535,13 @@ _pagebuf_page_io( lock_buffer(bh); get_bh(bh); - bh->b_size = 1 << sector_shift; - bh->b_blocknr = bn + (i - (pg_offset >> sector_shift)); + bh->b_size = sector; + bh->b_blocknr = bn; bufferlist[cnt++] = bh; - } while (i++, (bh = bh->b_this_page) != head); + + } while ((bn += i), + (blk_length += sector), + (bh = bh->b_this_page) != head); goto request; } @@ -1579,14 +1588,15 @@ _pagebuf_page_io( } multi_ok = (blk_length != 1); + i = sector >> BBSHIFT; - for (; blk_length > 0; blk_length--, pg_offset += sector) { + for (; blk_length > 0; bn += i, blk_length--, pg_offset += sector) { bh = kmem_cache_alloc(bh_cachep, SLAB_NOFS); if (!bh) bh = _pagebuf_get_prealloc_bh(); memset(bh, 0, sizeof(*bh)); + bh->b_blocknr = bn; bh->b_size = sector; - bh->b_blocknr = bn++; bh->b_dev = pbr->pbr_kdev; set_bit(BH_Lock, &bh->b_state); set_bh_page(bh, page, pg_offset); @@ -1649,13 +1659,13 @@ _pagebuf_page_apply( if ((pbr->pbr_bsize == PAGE_CACHE_SIZE) && (pb->pb_buffer_length < PAGE_CACHE_SIZE) && (pb->pb_flags & PBF_READ) && pb->pb_locked) { - bn -= (pb->pb_offset >> pbr->pbr_sshift); + bn -= (pb->pb_offset >> BBSHIFT); pg_offset = 0; pg_length = PAGE_CACHE_SIZE; } else { pb_offset = offset - pb->pb_file_offset; if (pb_offset) { - bn += (pb_offset + pbr->pbr_smask) >> pbr->pbr_sshift; + bn += (pb_offset + BBMASK) >> BBSHIFT; } } @@ -1877,7 +1887,7 @@ pagebuf_delwri_queue( } list_add_tail(&pb->pb_list, &pbd_delwrite_queue); - pb->pb_flushtime = jiffies + pb_params.p_un.age_buffer; + pb->pb_flushtime = jiffies + pb_params.age_buffer.val; spin_unlock(&pbd_delwrite_lock); if (unlock && (pb->pb_flags & _PBF_LOCKABLE)) { @@ -2032,7 +2042,7 @@ pagebuf_daemon( do { if (pbd_active == 1) { mod_timer(&pb_daemon_timer, - jiffies + pb_params.p_un.flush_interval); + jiffies + pb_params.flush_interval.val); interruptible_sleep_on(&pbd_waitq); } @@ -2100,11 +2110,11 @@ pagebuf_delwri_flush( int pincount = 0; int flush_cnt = 0; + pagebuf_runall_queues(pagebuf_dataiodone_tq); + spin_lock(&pbd_delwrite_lock); INIT_LIST_HEAD(&tmp); - pagebuf_runall_queues(pagebuf_dataiodone_tq); - list_for_each_safe(curr, next, &pbd_delwrite_queue) { pb = list_entry(curr, page_buf_t, pb_list); @@ -2260,7 +2270,7 @@ pb_stats_clear_handler( if (!ret && write && *valp) { printk("XFS Clearing pbstats\n"); memset(&pbstats, 0, sizeof(pbstats)); - pb_params.p_un.stats_clear = 0; + pb_params.stats_clear.val = 0; } return ret; @@ -2269,22 +2279,26 @@ pb_stats_clear_handler( STATIC struct ctl_table_header *pagebuf_table_header; STATIC ctl_table pagebuf_table[] = { - {PB_FLUSH_INT, "flush_int", &pb_params.data[0], + {PB_FLUSH_INT, "flush_int", &pb_params.flush_interval.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, - &sysctl_intvec, NULL, &pagebuf_min[0], &pagebuf_max[0]}, + &sysctl_intvec, NULL, + &pb_params.flush_interval.min, &pb_params.flush_interval.max}, - {PB_FLUSH_AGE, "flush_age", &pb_params.data[1], + {PB_FLUSH_AGE, "flush_age", &pb_params.age_buffer.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, - &sysctl_intvec, NULL, &pagebuf_min[1], &pagebuf_max[1]}, + &sysctl_intvec, NULL, + &pb_params.age_buffer.min, &pb_params.age_buffer.max}, - {PB_STATS_CLEAR, "stats_clear", &pb_params.data[2], + {PB_STATS_CLEAR, "stats_clear", &pb_params.stats_clear.val, sizeof(ulong), 0644, NULL, &pb_stats_clear_handler, - &sysctl_intvec, NULL, &pagebuf_min[2], &pagebuf_max[2]}, + &sysctl_intvec, NULL, + &pb_params.stats_clear.min, &pb_params.stats_clear.max}, #ifdef PAGEBUF_TRACE - {PB_DEBUG, "debug", &pb_params.data[3], + {PB_DEBUG, "debug", &pb_params.debug.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]}, + &sysctl_intvec, NULL, + &pb_params.debug.min, &pb_params.debug.max}, #endif {0} }; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/pagebuf/page_buf_internal.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/pagebuf/page_buf_internal.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/pagebuf/page_buf_internal.h 2003-05-13 12:37:02.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/pagebuf/page_buf_internal.h 2003-08-17 21:26:19.000000000 +0200 @@ -85,18 +85,19 @@ struct pagebuf_trace_buf { * Tunable pagebuf parameters */ -#define P_PARAM 4 +typedef struct pb_sysctl_val { + ulong min; + ulong val; + ulong max; +} pb_sysctl_val_t; -typedef union pagebuf_param { - struct { - ulong flush_interval; /* interval between runs of the +typedef struct pagebuf_param { + pb_sysctl_val_t flush_interval; /* interval between runs of the * delwri flush daemon. */ - ulong age_buffer; /* time for buffer to age before + pb_sysctl_val_t age_buffer; /* time for buffer to age before * we flush it. */ - ulong debug; /* debug tracing on or off */ - ulong stats_clear; /* clear the pagebuf stats */ - } p_un; - ulong data[P_PARAM]; + pb_sysctl_val_t stats_clear; /* clear the pagebuf stats */ + pb_sysctl_val_t debug; /* debug tracing on or off */ } pagebuf_param_t; enum { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_dquot.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_dquot.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_dquot.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_dquot.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,43 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_trans_space.h" +#include "xfs_trans_priv.h" + #include "xfs_qm.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_dquot_item.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_dquot_item.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_dquot_item.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_dquot_item.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,42 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_trans_priv.h" + #include "xfs_qm.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,7 +30,44 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_clnt.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_trans_space.h" +#include "xfs_utils.h" + #include "xfs_qm.h" /* @@ -1572,7 +1609,7 @@ xfs_qm_dqiterate( map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP); lblkno = 0; - maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp)); do { nmaps = XFS_DQITER_MAP_SIZE; /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm_bhv.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm_bhv.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm_bhv.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm_bhv.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,41 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_clnt.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" + #include "xfs_qm.h" #define MNTOPT_QUOTA "quota" /* disk quotas (user) */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm_stats.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm_stats.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm_stats.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm_stats.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,40 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" + #include "xfs_qm.h" struct xqmstats xqmstats; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm_syscalls.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm_syscalls.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_qm_syscalls.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_qm_syscalls.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,41 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_utils.h" + #include "xfs_qm.h" #ifdef DEBUG diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_trans_dquot.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_trans_dquot.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/quota/xfs_trans_dquot.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/quota/xfs_trans_dquot.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,42 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc.h" +#include "xfs_dmapi.h" +#include "xfs_quota.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_acl.h" +#include "xfs_cap.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_buf_item.h" +#include "xfs_trans_priv.h" + #include "xfs_qm.h" STATIC void xfs_trans_alloc_dqinfo(xfs_trans_t *); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/kmem.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/kmem.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/kmem.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/kmem.c 2003-08-17 21:26:19.000000000 +0200 @@ -41,25 +41,6 @@ #define DEF_PRIORITY (6) #define MAX_SLAB_SIZE 0x10000 -static __inline unsigned int flag_convert(int flags) -{ -#if DEBUG - if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS))) { - printk(KERN_WARNING - "XFS: memory allocation with wrong flags (%x)\n", flags); - BUG(); - } -#endif - - if (flags & KM_NOSLEEP) - return GFP_ATOMIC; - /* If we're in a transaction, FS activity is not ok */ - else if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) - return GFP_NOFS; - else - return GFP_KERNEL; -} - #define MAX_SHAKE 8 static kmem_shake_func_t shake_list[MAX_SHAKE]; @@ -113,18 +94,20 @@ static __inline__ void kmem_shake(void) void * kmem_alloc(size_t size, int flags) { - int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + int lflags = kmem_flags_convert(flags); + int nosleep = flags & KM_NOSLEEP; void *rval; repeat: if (MAX_SLAB_SIZE < size) { /* Avoid doing filesystem sensitive stuff to get this */ - rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + rval = __vmalloc(size, lflags, PAGE_KERNEL); } else { - rval = kmalloc(size, flag_convert(flags)); + rval = kmalloc(size, lflags); } - if (rval || (flags & KM_NOSLEEP)) + if (rval || nosleep) return rval; /* @@ -137,8 +120,8 @@ repeat: goto repeat; } - rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); - if (!rval && (flags & KM_SLEEP)) + rval = __vmalloc(size, lflags, PAGE_KERNEL); + if (!rval && !nosleep) panic("kmem_alloc: NULL memory on KM_SLEEP request!"); return rval; @@ -197,7 +180,7 @@ kmem_zone_alloc(kmem_zone_t *zone, int f void *ptr = NULL; repeat: - ptr = kmem_cache_alloc(zone, flag_convert(flags)); + ptr = kmem_cache_alloc(zone, kmem_flags_convert(flags)); if (ptr || (flags & KM_NOSLEEP)) return ptr; @@ -225,7 +208,7 @@ kmem_zone_zalloc(kmem_zone_t *zone, int void *ptr = NULL; repeat: - ptr = kmem_cache_alloc(zone, flag_convert(flags)); + ptr = kmem_cache_alloc(zone, kmem_flags_convert(flags)); if (ptr) { memset(ptr, 0, kmem_cache_size(zone)); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/kmem.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/kmem.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/kmem.h 2003-05-13 12:37:24.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/kmem.h 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -44,6 +44,50 @@ #define kmem_zone kmem_cache_s #define kmem_zone_t kmem_cache_t +typedef unsigned long xfs_pflags_t; + +#define PFLAGS_TEST_NOIO() (current->flags & PF_NOIO) +#define PFLAGS_TEST_FSTRANS() (current->flags & PF_FSTRANS) + +#define PFLAGS_SET_NOIO(STATEP) do { \ + *(STATEP) = current->flags; \ + current->flags |= PF_NOIO; \ +} while (0) + +#define PFLAGS_SET_FSTRANS(STATEP) do { \ + *(STATEP) = current->flags; \ + current->flags |= PF_FSTRANS; \ +} while (0) + +#define PFLAGS_RESTORE(STATEP) do { \ + current->flags = *(STATEP); \ +} while (0) + +#define PFLAGS_DUP(OSTATEP, NSTATEP) do { \ + *(NSTATEP) = *(OSTATEP); \ +} while (0); + +static __inline unsigned int kmem_flags_convert(int flags) +{ + int lflags; + +#if DEBUG + if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS))) { + printk(KERN_WARNING + "XFS: memory allocation with wrong flags (%x)\n", flags); + BUG(); + } +#endif + + lflags = (flags & KM_NOSLEEP) ? GFP_ATOMIC : GFP_KERNEL; + + /* avoid recusive callbacks to filesystem during transactions */ + if (PFLAGS_TEST_FSTRANS() || (flags & KM_NOFS)) + lflags &= ~__GFP_FS; + + return lflags; +} + 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); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/ktrace.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/ktrace.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/ktrace.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/ktrace.c 2003-08-17 21:26:18.000000000 +0200 @@ -31,6 +31,7 @@ */ #include +#include #include #include "kmem.h" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/spin.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/spin.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/support/spin.h 2003-05-13 12:37:25.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/support/spin.h 2003-08-17 21:26:19.000000000 +0200 @@ -43,6 +43,8 @@ * We don't need to worry about SMP or not here. */ +#define SPLDECL(s) unsigned long s + typedef spinlock_t lock_t; #define spinlock_init(lock, name) spin_lock_init(lock) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs.h 2003-05-13 12:35:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs.h 2003-08-17 21:26:18.000000000 +0200 @@ -32,10 +32,10 @@ #ifndef __XFS_H__ #define __XFS_H__ -#include #include - +#include #include + #include #include @@ -53,56 +53,7 @@ #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 -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_acl.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_acl.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_acl.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_acl.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,24 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_inum.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_acl.h" +#include "xfs_mac.h" +#include "xfs_attr.h" + #include STATIC int xfs_acl_setmode(vnode_t *, xfs_acl_t *, int *); @@ -209,19 +226,23 @@ xfs_acl_vget( int kind) { int error; - xfs_acl_t *xfs_acl; + xfs_acl_t *xfs_acl = NULL; posix_acl_xattr_header *ext_acl = acl; + int flags = 0; VN_HOLD(vp); if ((error = _MAC_VACCESS(vp, NULL, VREAD))) goto out; - if (!(_ACL_ALLOC(xfs_acl))) { - error = ENOMEM; - goto out; - } + if(size) { + if (!(_ACL_ALLOC(xfs_acl))) { + error = ENOMEM; + goto out; + } + memset(xfs_acl, 0, sizeof(xfs_acl_t)); + } else + flags = ATTR_KERNOVAL; - memset(xfs_acl, 0, sizeof(xfs_acl_t)); - xfs_acl_get_attr(vp, xfs_acl, kind, size? 0 : ATTR_KERNOVAL, &error); + xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error); if (error) goto out; @@ -245,7 +266,8 @@ xfs_acl_vget( } out: VN_RELE(vp); - _ACL_FREE(xfs_acl); + if(xfs_acl) + _ACL_FREE(xfs_acl); return -error; } @@ -640,6 +662,7 @@ xfs_acl_get_attr( { int len = sizeof(xfs_acl_t); + ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); flags |= ATTR_ROOT; VOP_ATTR_GET(vp, kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_ag.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_ag.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_ag.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_ag.h 2003-08-17 21:26:18.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -185,9 +185,8 @@ xfs_agblock_t xfs_agfl_block(struct xfs_ #endif #define XFS_AGFL_SIZE(mp) ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t)) -/* -- nathans TODO ... use of BBSIZE here - should be sector size -- */ typedef struct xfs_agfl { - xfs_agblock_t agfl_bno[BBSIZE/sizeof(xfs_agblock_t)]; + xfs_agblock_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */ } xfs_agfl_t; /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_alloc.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_alloc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_alloc.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_alloc.c 2003-08-17 21:26:18.000000000 +0200 @@ -33,7 +33,26 @@ /* * Free space allocation for XFS. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" +#include "xfs_bit.h" +#include "xfs_error.h" + #if defined(DEBUG) /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_alloc_btree.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_alloc_btree.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_alloc_btree.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_alloc_btree.c 2003-08-17 21:26:18.000000000 +0200 @@ -34,7 +34,24 @@ * Free space allocation for XFS. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" +#include "xfs_error.h" /* * Prototypes for internal functions. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_attr.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_attr.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_attr.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_attr.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,39 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_attr_leaf.h" +#include "xfs_error.h" +#include "xfs_bit.h" +#include "xfs_quota.h" +#include "xfs_rw.h" +#include "xfs_trans_space.h" /* * xfs_attr.c diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_attr_fetch.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_attr_fetch.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_attr_fetch.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_attr_fetch.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,36 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_itable.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_attr_leaf.h" int xfs_attr_fetch(xfs_inode_t *ip, char *name, char *value, int valuelen) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_attr_leaf.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_attr_leaf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_attr_leaf.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_attr_leaf.c 2003-08-17 21:26:18.000000000 +0200 @@ -35,7 +35,36 @@ * GROT: figure out how to recover gracefully when bmap returns ENOSPC. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_attr_leaf.h" +#include "xfs_error.h" +#include "xfs_bit.h" /* * xfs_attr_leaf.c @@ -457,8 +486,7 @@ xfs_attr_shortform_list(xfs_attr_list_co i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { if (unlikely( ((char *)sfe < (char *)sf) || - ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)) || - (sfe->namelen >= MAXNAMELEN))) { + ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) { XFS_CORRUPTION_ERROR("xfs_attr_shortform_list", XFS_ERRLEVEL_LOW, context->dp->i_mount, sfe); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_bit.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_bit.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_bit.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_bit.c 2003-08-17 21:26:18.000000000 +0200 @@ -34,7 +34,12 @@ * XFS bit manipulation routines, used in non-realtime code. */ -#include +#include "xfs.h" +#include "xfs_bit.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_buf_item.h" + #ifndef HAVE_ARCH_HIGHBIT /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_bmap.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_bmap.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_bmap.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_bmap.c 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,44 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_dmapi.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_itable.h" +#include "xfs_extfree_item.h" +#include "xfs_alloc.h" +#include "xfs_bmap.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_bit.h" +#include "xfs_rw.h" +#include "xfs_quota.h" +#include "xfs_trans_space.h" +#include "xfs_buf_item.h" #ifdef DEBUG ktrace_t *xfs_bmap_trace_buf; @@ -5542,7 +5579,7 @@ xfs_getbmap( if (whichfork == XFS_DATA_FORK) { if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) { prealloced = 1; - fixlen = XFS_MAX_FILE_OFFSET; + fixlen = XFS_MAXIOFFSET(mp); } else { prealloced = 0; fixlen = ip->i_d.di_size; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_bmap_btree.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_bmap_btree.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_bmap_btree.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_bmap_btree.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,36 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_itable.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_bit.h" +#include "xfs_bmap.h" +#include "xfs_error.h" +#include "xfs_quota.h" #ifdef DEBUG ktrace_t *xfs_bmbt_trace_buf; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_btree.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_btree.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_btree.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_btree.c 2003-08-17 21:26:18.000000000 +0200 @@ -34,7 +34,31 @@ * This file contains common code for the space manager's btree implementations. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bit.h" +#include "xfs_error.h" /* * Cursor allocation zone. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_buf.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_buf.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_buf.h 2003-05-03 03:37:45.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_buf.h 2003-08-17 21:26:18.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -283,7 +283,6 @@ static inline int XFS_bwrite(page_buf_t return error; } - #define XFS_bdwrite(pb) \ pagebuf_iostart(pb, PBF_DELWRI | PBF_ASYNC) @@ -307,15 +306,15 @@ static inline int xfs_bdwrite(void *mp, * of its metadata. */ -extern void XFS_bflush(xfs_buftarg_t *); -#define xfs_binval(buftarg) XFS_bflush(buftarg) +#define xfs_binval(buftarg) xfs_flush_buftarg(buftarg) + +#define XFS_bflush(buftarg) xfs_flush_buftarg(buftarg) #define xfs_incore_relse(buftarg,delwri_only,wait) \ xfs_relse_buftarg(buftarg) #define xfs_baread(target, rablkno, ralen) \ - pagebuf_readahead((target), (rablkno), \ - (ralen), PBF_DONT_BLOCK) + pagebuf_readahead((target), (rablkno), (ralen), PBF_DONT_BLOCK) #define XFS_getrbuf(sleep,mp) \ pagebuf_get_empty((mp)->m_ddev_targp) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_buf_item.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_buf_item.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_buf_item.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_buf_item.c 2003-08-17 21:26:18.000000000 +0200 @@ -37,7 +37,22 @@ * transaction routines. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_buf_item.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_trans_priv.h" +#include "xfs_rw.h" +#include "xfs_bit.h" +#include "xfs_error.h" #define ROUNDUPNBWORD(x) (((x) + (NBWORD - 1)) & ~(NBWORD - 1)) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_cap.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_cap.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_cap.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_cap.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" STATIC int xfs_cap_allow_set(vnode_t *); @@ -115,15 +115,17 @@ xfs_cap_vget( int flags = ATTR_ROOT; xfs_cap_set_t xfs_cap = { 0 }; posix_cap_xattr *xattr_cap = cap; + char *data = (char *)&xfs_cap; VN_HOLD(vp); if ((error = _MAC_VACCESS(vp, NULL, VREAD))) goto out; - if (!size) + if (!size) { flags |= ATTR_KERNOVAL; - VOP_ATTR_GET(vp, SGI_CAP_LINUX, (char *)&xfs_cap, - &len, flags, sys_cred, error); + data = NULL; + } + VOP_ATTR_GET(vp, SGI_CAP_LINUX, data, &len, flags, sys_cred, error); if (error) goto out; ASSERT(len == sizeof(xfs_cap_set_t)); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_da_btree.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_da_btree.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_da_btree.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_da_btree.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,41 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_attr_leaf.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_error.h" +#include "xfs_bit.h" #if defined(XFSDEBUG) && defined(CONFIG_KDB) #undef xfs_buftrace diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dfrag.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dfrag.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dfrag.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dfrag.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,35 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_ag.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_ialloc.h" +#include "xfs_itable.h" +#include "xfs_dfrag.h" +#include "xfs_error.h" +#include "xfs_mac.h" +#include "xfs_rw.h" /* * Syssgi interface for swapext diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dinode.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dinode.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dinode.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dinode.h 2003-08-17 21:26:19.000000000 +0200 @@ -72,7 +72,8 @@ typedef struct xfs_dinode_core __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 */ + __uint8_t di_pad[8]; /* unused, zeroed space */ + __uint16_t di_flushiter; /* incremented on flush */ 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 */ @@ -89,6 +90,8 @@ typedef struct xfs_dinode_core __uint32_t di_gen; /* generation number */ } xfs_dinode_core_t; +#define DI_MAX_FLUSH 0xffff + typedef struct xfs_dinode { xfs_dinode_core_t di_core; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,32 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_error.h" /* * xfs_dir.c diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2.c 2003-08-17 21:26:18.000000000 +0200 @@ -35,7 +35,38 @@ * Top-level and utility routines. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_dir2_sf.h" +#include "xfs_dir2_trace.h" +#include "xfs_error.h" +#include "xfs_bit.h" /* * Declarations for interface routines. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_block.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_block.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_block.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_block.c 2003-08-17 21:26:18.000000000 +0200 @@ -36,8 +36,32 @@ * See xfs_dir2_block.h for the format. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_trace.h" +#include "xfs_error.h" /* * Local function prototypes. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_data.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_data.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_data.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_data.c 2003-08-17 21:26:18.000000000 +0200 @@ -36,8 +36,30 @@ * See xfs_dir2_data.h for data structures. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_error.h" #ifdef DEBUG /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_leaf.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_leaf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_leaf.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_leaf.c 2003-08-17 21:26:18.000000000 +0200 @@ -38,7 +38,34 @@ * XFS_DIR2_LEAF1 block containing the hash table and freespace map. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_dir2_trace.h" +#include "xfs_error.h" +#include "xfs_bit.h" /* * Local function declarations. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_node.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_node.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_node.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_node.c 2003-08-17 21:26:18.000000000 +0200 @@ -36,7 +36,32 @@ * See data structures in xfs_dir2_node.h and xfs_da_btree.h. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_dir2_trace.h" +#include "xfs_error.h" /* * Function declarations. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_sf.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_sf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_sf.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_sf.c 2003-08-17 21:26:18.000000000 +0200 @@ -35,7 +35,32 @@ * Shortform directory implementation for v2 directories. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_error.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_trace.h" /* * Prototypes for internal functions. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_trace.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_trace.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir2_trace.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir2_trace.c 2003-08-17 21:26:18.000000000 +0200 @@ -34,8 +34,20 @@ * xfs_dir2_trace.c * Tracing for xfs v2 directories. */ -#include +#include "xfs.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_da_btree.h" +#include "xfs_dir2_trace.h" #ifdef DEBUG ktrace_t *xfs_dir2_trace_buf; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir_leaf.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir_leaf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dir_leaf.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dir_leaf.c 2003-08-17 21:26:18.000000000 +0200 @@ -36,8 +36,33 @@ * GROT: figure out how to recover gracefully when bmap returns ENOSPC. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_error.h" /* * xfs_dir_leaf.c @@ -458,8 +483,7 @@ xfs_dir_shortform_getdents(xfs_inode_t * if (unlikely( ((char *)sfe < (char *)sf) || - ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)) || - (sfe->namelen >= MAXNAMELEN))) { + ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)))) { xfs_dir_trace_g_du("sf: corrupted", dp, uio); XFS_CORRUPTION_ERROR("xfs_dir_shortform_getdents", XFS_ERRLEVEL_LOW, mp, sfe); @@ -1976,8 +2000,7 @@ xfs_dir_leaf_getdents_int( if (unlikely( ((char *)namest < (char *)leaf) || - ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)) || - (entry->namelen >= MAXNAMELEN))) { + ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) { XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(1)", XFS_ERRLEVEL_LOW, mp, leaf); xfs_dir_trace_g_du("leaf: corrupted", dp, uio); @@ -2040,8 +2063,7 @@ xfs_dir_leaf_getdents_int( if (unlikely( ((char *)namest < (char *)leaf) || - ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)) || - (entry->namelen >= MAXNAMELEN))) { + ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) { XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(2)", XFS_ERRLEVEL_LOW, mp, leaf); xfs_dir_trace_g_du("leaf: corrupted", dp, uio); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dmops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dmops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_dmops.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_dmops.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,20 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" + #ifndef CONFIG_XFS_DMAPI xfs_dmops_t xfs_dmcore_xfs = { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_error.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_error.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_error.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_error.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,8 +30,26 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_sb.h" +#include "xfs_trans.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_utils.h" +#include "xfs_error.h" #ifdef DEBUG @@ -305,6 +323,7 @@ xfs_corruption_error( int linenum, inst_t *ra) { - xfs_hex_dump(p, 16); + if (level <= xfs_error_level) + xfs_hex_dump(p, 16); xfs_error_report(tag, level, mp, fname, linenum, ra); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_extfree_item.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_extfree_item.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_extfree_item.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_extfree_item.c 2003-08-17 21:26:18.000000000 +0200 @@ -35,7 +35,20 @@ * and xfs_efd_log_item items. */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_buf_item.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_trans_priv.h" +#include "xfs_extfree_item.h" kmem_zone_t *xfs_efi_zone; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_fsops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_fsops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_fsops.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_fsops.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,37 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_ag.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_error.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_fsops.h" +#include "xfs_itable.h" +#include "xfs_rw.h" +#include "xfs_trans_space.h" +#include "xfs_rtalloc.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_inode_item.h" /* * File system operations diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_ialloc.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_ialloc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_ialloc.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_ialloc.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,33 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_error.h" /* * Log specified fields for the inode given by bp and off. @@ -126,7 +151,6 @@ xfs_ialloc_ag_alloc( 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 */ @@ -240,6 +264,11 @@ xfs_ialloc_ag_alloc( version = XFS_DINODE_VERSION_2; else version = XFS_DINODE_VERSION_1; + + memset(&dic, 0, sizeof(xfs_dinode_core_t)); + INT_SET(dic.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); + INT_SET(dic.di_version, ARCH_CONVERT, version); + for (j = 0; j < nbufs; j++) { /* * Get the block. @@ -254,36 +283,6 @@ xfs_ialloc_ag_alloc( /* * 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); - memset(&(dic.di_pad[0]), 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); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_ialloc_btree.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_ialloc_btree.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_ialloc_btree.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_ialloc_btree.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,13 +30,30 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ + +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" + /* * Inode allocation management for XFS. */ -#include - - /* * Prototypes for internal functions. */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_iget.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_iget.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_iget.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_iget.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,31 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_quota.h" +#include "xfs_utils.h" /* * Initialize the inode hash table for the newly mounted file system. @@ -190,7 +214,13 @@ again: XFS_STATS_INC(xfsstats.xs_ig_found); + ip->i_flags &= ~XFS_IRECLAIMABLE; read_unlock(&ih->ih_lock); + + XFS_MOUNT_ILOCK(mp); + list_del_init(&ip->i_reclaim); + XFS_MOUNT_IUNLOCK(mp); + goto finish_inode; } else if (vp != inode_vp) { @@ -228,6 +258,7 @@ finish_inode: if (newnode) { xfs_iocore_inode_reinit(ip); } + vn_trace_exit(vp, "xfs_iget.found", (inst_t *)__return_address); goto return_ip; @@ -448,8 +479,10 @@ inode_allocate: } bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); - if (bdp == NULL) + if (bdp == NULL) { + XFS_STATS_INC(xfsstats.xs_ig_dup); goto inode_allocate; + } ip = XFS_BHVTOI(bdp); if (lock_flags != 0) xfs_ilock(ip, lock_flags); @@ -702,6 +735,9 @@ xfs_iextract( } } + /* Deal with the deleted inodes list */ + list_del_init(&ip->i_reclaim); + mp->m_ireclaims++; XFS_MOUNT_IUNLOCK(mp); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_inode.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_inode.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_inode.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,8 +30,41 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include /* for get_unaligned, put_unaligned */ +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_imap.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_buf_item.h" +#include "xfs_rw.h" +#include "xfs_error.h" +#include "xfs_bit.h" +#include "xfs_utils.h" +#include "xfs_dir2_trace.h" +#include "xfs_quota.h" +#include "xfs_mac.h" +#include "xfs_acl.h" kmem_zone_t *xfs_ifork_zone; @@ -379,7 +412,7 @@ xfs_itobp( mp->m_dev, (unsigned long long)imap.im_blkno, i, INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); #endif - XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_LOW, + XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH, mp, dip); xfs_trans_brelse(tp, bp); return XFS_ERROR(EFSCORRUPTED); @@ -792,6 +825,8 @@ xfs_xlate_dinode_core( sizeof(buf_core->di_pad)); } + INT_XLATE(buf_core->di_flushiter, mem_core->di_flushiter, dir, arch); + 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, @@ -923,6 +958,7 @@ xfs_iread( 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); + ip->i_d.di_flushiter = INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT); /* * Make sure to pull in the mode here as well in * case the inode is released without being used. @@ -939,6 +975,8 @@ xfs_iread( XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); } + INIT_LIST_HEAD(&ip->i_reclaim); + /* * The inode format changed when we moved the link count and * made it 32 bits long. If this is an old format inode, @@ -1230,7 +1268,7 @@ xfs_isize_check( */ if (xfs_bmapi(NULL, ip, map_first, (XFS_B_TO_FSB(mp, - (xfs_ufsize_t)XFS_MAX_FILE_OFFSET) - + (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first), XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps, NULL)) @@ -1284,11 +1322,11 @@ xfs_file_last_byte( last_byte = XFS_FSB_TO_B(mp, last_block); if (last_byte < 0) { - return XFS_MAX_FILE_OFFSET; + return XFS_MAXIOFFSET(mp); } last_byte += (1 << mp->m_writeio_log); if (last_byte < 0) { - return XFS_MAX_FILE_OFFSET; + return XFS_MAXIOFFSET(mp); } return last_byte; } @@ -1578,7 +1616,7 @@ xfs_itruncate_finish( * 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); + last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp)); ASSERT(first_unmap_block <= last_block); done = 0; if (last_block == first_unmap_block) { @@ -2588,6 +2626,16 @@ xfs_iunpin( ASSERT(atomic_read(&ip->i_pincount) > 0); if (atomic_dec_and_test(&ip->i_pincount)) { + vnode_t *vp = XFS_ITOV_NULL(ip); + + /* make sync come back and flush this inode */ + if (vp) { + struct inode *inode = LINVFS_GET_IP(vp); + + if (!(inode->i_state & I_NEW)) + mark_inode_dirty_sync(inode); + } + wake_up(&ip->i_ipin_wait); } } @@ -2949,9 +2997,7 @@ xfs_iflush( * see if other inodes can be gathered into this write */ -#ifdef DEBUG - ip->i_chash->chl_buf = bp; /* inode clustering debug */ -#endif + ip->i_chash->chl_buf = bp; ch = XFS_CHASH(mp, ip->i_blkno); s = mutex_spinlock(&ch->ch_lock); @@ -3190,6 +3236,13 @@ xfs_iflush_int( goto corrupt_out; } /* + * bump the flush iteration count, used to detect flushes which + * postdate a log record during recovery. + */ + + ip->i_d.di_flushiter++; + + /* * 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 @@ -3198,6 +3251,10 @@ xfs_iflush_int( xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), -1, ARCH_CONVERT); + /* Wrap, we never let the log put out DI_MAX_FLUSH */ + if (ip->i_d.di_flushiter == DI_MAX_FLUSH) + ip->i_d.di_flushiter = 0; + /* * If this is really an old format inode and the superblock version * has not been updated to support only new format inodes, then @@ -3596,6 +3653,8 @@ xfs_ichgtime(xfs_inode_t *ip, */ SYNCHRONIZE(); ip->i_update_core = 1; + if (!(inode->i_state & I_LOCK)) + mark_inode_dirty(inode); } #ifdef XFS_ILOCK_TRACE diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_inode.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_inode.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_inode.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_inode.h 2003-08-17 21:26:19.000000000 +0200 @@ -192,9 +192,7 @@ typedef struct xfs_chashlist { 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 + struct xfs_buf *chl_buf; /* the inode buffer */ } xfs_chashlist_t; typedef struct xfs_chash { @@ -243,6 +241,7 @@ typedef struct xfs_inode { 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 list_head i_reclaim; /* reclaim list */ struct bhv_desc i_bhv_desc; /* inode behavior descriptor*/ struct xfs_dquot *i_udquot; /* user dquot */ struct xfs_dquot *i_gdquot; /* group dquot */ @@ -365,6 +364,7 @@ void xfs_ifork_next_set(xfs_inode_t *ip, #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 */ +#define XFS_IRECLAIMABLE 0x0010 /* inode can be reclaimed */ /* * Flags for inode locking. @@ -408,14 +408,6 @@ void xfs_ifork_next_set(xfs_inode_t *ip, #define XFS_ITRUNC_DEFINITE 0x1 #define XFS_ITRUNC_MAYBE 0x2 -/* - * max file offset is 2^(31+PAGE_SHIFT) - 1 (due to linux page cache) - * - * NOTE: XFS itself can handle 2^63 - 1 (largest positive value of xfs_fsize_t) - * but this is the Linux limit. - */ -#define XFS_MAX_FILE_OFFSET MAX_LFS_FILESIZE - #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) @@ -479,7 +471,7 @@ void xfs_iunlock_map_shared(xfs_inode_t void xfs_ifunlock(xfs_inode_t *); void xfs_ireclaim(xfs_inode_t *); int xfs_finish_reclaim(xfs_inode_t *, int, int); -int xfs_finish_reclaim_all(struct xfs_mount *); +int xfs_finish_reclaim_all(struct xfs_mount *, int); /* * xfs_inode.c prototypes. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_inode_item.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_inode_item.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_inode_item.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_inode_item.c 2003-08-17 21:26:18.000000000 +0200 @@ -36,7 +36,32 @@ * items as well as utility routines used by the inode specific * transaction routines. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_buf_item.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_trans_priv.h" +#include "xfs_ag.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_rw.h" kmem_zone_t *xfs_ili_zone; /* inode log item zone */ @@ -854,7 +879,7 @@ xfs_inode_item_push( * 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); + (void) xfs_iflush(ip, XFS_IFLUSH_ASYNC); xfs_iunlock(ip, XFS_ILOCK_SHARED); return; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_iocore.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_iocore.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_iocore.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_iocore.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,7 +30,38 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_itable.h" +#include "xfs_btree.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_error.h" +#include "xfs_bit.h" +#include "xfs_rw.h" +#include "xfs_quota.h" +#include "xfs_trans_space.h" +#include "xfs_dmapi.h" STATIC xfs_fsize_t @@ -46,8 +77,7 @@ xfs_ioinit( struct xfs_mount_args *mntargs, int flags) { - return xfs_mountfs(vfsp, XFS_VFSTOM(vfsp), - vfsp->vfs_super->s_bdev->bd_dev, flags); + return xfs_mountfs(vfsp, XFS_VFSTOM(vfsp), flags); } xfs_ioops_t xfs_iocore_xfs = { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_itable.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_itable.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_itable.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_itable.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,30 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_ag.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_ialloc.h" +#include "xfs_itable.h" +#include "xfs_error.h" /* * Return stat information for one inode. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log.c 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,25 @@ * High level interface routines for log manager */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_ag.h" +#include "xfs_sb.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_error.h" +#include "xfs_log_priv.h" +#include "xfs_buf_item.h" +#include "xfs_alloc_btree.h" +#include "xfs_log_recover.h" +#include "xfs_bit.h" +#include "xfs_rw.h" +#include "xfs_trans_priv.h" #define xlog_write_adv_cnt(ptr, len, off, bytes) \ @@ -396,19 +414,6 @@ xfs_log_release_iclog(xfs_mount_t *mp, } /* - * 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. @@ -479,8 +484,6 @@ xfs_log_mount(xfs_mount_t *mp, xfs_daddr_t blk_offset, int num_bblks) { - xlog_t *log; - if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname); else { @@ -490,7 +493,7 @@ xfs_log_mount(xfs_mount_t *mp, ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); } - mp->m_log = log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks); + mp->m_log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks); #if defined(DEBUG) || defined(XLOG_NOLOG) if (! xlog_debug) { @@ -510,19 +513,19 @@ xfs_log_mount(xfs_mount_t *mp, if (readonly) vfsp->vfs_flag &= ~VFS_RDONLY; - error = xlog_recover(log, readonly); + error = xlog_recover(mp->m_log, readonly); if (readonly) vfsp->vfs_flag |= VFS_RDONLY; if (error) { cmn_err(CE_WARN, "XFS: log mount/recovery failed"); - xlog_unalloc_log(log); + xlog_unalloc_log(mp->m_log); return error; } } /* Normal transactions can now occur */ - log->l_flags &= ~XLOG_ACTIVE_RECOVERY; + mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY; /* End mounting message in xfs_log_mount_finish */ return 0; @@ -791,8 +794,9 @@ xfs_log_move_tail(xfs_mount_t *mp, do { ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV); - if (free_bytes < tic->t_unit_res) + if (free_bytes < tic->t_unit_res && tail_lsn != 1) break; + tail_lsn = 0; free_bytes -= tic->t_unit_res; sv_signal(&tic->t_sema); tic = tic->t_next; @@ -811,8 +815,9 @@ xfs_log_move_tail(xfs_mount_t *mp, need_bytes = tic->t_unit_res*tic->t_cnt; else need_bytes = tic->t_unit_res; - if (free_bytes < need_bytes) + if (free_bytes < need_bytes && tail_lsn != 1) break; + tail_lsn = 0; free_bytes -= need_bytes; sv_signal(&tic->t_sema); tic = tic->t_next; @@ -833,8 +838,10 @@ xfs_log_need_covered(xfs_mount_t *mp) SPLDECL(s); int needed = 0, gen; xlog_t *log = mp->m_log; + vfs_t *vfsp = XFS_MTOVFS(mp); - if (mp->m_frozen || XFS_FORCED_SHUTDOWN(mp)) + if (mp->m_frozen || XFS_FORCED_SHUTDOWN(mp) || + (vfsp->vfs_flag & VFS_RDONLY)) return 0; s = LOG_LOCK(log); @@ -1059,7 +1066,7 @@ xlog_get_iclog_buffer_size(xfs_mount_t * if (mp->m_logbufs == 0) { xlog_debug = 0; xlog_devt = log->l_dev; - log->l_iclog_bufs = XLOG_NUM_ICLOGS; + log->l_iclog_bufs = XLOG_MIN_ICLOGS; } else #endif { @@ -1067,9 +1074,16 @@ xlog_get_iclog_buffer_size(xfs_mount_t * * 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 + if (mp->m_logbufs == -1) { + if (xfs_physmem <= btoc(128*1024*1024)) { + log->l_iclog_bufs = XLOG_MIN_ICLOGS; + } else if (xfs_physmem <= btoc(400*1024*1024)) { + log->l_iclog_bufs = XLOG_MED_ICLOGS;; + } else { + /* 256K with 32K bufs */ + log->l_iclog_bufs = XLOG_MAX_ICLOGS; + } + } else log->l_iclog_bufs = mp->m_logbufs; #if defined(DEBUG) || defined(XLOG_NOLOG) @@ -1173,28 +1187,42 @@ xlog_alloc_log(xfs_mount_t *mp, int i; int iclogsize; - log = (void *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP); + log = (xlog_t *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP); 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_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 */ + + if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) { + if (mp->m_sb.sb_logsunit <= 1) { + log->l_stripemask = 1; + } else { + log->l_stripemask = 1 << + xfs_highbit32(mp->m_sb.sb_logsunit >> BBSHIFT); + } + } + if (XFS_SB_VERSION_HASSECTOR(&mp->m_sb)) { + log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; + ASSERT(log->l_sectbb_log <= mp->m_sectbb_log); + /* for larger sector sizes, must have v2 or external log */ + ASSERT(log->l_sectbb_log == 0 || + log->l_logBBstart == 0 || + XFS_SB_VERSION_HASLOGV2(&mp->m_sb)); + ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); + } + log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1; xlog_get_iclog_buffer_size(mp, log); @@ -2793,10 +2821,9 @@ xlog_state_switch_iclogs(xlog_t *log, /* Round up to next log-sunit */ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - if (log->l_curr_block & (log->l_mp->m_lstripemask - 1)) { - roundup = log->l_mp->m_lstripemask - - (log->l_curr_block & - (log->l_mp->m_lstripemask - 1)); + if (log->l_curr_block & (log->l_stripemask - 1)) { + roundup = log->l_stripemask - + (log->l_curr_block & (log->l_stripemask - 1)); } else { roundup = 0; } @@ -3275,15 +3302,17 @@ xlog_verify_disk_cycle_no(xlog_t *log, { xfs_buf_t *bp; uint cycle_no; + xfs_caddr_t ptr; 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); + bp = xlog_get_bp(log, 1); 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) + ptr = xlog_align(log, i, 1, bp); + if (GET_CYCLE(ptr, ARCH_CONVERT) != cycle_no) xlog_warn("XFS: xlog_verify_disk_cycle_no: bad cycle no"); } xlog_put_bp(bp); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log.h 2003-08-17 21:26:18.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -153,7 +153,6 @@ xfs_lsn_t xfs_log_done(struct xfs_mount int xfs_log_force(struct xfs_mount *mp, xfs_lsn_t lsn, uint flags); -int xfs_log_init(void); int xfs_log_mount(struct xfs_mount *mp, dev_t log_dev, xfs_daddr_t start_block, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log_priv.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log_priv.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log_priv.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log_priv.h 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -50,7 +50,8 @@ struct xfs_mount; * Macros, structures, prototypes for internal log manager use. */ -#define XLOG_NUM_ICLOGS 2 +#define XLOG_MIN_ICLOGS 2 +#define XLOG_MED_ICLOGS 4 #define XLOG_MAX_ICLOGS 8 #define XLOG_CALLBACK_SIZE 10 #define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Illegal cycle number */ @@ -73,6 +74,9 @@ int xlog_btolrbb(int b); #define XLOG_HEADER_SIZE 512 +#define XLOG_REC_SHIFT(log) \ + BTOBB(1 << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \ + XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) #define XLOG_TOTAL_REC_SHIFT(log) \ BTOBB(XLOG_MAX_ICLOGS << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) @@ -202,9 +206,9 @@ void xlog_grant_add_space(struct log *lo #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); } +#define xlog_panic(args...) cmn_err(CE_PANIC, ## args) +#define xlog_exit(args...) cmn_err(CE_PANIC, ## args) +#define xlog_warn(args...) cmn_err(CE_WARN, ## args) /* * In core log state @@ -403,6 +407,7 @@ typedef struct xlog_rec_ext_header { uint xh_cycle; /* write cycle of log : 4 */ uint xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ } xlog_rec_ext_header_t; + #ifdef __KERNEL__ /* * - A log record header is 512 bytes. There is plenty of room to grow the @@ -441,12 +446,10 @@ typedef struct xlog_iclog_fields { char *ic_datap; /* pointer to iclog data */ } xlog_iclog_fields_t; -typedef struct xlog_in_core2 { - union { - xlog_rec_header_t hic_header; - xlog_rec_ext_header_t hic_xheader; - char hic_sector[XLOG_HEADER_SIZE]; - } ic_h; +typedef union xlog_in_core2 { + xlog_rec_header_t hic_header; + xlog_rec_ext_header_t hic_xheader; + char hic_sector[XLOG_HEADER_SIZE]; } xlog_in_core_2_t; typedef struct xlog_in_core { @@ -473,7 +476,7 @@ typedef struct xlog_in_core { #define ic_bwritecnt hic_fields.ic_bwritecnt #define ic_state hic_fields.ic_state #define ic_datap hic_fields.ic_datap -#define ic_header hic_data->ic_h.hic_header +#define ic_header hic_data->hic_header /* * The reservation head lsn is not made up of a cycle number and block number. @@ -530,8 +533,11 @@ typedef struct log { uint l_flags; uint l_quotaoffs_flag;/* XFS_DQ_*, if QUOTAOFFs found */ struct xfs_buf_cancel **l_buf_cancel_table; + int l_stripemask; /* log stripe mask */ int l_iclog_hsize; /* size of iclog header */ int l_iclog_heads; /* number of iclog header sectors */ + uint l_sectbb_log; /* log2 of sector size in bbs */ + uint l_sectbb_mask; /* sector size in bbs alignment mask */ } xlog_t; @@ -546,11 +552,13 @@ extern int xlog_print_find_oldest(xlog_ 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); +extern struct xfs_buf *xlog_get_bp(xlog_t *, int); +extern void xlog_put_bp(struct xfs_buf *); +extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); +extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); + #define XLOG_TRACE_GRAB_FLUSH 1 #define XLOG_TRACE_REL_FLUSH 2 #define XLOG_TRACE_SLEEP_FLUSH 3 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log_recover.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log_recover.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_log_recover.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_log_recover.c 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -30,56 +30,103 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_ag.h" +#include "xfs_sb.h" +#include "xfs_trans.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_error.h" +#include "xfs_bmap_btree.h" +#include "xfs_alloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_imap.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_ialloc_btree.h" +#include "xfs_ialloc.h" +#include "xfs_error.h" +#include "xfs_log_priv.h" +#include "xfs_buf_item.h" +#include "xfs_alloc_btree.h" +#include "xfs_log_recover.h" +#include "xfs_extfree_item.h" +#include "xfs_trans_priv.h" +#include "xfs_bit.h" +#include "xfs_quota.h" +#include "xfs_rw.h" -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 int xlog_find_zeroed(xlog_t *, xfs_daddr_t *); +STATIC int xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t); 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); +STATIC void xlog_recover_check_summary(xlog_t *); +STATIC void xlog_recover_check_ail(xfs_mount_t *, xfs_log_item_t *, int); #else #define xlog_recover_check_summary(log) #define xlog_recover_check_ail(mp, lip, gen) -#endif /* DEBUG */ +#endif +/* + * Sector aligned buffer routines for buffer create/read/write/access + */ + +#define XLOG_SECTOR_ROUNDUP_BBCOUNT(log, bbs) \ + ( ((log)->l_sectbb_mask && (bbs & (log)->l_sectbb_mask)) ? \ + ((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) ) +#define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno) ((bno) & ~(log)->l_sectbb_mask) + xfs_buf_t * -xlog_get_bp(int num_bblks, xfs_mount_t *mp) +xlog_get_bp( + xlog_t *log, + int num_bblks) { - xfs_buf_t *bp; - ASSERT(num_bblks > 0); - bp = XFS_ngetrbuf(BBTOB(num_bblks),mp); - return bp; -} /* xlog_get_bp */ - + if (log->l_sectbb_log) { + if (num_bblks > 1) + num_bblks += XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1); + num_bblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, num_bblks); + } + return XFS_ngetrbuf(BBTOB(num_bblks), log->l_mp); +} void -xlog_put_bp(xfs_buf_t *bp) +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) +xlog_bread( + xlog_t *log, + xfs_daddr_t blk_no, + int nbblks, + xfs_buf_t *bp) { - int error; + int error; + + if (log->l_sectbb_log) { + blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no); + nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks); + } - ASSERT(log); ASSERT(nbblks > 0); ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); ASSERT(bp); @@ -91,14 +138,11 @@ xlog_bread(xlog_t *log, XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp); xfsbdstrat(log->l_mp, bp); - if ((error = xfs_iowait(bp))) { + if ((error = xfs_iowait(bp))) xfs_ioerror_alert("xlog_bread", log->l_mp, 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. @@ -107,12 +151,17 @@ xlog_bread(xlog_t *log, */ int xlog_bwrite( - xlog_t *log, - int blk_no, - int nbblks, + xlog_t *log, + xfs_daddr_t blk_no, + int nbblks, xfs_buf_t *bp) { - int error; + int error; + + if (log->l_sectbb_log) { + blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no); + nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks); + } ASSERT(nbblks > 0); ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); @@ -128,94 +177,109 @@ xlog_bwrite( if ((error = xfs_bwrite(log->l_mp, bp))) xfs_ioerror_alert("xlog_bwrite", log->l_mp, bp, XFS_BUF_ADDR(bp)); + return error; +} - return (error); -} /* xlog_bwrite */ +xfs_caddr_t +xlog_align( + xlog_t *log, + xfs_daddr_t blk_no, + int nbblks, + xfs_buf_t *bp) +{ + xfs_caddr_t ptr; + + if (!log->l_sectbb_log) + return XFS_BUF_PTR(bp); + + ptr = XFS_BUF_PTR(bp) + BBTOB((int)blk_no & log->l_sectbb_mask); + ASSERT(XFS_BUF_SIZE(bp) >= + BBTOB(nbblks + (blk_no & log->l_sectbb_mask))); + return ptr; +} #ifdef DEBUG /* - * check log record header for recovery + * dump debug superblock and log record information */ -static void -xlog_header_check_dump(xfs_mount_t *mp, xlog_rec_header_t *head) +STATIC void +xlog_header_check_dump( + xfs_mount_t *mp, + xlog_rec_header_t *head) { - int b; + int b; - printk("%s: SB : uuid = ", __FUNCTION__); - 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)); + printk("%s: SB : uuid = ", __FUNCTION__); + 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)); } +#else +#define xlog_header_check_dump(mp, head) #endif /* * check log record header for recovery */ - STATIC int -xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head) +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 (unlikely(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 - XFS_ERROR_REPORT("xlog_header_check_recover(1)", - XFS_ERRLEVEL_HIGH, mp); - return XFS_ERROR(EFSCORRUPTED); - } else if (unlikely(!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 - XFS_ERROR_REPORT("xlog_header_check_recover(2)", - XFS_ERRLEVEL_HIGH, mp); - return XFS_ERROR(EFSCORRUPTED); - } + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); - return 0; + /* + * 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 (unlikely(INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT)) { + xlog_warn( + "XFS: dirty log written in incompatible format - can't recover"); + xlog_header_check_dump(mp, head); + XFS_ERROR_REPORT("xlog_header_check_recover(1)", + XFS_ERRLEVEL_HIGH, mp); + return XFS_ERROR(EFSCORRUPTED); + } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) { + xlog_warn( + "XFS: dirty log entry has mismatched uuid - can't recover"); + xlog_header_check_dump(mp, head); + XFS_ERROR_REPORT("xlog_header_check_recover(2)", + XFS_ERRLEVEL_HIGH, mp); + 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) +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. - */ + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); - xlog_warn("XFS: nil uuid in log - IRIX style log"); - - } else if (unlikely(!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 - XFS_ERROR_REPORT("xlog_header_check_mount", - XFS_ERRLEVEL_HIGH, mp); - return XFS_ERROR(EFSCORRUPTED); - } - - return 0; + 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 (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) { + xlog_warn("XFS: log has mismatched uuid - can't recover"); + xlog_header_check_dump(mp, head); + XFS_ERROR_REPORT("xlog_header_check_mount", + XFS_ERRLEVEL_HIGH, mp); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; } STATIC void @@ -223,6 +287,7 @@ xlog_recover_iodone( struct xfs_buf *bp) { xfs_mount_t *mp; + ASSERT(XFS_BUF_FSPRIVATE(bp, void *)); if (XFS_BUF_GETERROR(bp)) { @@ -247,12 +312,14 @@ xlog_recover_iodone( * 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) +xlog_find_cycle_start( + xlog_t *log, + xfs_buf_t *bp, + xfs_daddr_t first_blk, + xfs_daddr_t *last_blk, + uint cycle) { + xfs_caddr_t offset; xfs_daddr_t mid_blk; uint mid_cycle; int error; @@ -261,7 +328,8 @@ xlog_find_cycle_start(xlog_t *log, 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); + offset = xlog_align(log, mid_blk, 1, bp); + mid_cycle = GET_CYCLE(offset, ARCH_CONVERT); if (mid_cycle == cycle) { *last_blk = mid_blk; /* last_half_cycle == mid_cycle */ @@ -275,8 +343,7 @@ xlog_find_cycle_start(xlog_t *log, (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 @@ -288,27 +355,27 @@ xlog_find_cycle_start(xlog_t *log, * Set blkno to -1 if we encounter no errors. This is an invalid block number * since we don't ever expect logs to get this large. */ - STATIC int -xlog_find_verify_cycle( xlog_t *log, - xfs_daddr_t start_blk, - int nbblks, - uint stop_on_cycle_no, - xfs_daddr_t *new_blk) +xlog_find_verify_cycle( + xlog_t *log, + xfs_daddr_t start_blk, + int nbblks, + uint stop_on_cycle_no, + xfs_daddr_t *new_blk) { - xfs_daddr_t i, j; - uint cycle; - xfs_buf_t *bp; - char *buf = NULL; - int error = 0; - xfs_daddr_t bufblks; + xfs_daddr_t i, j; + uint cycle; + xfs_buf_t *bp; + xfs_daddr_t bufblks; + xfs_caddr_t buf = NULL; + int error = 0; bufblks = 1 << ffs(nbblks); - while (!(bp = xlog_get_bp(bufblks, log->l_mp))) { + while (!(bp = xlog_get_bp(log, bufblks))) { /* can't get enough memory to do everything in one big buffer */ bufblks >>= 1; - if (!bufblks) + if (bufblks <= log->l_sectbb_log) return ENOMEM; } @@ -320,7 +387,7 @@ xlog_find_verify_cycle( xlog_t *log, if ((error = xlog_bread(log, i, bcount, bp))) goto out; - buf = XFS_BUF_PTR(bp); + buf = xlog_align(log, i, bcount, bp); for (j = 0; j < bcount; j++) { cycle = GET_CYCLE(buf, ARCH_CONVERT); if (cycle == stop_on_cycle_no) { @@ -336,10 +403,8 @@ xlog_find_verify_cycle( xlog_t *log, out: xlog_put_bp(bp); - return error; -} /* xlog_find_verify_cycle */ - +} /* * Potentially backup over partial log record write. @@ -353,98 +418,103 @@ out: * 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; - int xhdrs; - - 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) << BBSHIFT); - } - - 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)"); - ASSERT(0); - error = XFS_ERROR(EIO); - goto out; +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; + xfs_caddr_t offset = NULL; + xlog_rec_header_t *head = NULL; + int error = 0; + int smallmem = 0; + int num_blks = *last_blk - start_blk; + int xhdrs; + + ASSERT(start_blk != 0 || *last_blk != start_blk); + + if (!(bp = xlog_get_bp(log, num_blks))) { + if (!(bp = xlog_get_bp(log, 1))) + return ENOMEM; + smallmem = 1; + } else { + if ((error = xlog_bread(log, start_blk, num_blks, bp))) + goto out; + offset = xlog_align(log, start_blk, num_blks, bp); + offset += ((num_blks - 1) << BBSHIFT); } - 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 (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - uint h_size = INT_GET(head->h_size, ARCH_CONVERT); - - xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; - if (h_size % XLOG_HEADER_CYCLE_SIZE) - xhdrs++; - } else { - xhdrs = 1; - } - - if (*last_blk - i + extra_bblks - != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+xhdrs) - *last_blk = i; + 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)"); + ASSERT(0); + error = XFS_ERROR(EIO); + goto out; + } -out: - xlog_put_bp(bp); + if (smallmem) { + if ((error = xlog_bread(log, i, 1, bp))) + goto out; + offset = xlog_align(log, i, 1, bp); + } - return error; -} /* xlog_find_verify_log_record */ + head = (xlog_rec_header_t *)offset; + + if (XLOG_HEADER_MAGIC_NUM == + INT_GET(head->h_magicno, ARCH_CONVERT)) + break; + + if (!smallmem) + offset -= 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 (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + uint h_size = INT_GET(head->h_size, ARCH_CONVERT); + + xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; + if (h_size % XLOG_HEADER_CYCLE_SIZE) + xhdrs++; + } else { + xhdrs = 1; + } + + if (*last_blk - i + extra_bblks + != BTOBB(INT_GET(head->h_len, ARCH_CONVERT)) + xhdrs) + *last_blk = i; + +out: + xlog_put_bp(bp); + return error; +} /* * Head is defined to be the point of the log where the next log write @@ -457,252 +527,257 @@ out: * 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) +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"); - } + xfs_buf_t *bp; + xfs_caddr_t offset; + 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"); + } - return 0; - } else if (error) { - xlog_warn("XFS: empty log check failed"); - return error; - } + 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; - } + first_blk = 0; /* get cycle # of 1st block */ + bp = xlog_get_bp(log, 1); + if (!bp) + return ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + offset = xlog_align(log, 0, 1, bp); + first_half_cycle = GET_CYCLE(offset, ARCH_CONVERT); - /* - * 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 = XLOG_TOTAL_REC_SHIFT(log); - if (head_blk >= num_scan_bblks) { - /* - * We are guaranteed that the entire check can be performed - * in one buffer. - */ - start_blk = head_blk - num_scan_bblks; - if ((error = xlog_find_verify_cycle(log, start_blk, num_scan_bblks, - stop_on_cycle, &new_blk))) - goto bp_err; - 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); - if ((error = xlog_find_verify_cycle(log, start_blk, - num_scan_bblks-(int)head_blk, (stop_on_cycle - 1), - &new_blk))) + last_blk = head_blk = log_bbnum - 1; /* get cycle # of last block */ + if ((error = xlog_bread(log, last_blk, 1, bp))) goto bp_err; - if (new_blk != -1) { - head_blk = new_blk; - goto bad_blk; + offset = xlog_align(log, last_blk, 1, bp); + last_half_cycle = GET_CYCLE(offset, 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; } /* - * 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. + * 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. */ - start_blk = 0; - ASSERT(head_blk <= INT_MAX); - if ((error = xlog_find_verify_cycle(log, start_blk, (int) head_blk, - stop_on_cycle, &new_blk))) - goto bp_err; - 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; - } + num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); + if (head_blk >= num_scan_bblks) { + /* + * We are guaranteed that the entire check can be performed + * in one buffer. + */ + start_blk = head_blk - num_scan_bblks; + if ((error = xlog_find_verify_cycle(log, + start_blk, num_scan_bblks, + stop_on_cycle, &new_blk))) + goto bp_err; + 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); + if ((error = xlog_find_verify_cycle(log, start_blk, + num_scan_bblks - (int)head_blk, + (stop_on_cycle - 1), &new_blk))) + goto bp_err; + 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); + if ((error = xlog_find_verify_cycle(log, + start_blk, (int)head_blk, + stop_on_cycle, &new_blk))) + goto bp_err; + 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 = XLOG_REC_SHIFT(log); + 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; + 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: + 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. @@ -721,13 +796,15 @@ bp_err: * available. */ int -xlog_find_tail(xlog_t *log, - xfs_daddr_t *head_blk, - xfs_daddr_t *tail_blk, - int readonly) +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_caddr_t offset = NULL; xfs_buf_t *bp; int error, i, found; xfs_daddr_t umount_data_blk; @@ -743,13 +820,14 @@ xlog_find_tail(xlog_t *log, if ((error = xlog_find_head(log, head_blk))) return error; - bp = xlog_get_bp(1,log->l_mp); + bp = xlog_get_bp(log, 1); 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) { + offset = xlog_align(log, 0, 1, bp); + if (GET_CYCLE(offset, ARCH_CONVERT) == 0) { *tail_blk = 0; /* leave all other log inited values alone */ goto exit; @@ -763,8 +841,9 @@ xlog_find_tail(xlog_t *log, for (i = (int)(*head_blk) - 1; i >= 0; i--) { if ((error = xlog_bread(log, i, 1, bp))) goto bread_err; + offset = xlog_align(log, i, 1, bp); if (XLOG_HEADER_MAGIC_NUM == - INT_GET(*(uint *)(XFS_BUF_PTR(bp)), ARCH_CONVERT)) { + INT_GET(*(uint *)offset, ARCH_CONVERT)) { found = 1; break; } @@ -779,8 +858,9 @@ xlog_find_tail(xlog_t *log, for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) { if ((error = xlog_bread(log, i, 1, bp))) goto bread_err; + offset = xlog_align(log, i, 1, bp); if (XLOG_HEADER_MAGIC_NUM == - INT_GET(*(uint*)(XFS_BUF_PTR(bp)), ARCH_CONVERT)) { + INT_GET(*(uint*)offset, ARCH_CONVERT)) { found = 2; break; } @@ -793,7 +873,7 @@ xlog_find_tail(xlog_t *log, } /* find blk_no of tail of log */ - rhead = (xlog_rec_header_t *)XFS_BUF_PTR(bp); + rhead = (xlog_rec_header_t *)offset; *tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT); /* @@ -853,7 +933,8 @@ xlog_find_tail(xlog_t *log, if ((error = xlog_bread(log, umount_data_blk, 1, bp))) { goto bread_err; } - op_head = (xlog_op_header_t *)XFS_BUF_PTR(bp); + offset = xlog_align(log, umount_data_blk, 1, bp); + op_head = (xlog_op_header_t *)offset; if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { /* * Set tail and last sync so that newly written @@ -868,7 +949,6 @@ xlog_find_tail(xlog_t *log, } } -#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 @@ -888,11 +968,9 @@ xlog_find_tail(xlog_t *log, * But... if the -device- itself is readonly, just skip this. * We can't recover this device anyway, so it won't matter. */ - - if (!is_read_only(log->l_mp->m_logdev_targp->pbr_kdev)) { + if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) { error = xlog_clear_stale_blocks(log, tail_lsn); } -#endif bread_err: exit: @@ -900,10 +978,8 @@ exit: if (error) xlog_warn("XFS: failed to locate log tail"); - return error; -} /* xlog_find_tail */ - +} /* * Is the log zeroed at all? @@ -922,22 +998,25 @@ exit: * >0 => error has occurred */ int -xlog_find_zeroed(struct log *log, - xfs_daddr_t *blk_no) +xlog_find_zeroed( + xlog_t *log, + xfs_daddr_t *blk_no) { xfs_buf_t *bp; + xfs_caddr_t offset; 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; /* check totally zeroed log */ - bp = xlog_get_bp(1,log->l_mp); + bp = xlog_get_bp(log, 1); 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); + offset = xlog_align(log, 0, 1, bp); + first_cycle = GET_CYCLE(offset, ARCH_CONVERT); if (first_cycle == 0) { /* completely zeroed log */ *blk_no = 0; xlog_put_bp(bp); @@ -947,7 +1026,8 @@ xlog_find_zeroed(struct log *log, /* 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); + offset = xlog_align(log, log_bbnum-1, 1, bp); + last_cycle = GET_CYCLE(offset, ARCH_CONVERT); if (last_cycle != 0) { /* log completely written to */ xlog_put_bp(bp); return 0; @@ -1008,67 +1088,106 @@ bp_err: if (error) return error; return -1; -} /* xlog_find_zeroed */ +} /* - * This is simply a subroutine used by xlog_clear_stale_blocks() below + * These are simple subroutines used by xlog_clear_stale_blocks() below * to initialize a buffer full of empty log record headers and write * them into the log. */ +STATIC void +xlog_add_record( + xlog_t *log, + xfs_caddr_t buf, + int cycle, + int block, + int tail_cycle, + int tail_block) +{ + xlog_rec_header_t *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, + XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); + ASSIGN_ANY_LSN(recp->h_lsn, cycle, block, ARCH_CONVERT); + ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT); + INT_SET(recp->h_fmt, ARCH_CONVERT, XLOG_FMT); + memcpy(&recp->h_fs_uuid, &log->l_mp->m_sb.sb_uuid, sizeof(uuid_t)); +} + STATIC int xlog_write_log_records( - xlog_t *log, - int cycle, - int start_block, - int blocks, - int tail_cycle, - int tail_block) -{ - xlog_rec_header_t *recp; - int i, j; - int end_block = start_block + blocks; - int error = 0; - xfs_buf_t *bp; - char *buf; - int bufblks; + xlog_t *log, + int cycle, + int start_block, + int blocks, + int tail_cycle, + int tail_block) +{ + xfs_caddr_t offset; + xfs_buf_t *bp; + int balign, ealign; + int sectbb = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1); + int end_block = start_block + blocks; + int bufblks; + int error = 0; + int i, j = 0; bufblks = 1 << ffs(blocks); - while (!(bp = xlog_get_bp(bufblks, log->l_mp))) { + while (!(bp = xlog_get_bp(log, bufblks))) { bufblks >>= 1; - if (!bufblks) + if (bufblks <= log->l_sectbb_log) return ENOMEM; } - 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, - XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); - ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT); + /* We may need to do a read at the start to fill in part of + * the buffer in the starting sector not covered by the first + * write below. + */ + balign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, start_block); + if (balign != start_block) { + if ((error = xlog_bread(log, start_block, 1, bp))) { + xlog_put_bp(bp); + return error; + } + j = start_block - balign; + } for (i = start_block; i < end_block; i += bufblks) { - int bcount = min(bufblks, end_block - start_block); - /* with plenty of memory, we duplicate the block - * right through the buffer and modify each entry - */ - ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT); - for (j = 1; j < bcount; j++) { - buf += BBSIZE; - recp = (xlog_rec_header_t*)buf; - memcpy(buf, XFS_BUF_PTR(bp), BBSIZE); - ASSIGN_ANY_LSN(recp->h_lsn, cycle, i+j, ARCH_CONVERT); - } - /* then write the whole lot out at once */ - error = xlog_bwrite(log, start_block, bcount, bp); - start_block += bcount; - buf = XFS_BUF_PTR(bp); - recp = (xlog_rec_header_t*)buf; + int bcount, endcount; + + bcount = min(bufblks, end_block - start_block); + endcount = bcount - j; + + /* We may need to do a read at the end to fill in part of + * the buffer in the final sector not covered by the write. + * If this is the same sector as the above read, skip it. + */ + ealign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, end_block); + if (j == 0 && (start_block + endcount > ealign)) { + offset = XFS_BUF_PTR(bp); + balign = BBTOB(ealign - start_block); + XFS_BUF_SET_PTR(bp, offset + balign, BBTOB(sectbb)); + if ((error = xlog_bread(log, ealign, sectbb, bp))) + break; + XFS_BUF_SET_PTR(bp, offset, bufblks); + } + + offset = xlog_align(log, start_block, endcount, bp); + for (; j < endcount; j++) { + xlog_add_record(log, offset, cycle, i+j, + tail_cycle, tail_block); + offset += BBSIZE; + } + error = xlog_bwrite(log, start_block, endcount, bp); + if (error) + break; + start_block += endcount; + j = 0; } xlog_put_bp(bp); - return error; } @@ -1212,10 +1331,11 @@ xlog_clear_stale_blocks( */ STATIC xlog_recover_t * -xlog_recover_find_tid(xlog_recover_t *q, - xlog_tid_t tid) +xlog_recover_find_tid( + xlog_recover_t *q, + xlog_tid_t tid) { - xlog_recover_t *p = q; + xlog_recover_t *p = q; while (p != NULL) { if (p->r_log_tid == tid) @@ -1223,42 +1343,43 @@ xlog_recover_find_tid(xlog_recover_t *q, p = p->r_next; } return p; -} /* xlog_recover_find_tid */ - +} STATIC void -xlog_recover_put_hashq(xlog_recover_t **q, - xlog_recover_t *trans) +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_add_item( + xlog_recover_item_t **itemq) { - xlog_recover_item_t *item; + 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_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; + 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; + ptr = (xfs_caddr_t) &trans->r_theader + + sizeof(xfs_trans_header_t) - len; memcpy(ptr, dp, len); /* d, s, l */ return 0; } @@ -1272,10 +1393,10 @@ xlog_recover_add_to_cont_trans(xlog_reco 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 +/* + * 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. @@ -1288,13 +1409,14 @@ xlog_recover_add_to_cont_trans(xlog_reco * 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; +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; @@ -1307,7 +1429,7 @@ xlog_recover_add_to_trans(xlog_recover_t return 0; } - ptr = kmem_alloc(len, 0); + ptr = kmem_alloc(len, KM_SLEEP); memcpy(ptr, dp, len); in_f = (xfs_inode_log_format_t *)ptr; @@ -1330,29 +1452,29 @@ xlog_recover_add_to_trans(xlog_recover_t 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_new_tid( + xlog_recover_t **q, + xlog_tid_t tid, + xfs_lsn_t lsn) { - xlog_recover_t *trans; + xlog_recover_t *trans; - trans = kmem_zalloc(sizeof(xlog_recover_t), 0); + trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP); 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_unlink_tid( + xlog_recover_t **q, + xlog_recover_t *trans) { - xlog_recover_t *tp; - int found = 0; + xlog_recover_t *tp; + int found = 0; ASSERT(trans != 0); if (trans == *q) { @@ -1375,11 +1497,12 @@ xlog_recover_unlink_tid(xlog_recover_t * 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) +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; @@ -1390,55 +1513,53 @@ xlog_recover_insert_item_backq(xlog_reco (*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_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_reorder_trans( + xlog_t *log, + xlog_recover_t *trans) { - xlog_recover_item_t *first_item, *itemq, *itemq_next; + 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( + 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 */ - + ASSERT(0); + return XFS_ERROR(EIO); + } + itemq = itemq_next; + } while (first_item != itemq); + return 0; +} /* * Build up the table of buf cancel records so that we don't replay @@ -1453,17 +1574,18 @@ xlog_recover_reorder_trans(xlog_t *log * record during the second pass. */ STATIC void -xlog_recover_do_buffer_pass1(xlog_t *log, - xfs_buf_log_format_t *buf_f) +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; + xfs_daddr_t blkno = 0; + uint len = 0; + ushort flags = 0; switch (buf_f->blf_type) { case XFS_LI_BUF: @@ -1483,9 +1605,8 @@ xlog_recover_do_buffer_pass1(xlog_t *l /* * If this isn't a cancel buffer item, then just return. */ - if (!(flags & XFS_BLI_CANCEL)) { + if (!(flags & XFS_BLI_CANCEL)) return; - } /* * Insert an xfs_buf_cancel record into the hash table of @@ -1499,8 +1620,8 @@ xlog_recover_do_buffer_pass1(xlog_t *l * the bucket. */ if (*bucket == NULL) { - bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t), - KM_SLEEP); + 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; @@ -1525,8 +1646,8 @@ xlog_recover_do_buffer_pass1(xlog_t *l nextp = nextp->bc_next; } ASSERT(prevp != NULL); - bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t), - KM_SLEEP); + 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; @@ -1548,17 +1669,17 @@ xlog_recover_do_buffer_pass1(xlog_t *l * made at that point. */ STATIC int -xlog_recover_do_buffer_pass2(xlog_t *log, - xfs_buf_log_format_t *buf_f) +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; - + xfs_daddr_t blkno = 0; + ushort flags = 0; + uint len = 0; switch (buf_f->blf_type) { case XFS_LI_BUF: @@ -1635,7 +1756,6 @@ xlog_recover_do_buffer_pass2(xlog_t *l return 0; } - /* * Perform recovery for a buffer full of inodes. In these buffers, * the only data which should be recovered is that which corresponds @@ -1650,10 +1770,11 @@ xlog_recover_do_buffer_pass2(xlog_t *l * 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) +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; @@ -1666,8 +1787,8 @@ xlog_recover_do_inode_buffer(xfs_mount_t 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; + unsigned int *data_map = NULL; + unsigned int map_size = 0; switch (buf_f->blf_type) { case XFS_LI_BUF: @@ -1758,7 +1879,7 @@ xlog_recover_do_inode_buffer(xfs_mount_t } return 0; -} /* xlog_recover_do_inode_buffer */ +} /* * Perform a 'normal' buffer recovery. Each logged region of the @@ -1768,17 +1889,18 @@ xlog_recover_do_inode_buffer(xfs_mount_t */ /*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) +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; + unsigned int *data_map = NULL; + unsigned int map_size = 0; int error; switch (buf_f->blf_type) { @@ -1828,7 +1950,7 @@ xlog_recover_do_reg_buffer(xfs_mount_t /* Shouldn't be any more regions */ ASSERT(i == item->ri_total); -} /* xlog_recover_do_reg_buffer */ +} /* * Do some primitive error checking on ondisk dquot data structures. @@ -1959,7 +2081,7 @@ xlog_recover_do_dquot_buffer( xfs_buf_t *bp, xfs_buf_log_format_t *buf_f) { - uint type; + uint type; /* * Filesystems are required to send in quota flags at mount time. @@ -2006,9 +2128,10 @@ xlog_recover_do_dquot_buffer( * 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) +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; @@ -2043,19 +2166,19 @@ xlog_recover_do_buffer_trans(xlog_t *l } } switch (buf_f->blf_type) { - case XFS_LI_BUF: + 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: + 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: + 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); @@ -2120,12 +2243,13 @@ xlog_recover_do_buffer_trans(xlog_t *l } return (error); -} /* xlog_recover_do_buffer_trans */ +} STATIC int -xlog_recover_do_inode_trans(xlog_t *log, - xlog_recover_item_t *item, - int pass) +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; @@ -2202,6 +2326,26 @@ xlog_recover_do_inode_trans(xlog_t *log XFS_ERRLEVEL_LOW, mp); return XFS_ERROR(EFSCORRUPTED); } + + /* Skip replay when the on disk inode is newer than the log one */ + if (dicp->di_flushiter < + INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT)) { + /* + * Deal with the wrap case, DI_MAX_FLUSH is less + * than smaller numbers + */ + if ((INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT) + == DI_MAX_FLUSH) && + (dicp->di_flushiter < (DI_MAX_FLUSH>>1))) { + /* do nothing */ + } else { + xfs_buf_relse(bp); + return 0; + } + } + /* Take the opportunity to reset the flush iteration count */ + dicp->di_flushiter = 0; + if (unlikely((dicp->di_mode & IFMT) == IFREG)) { if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && (dicp->di_format != XFS_DINODE_FMT_BTREE)) { @@ -2345,7 +2489,6 @@ xlog_recover_do_inode_trans(xlog_t *log } } - write_inode_buffer: if (ITEM_TYPE(item) == XFS_LI_INODE) { ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || @@ -2359,8 +2502,7 @@ write_inode_buffer: } return (error); -} /* xlog_recover_do_inode_trans */ - +} /* * Recover QUOTAOFF records. We simply make a note of it in the xlog_t @@ -2368,11 +2510,12 @@ write_inode_buffer: * of that type. */ STATIC int -xlog_recover_do_quotaoff_trans(xlog_t *log, - xlog_recover_item_t *item, - int pass) +xlog_recover_do_quotaoff_trans( + xlog_t *log, + xlog_recover_item_t *item, + int pass) { - xfs_qoff_logformat_t *qoff_f; + xfs_qoff_logformat_t *qoff_f; if (pass == XLOG_RECOVER_PASS2) { return (0); @@ -2393,14 +2536,14 @@ xlog_recover_do_quotaoff_trans(xlog_t return (0); } - /* * Recover a dquot record */ STATIC int -xlog_recover_do_dquot_trans(xlog_t *log, - xlog_recover_item_t *item, - int pass) +xlog_recover_do_dquot_trans( + xlog_t *log, + xlog_recover_item_t *item, + int pass) { xfs_mount_t *mp; xfs_buf_t *bp; @@ -2484,7 +2627,7 @@ xlog_recover_do_dquot_trans(xlog_t *log xfs_bdwrite(mp, bp); return (0); -} /* xlog_recover_do_dquot_trans */ +} /* * This routine is called to create an in-core extent free intent @@ -2494,10 +2637,11 @@ xlog_recover_do_dquot_trans(xlog_t *log * LSN. */ STATIC void -xlog_recover_do_efi_trans(xlog_t *log, - xlog_recover_item_t *item, - xfs_lsn_t lsn, - int pass) +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; @@ -2526,7 +2670,7 @@ xlog_recover_do_efi_trans(xlog_t *log, * xfs_trans_update_ail() drops the AIL lock. */ xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s); -} /* xlog_recover_do_efi_trans */ +} /* @@ -2538,13 +2682,14 @@ xlog_recover_do_efi_trans(xlog_t *log, * AIL and free it. */ STATIC void -xlog_recover_do_efd_trans(xlog_t *log, - xlog_recover_item_t *item, - int pass) +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_efi_log_item_t *efip = NULL; xfs_log_item_t *lip; int gen; int nexts; @@ -2597,9 +2742,9 @@ xlog_recover_do_efd_trans(xlog_t *log, ((nexts - 1) * sizeof(xfs_extent_t))); } else { kmem_zone_free(xfs_efi_zone, efip); + } } - } -} /* xlog_recover_do_efd_trans */ +} /* * Perform the transaction @@ -2608,12 +2753,13 @@ xlog_recover_do_efd_trans(xlog_t *log, * 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) +xlog_recover_do_trans( + xlog_t *log, + xlog_recover_t *trans, + int pass) { - int error = 0; - xlog_recover_item_t *item, *first_item; + int error = 0; + xlog_recover_item_t *item, *first_item; if ((error = xlog_recover_reorder_trans(log, trans))) return error; @@ -2663,8 +2809,7 @@ xlog_recover_do_trans(xlog_t *log, } while (first_item != item); return error; -} /* xlog_recover_do_trans */ - +} /* * Free up any resources allocated by the transaction @@ -2672,10 +2817,11 @@ xlog_recover_do_trans(xlog_t *log, * Remember that EFIs, EFDs, and IUNLINKs are handled later. */ STATIC void -xlog_recover_free_trans(xlog_recover_t *trans) +xlog_recover_free_trans( + xlog_recover_t *trans) { - xlog_recover_item_t *first_item, *item, *free_item; - int i; + xlog_recover_item_t *first_item, *item, *free_item; + int i; item = first_item = trans->r_itemq; do { @@ -2693,16 +2839,16 @@ xlog_recover_free_trans(xlog_recover_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) +xlog_recover_commit_trans( + xlog_t *log, + xlog_recover_t **q, + xlog_recover_t *trans, + int pass) { - int error; + int error; if ((error = xlog_recover_unlink_tid(q, trans))) return error; @@ -2710,18 +2856,16 @@ xlog_recover_commit_trans(xlog_t *log, 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) +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 */ - + return 0; +} /* * There are two valid states of the r_state field. 0 indicates that the @@ -2733,97 +2877,101 @@ xlog_recover_unmount_trans(xlog_recover_ * 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) && num_logops) { - 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; +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; + int num_logops; + xlog_op_header_t *ohead; + xlog_recover_t *trans; + xlog_tid_t tid; + int error; + unsigned long hash; + uint flags; + + lp = dp + INT_GET(rhead->h_len, ARCH_CONVERT); + num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT); + + /* 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) && num_logops) { + 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)); } - default: { - xlog_warn("XFS: xlog_recover_process_data: bad flag"); - ASSERT(0); - error = XFS_ERROR(EIO); - break; + 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; + } + if (error) + return error; } - } /* switch */ - if (error) - return error; - } /* if */ - dp += INT_GET(ohead->oh_len, ARCH_CONVERT); - num_logops--; - } - return( 0 ); -} /* xlog_recover_process_data */ - + dp += INT_GET(ohead->oh_len, ARCH_CONVERT); + num_logops--; + } + return 0; +} /* * 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) +xlog_recover_process_efi( + xfs_mount_t *mp, + xfs_efi_log_item_t *efip) { xfs_efd_log_item_t *efdp; xfs_trans_t *tp; @@ -2868,8 +3016,7 @@ xlog_recover_process_efi(xfs_mount_t *m 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 @@ -2877,13 +3024,13 @@ xlog_recover_process_efi(xfs_mount_t *m */ #if defined(DEBUG) STATIC void -xlog_recover_check_ail(xfs_mount_t *mp, - xfs_log_item_t *lip, - int gen) +xlog_recover_check_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip, + int gen) { - int orig_gen; + int orig_gen = gen; - orig_gen = gen; do { ASSERT(lip->li_type != XFS_LI_EFI); lip = xfs_trans_next_ail(mp, lip, &gen, NULL); @@ -2898,7 +3045,6 @@ xlog_recover_check_ail(xfs_mount_t *mp, } #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 @@ -2918,7 +3064,8 @@ xlog_recover_check_ail(xfs_mount_t *mp, * we see something other than an EFI in the AIL. */ STATIC void -xlog_recover_process_efis(xlog_t *log) +xlog_recover_process_efis( + xlog_t *log) { xfs_log_item_t *lip; xfs_efi_log_item_t *efip; @@ -2954,8 +3101,7 @@ xlog_recover_process_efis(xlog_t *log) lip = xfs_trans_next_ail(mp, lip, &gen, NULL); } AIL_UNLOCK(mp, s); -} /* xlog_recover_process_efis */ - +} /* * This routine performs a transaction to null out a bad inode pointer @@ -2998,8 +3144,7 @@ xlog_recover_clear_agi_bucket( (offset + sizeof(xfs_agino_t) - 1)); (void) xfs_trans_commit(tp, 0, NULL); -} /* xlog_recover_clear_agi_bucket */ - +} /* * xlog_iunlink_recover @@ -3014,7 +3159,8 @@ xlog_recover_clear_agi_bucket( * atomic. */ void -xlog_recover_process_iunlinks(xlog_t *log) +xlog_recover_process_iunlinks( + xlog_t *log) { xfs_mount_t *mp; xfs_agnumber_t agno; @@ -3156,40 +3302,47 @@ xlog_recover_process_iunlinks(xlog_t *lo } mp->m_dmevmask = mp_dmevmask; +} -} /* 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, j, k; - int size = iclog->ic_offset + iclog->ic_roundoff; - xfs_caddr_t dp; - union ich { - xlog_rec_ext_header_t hic_xheader; - char hic_sector[XLOG_HEADER_SIZE]; - } *xhdr; - uint cycle_lsn; #ifdef DEBUG - uint *up; - uint chksum = 0; +STATIC void +xlog_pack_data_checksum( + xlog_t *log, + xlog_in_core_t *iclog, + int size) +{ + int i; + uint *up; + uint chksum = 0; up = (uint *)iclog->ic_datap; /* divide length by 4 to get # words */ - for (i=0; i> 2; i++) { + for (i = 0; i < (size >> 2); i++) { chksum ^= INT_GET(*up, ARCH_CONVERT); up++; } INT_SET(iclog->ic_header.h_chksum, ARCH_CONVERT, chksum); -#endif /* DEBUG */ +} +#else +#define xlog_pack_data_checksum(log, iclog, size) +#endif + +/* + * Stamp cycle number in every block + */ +void +xlog_pack_data( + xlog_t *log, + xlog_in_core_t *iclog) +{ + int i, j, k; + int size = iclog->ic_offset + iclog->ic_roundoff; + uint cycle_lsn; + xfs_caddr_t dp; + xlog_in_core_2_t *xhdr; + + xlog_pack_data_checksum(log, iclog, size); cycle_lsn = CYCLE_LSN_NOCONV(iclog->ic_header.h_lsn, ARCH_CONVERT); @@ -3202,7 +3355,7 @@ xlog_pack_data(xlog_t *log, xlog_in_core } if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - xhdr = (union ich*)&iclog->ic_header; + xhdr = (xlog_in_core_2_t *)&iclog->ic_header; for ( ; i < BTOBB(size); i++) { j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); @@ -3215,45 +3368,18 @@ xlog_pack_data(xlog_t *log, xlog_in_core xhdr[i].hic_xheader.xh_cycle = cycle_lsn; } } - -} /* xlog_pack_data */ - - -/*ARGSUSED*/ -STATIC void -xlog_unpack_data(xlog_rec_header_t *rhead, - xfs_caddr_t dp, - xlog_t *log) -{ - int i, j, k; - union ich { - xlog_rec_header_t hic_header; - xlog_rec_ext_header_t hic_xheader; - char hic_sector[XLOG_HEADER_SIZE]; - } *xhdr; +} #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) - uint *up = (uint *)dp; - uint chksum = 0; -#endif - - for (i=0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) && - i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { - *(uint *)dp = *(uint *)&rhead->h_cycle_data[i]; - dp += BBSIZE; - } - - if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - xhdr = (union ich*)rhead; - for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) { - j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - *(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; - dp += BBSIZE; - } - } +STATIC void +xlog_unpack_data_checksum( + xlog_rec_header_t *rhead, + xfs_caddr_t dp, + xlog_t *log) +{ + uint *up = (uint *)dp; + uint chksum = 0; -#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); @@ -3274,9 +3400,77 @@ xlog_unpack_data(xlog_rec_header_t *rhea log->l_flags |= XLOG_CHKSUM_MISMATCH; } } -#endif /* DEBUG && XFS_LOUD_RECOVERY */ -} /* xlog_unpack_data */ +} +#else +#define xlog_unpack_data_checksum(rhead, dp, log) +#endif + +STATIC void +xlog_unpack_data( + xlog_rec_header_t *rhead, + xfs_caddr_t dp, + xlog_t *log) +{ + int i, j, k; + xlog_in_core_2_t *xhdr; + + for (i = 0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) && + i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { + *(uint *)dp = *(uint *)&rhead->h_cycle_data[i]; + dp += BBSIZE; + } + + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + xhdr = (xlog_in_core_2_t *)rhead; + for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) { + j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + *(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; + dp += BBSIZE; + } + } + + xlog_unpack_data_checksum(rhead, dp, log); +} + +STATIC int +xlog_valid_rec_header( + xlog_t *log, + xlog_rec_header_t *rhead, + xfs_daddr_t blkno) +{ + int bblks; + + if (unlikely( + (INT_GET(rhead->h_magicno, ARCH_CONVERT) != + XLOG_HEADER_MAGIC_NUM))) { + XFS_ERROR_REPORT("xlog_valid_rec_header(1)", + XFS_ERRLEVEL_LOW, log->l_mp); + return XFS_ERROR(EFSCORRUPTED); + } + if (unlikely( + (INT_ISZERO(rhead->h_version, ARCH_CONVERT) || + (INT_GET(rhead->h_version, ARCH_CONVERT) & + (~XLOG_VERSION_OKBITS)) != 0))) { + xlog_warn("XFS: %s: unrecognised log version (%d).", + __FUNCTION__, INT_GET(rhead->h_version, ARCH_CONVERT)); + return XFS_ERROR(EIO); + } + /* LR body must have data or it wouldn't have been written */ + bblks = INT_GET(rhead->h_len, ARCH_CONVERT); + if (unlikely( bblks <= 0 || bblks > INT_MAX )) { + XFS_ERROR_REPORT("xlog_valid_rec_header(2)", + XFS_ERRLEVEL_LOW, log->l_mp); + return XFS_ERROR(EFSCORRUPTED); + } + if (unlikely( blkno > log->l_logBBsize || blkno > INT_MAX )) { + XFS_ERROR_REPORT("xlog_valid_rec_header(3)", + XFS_ERRLEVEL_LOW, log->l_mp); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} /* * Read the log from tail to head and process the log records found. @@ -3287,223 +3481,246 @@ xlog_unpack_data(xlog_rec_header_t *rhea * 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, h_size; - int bblks, split_bblks; - int hblks, split_hblks, wrapped_hblks; - xlog_recover_t *rhash[XLOG_RHASH_SIZE]; - - error = 0; - - - /* - * Read the header of the tail block and get the iclog buffer size from - * h_size. Use this to tell how many sectors make up the log header. - */ - if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - /* - * When using variable length iclogs, read first sector of iclog - * header and extract the header size from it. Get a new hbp that - * is the correct size. - */ - hbp = xlog_get_bp(1, log->l_mp); - if (!hbp) - return ENOMEM; - if ((error = xlog_bread(log, tail_blk, 1, hbp))) - goto bread_err1; - rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); - ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == - XLOG_HEADER_MAGIC_NUM); - if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) { - xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number."); - error = XFS_ERROR(EIO); - goto bread_err1; - } - h_size = INT_GET(rhead->h_size, ARCH_CONVERT); +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, offset; + xfs_buf_t *hbp, *dbp; + int error = 0, h_size; + int bblks, split_bblks; + int hblks, split_hblks, wrapped_hblks; + xlog_recover_t *rhash[XLOG_RHASH_SIZE]; + + ASSERT(head_blk != tail_blk); - if ((INT_GET(rhead->h_version, ARCH_CONVERT) & XLOG_VERSION_2) && - (h_size > XLOG_HEADER_CYCLE_SIZE)) { - hblks = h_size / XLOG_HEADER_CYCLE_SIZE; - if (h_size % XLOG_HEADER_CYCLE_SIZE) - hblks++; - xlog_put_bp(hbp); - hbp = xlog_get_bp(hblks, log->l_mp); + /* + * Read the header of the tail block and get the iclog buffer size from + * h_size. Use this to tell how many sectors make up the log header. + */ + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + /* + * When using variable length iclogs, read first sector of + * iclog header and extract the header size from it. Get a + * new hbp that is the correct size. + */ + hbp = xlog_get_bp(log, 1); + if (!hbp) + return ENOMEM; + if ((error = xlog_bread(log, tail_blk, 1, hbp))) + goto bread_err1; + offset = xlog_align(log, tail_blk, 1, hbp); + rhead = (xlog_rec_header_t *)offset; + error = xlog_valid_rec_header(log, rhead, tail_blk); + if (error) + goto bread_err1; + h_size = INT_GET(rhead->h_size, ARCH_CONVERT); + if ((INT_GET(rhead->h_version, ARCH_CONVERT) + & XLOG_VERSION_2) && + (h_size > XLOG_HEADER_CYCLE_SIZE)) { + hblks = h_size / XLOG_HEADER_CYCLE_SIZE; + if (h_size % XLOG_HEADER_CYCLE_SIZE) + hblks++; + xlog_put_bp(hbp); + hbp = xlog_get_bp(log, hblks); + } else { + hblks = 1; + } } else { - hblks=1; + ASSERT(log->l_sectbb_log == 0); + hblks = 1; + hbp = xlog_get_bp(log, 1); + h_size = XLOG_BIG_RECORD_BSIZE; } - } else { - hblks=1; - hbp = xlog_get_bp(1, log->l_mp); - h_size = XLOG_BIG_RECORD_BSIZE; - } - - if (!hbp) - return ENOMEM; - dbp = xlog_get_bp(BTOBB(h_size),log->l_mp); - if (!dbp) { - xlog_put_bp(hbp); - return ENOMEM; - } - - memset(rhash, 0, sizeof(rhash)); - if (tail_blk <= head_blk) { - for (blk_no = tail_blk; blk_no < head_blk; ) { - if ((error = xlog_bread(log, blk_no, hblks, hbp))) - goto bread_err2; - 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 (unlikely((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))) { - XFS_ERROR_REPORT("xlog_do_recovery_pass(1)", - XFS_ERRLEVEL_LOW, log->l_mp); - error = EFSCORRUPTED; - goto bread_err2; - } - if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) { - xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number."); - error = XFS_ERROR(EIO); - goto bread_err2; - } - bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); /* blocks in data section */ - if (bblks > 0) { - if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp))) - goto bread_err2; - 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_err2; - } - blk_no += (bblks+hblks); + if (!hbp) + return ENOMEM; + dbp = xlog_get_bp(log, BTOBB(h_size)); + if (!dbp) { + xlog_put_bp(hbp); + return ENOMEM; } - } 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) { - /* - * Check for header wrapping around physical end-of-log - */ - wrapped_hblks = 0; - if (blk_no+hblks <= log->l_logBBsize) { - /* Read header in one read */ - if ((error = xlog_bread(log, blk_no, hblks, hbp))) - goto bread_err2; - } else { - /* This log record is split across physical end of log */ - split_hblks = 0; - if (blk_no != log->l_logBBsize) { - /* some data is before physical end of log */ - ASSERT(blk_no <= INT_MAX); - split_hblks = log->l_logBBsize - (int)blk_no; - ASSERT(split_hblks > 0); - if ((error = xlog_bread(log, blk_no, split_hblks, hbp))) - goto bread_err2; - } - bufaddr = XFS_BUF_PTR(hbp); - XFS_BUF_SET_PTR(hbp, bufaddr + BBTOB(split_hblks), - BBTOB(hblks - split_hblks)); - wrapped_hblks = hblks - split_hblks; - if ((error = xlog_bread(log, 0, wrapped_hblks, hbp))) - goto bread_err2; - XFS_BUF_SET_PTR(hbp, bufaddr, hblks); - } - 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 += hblks; /* successfully read header */ - - if (unlikely((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) || - (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) || - (bblks <= 0))) { - XFS_ERROR_REPORT("xlog_do_recovery_pass(2)", - XFS_ERRLEVEL_LOW, log->l_mp); - error = EFSCORRUPTED; - goto bread_err2; - } - /* Read in data for log record */ - if (blk_no+bblks <= log->l_logBBsize) { - if ((error = xlog_bread(log, blk_no, bblks, dbp))) - goto bread_err2; - } 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_err2; - } - bufaddr = XFS_BUF_PTR(dbp); - XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks), - BBTOB(bblks - split_bblks)); - if ((error = xlog_bread(log, wrapped_hblks, - bblks - split_bblks, dbp))) - goto bread_err2; - XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_BIG_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_err2; - 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, hblks, hbp))) - goto bread_err2; - 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+hblks, bblks, dbp))) - goto bread_err2; - 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_err2; - blk_no += (bblks+hblks); - } - } - -bread_err2: - xlog_put_bp(dbp); -bread_err1: - xlog_put_bp(hbp); + memset(rhash, 0, sizeof(rhash)); + if (tail_blk <= head_blk) { + for (blk_no = tail_blk; blk_no < head_blk; ) { + if ((error = xlog_bread(log, blk_no, hblks, hbp))) + goto bread_err2; + offset = xlog_align(log, blk_no, hblks, hbp); + rhead = (xlog_rec_header_t *)offset; + error = xlog_valid_rec_header(log, rhead, blk_no); + if (error) + goto bread_err2; + + /* blocks in data section */ + bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + error = xlog_bread(log, blk_no + hblks, bblks, dbp); + if (error) + goto bread_err2; + offset = xlog_align(log, blk_no + hblks, bblks, dbp); + xlog_unpack_data(rhead, offset, log); + if ((error = xlog_recover_process_data(log, + rhash, rhead, offset, pass))) + goto bread_err2; + blk_no += bblks + hblks; + } + } 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) { + /* + * Check for header wrapping around physical end-of-log + */ + offset = NULL; + split_hblks = 0; + wrapped_hblks = 0; + if (blk_no + hblks <= log->l_logBBsize) { + /* Read header in one read */ + error = xlog_bread(log, blk_no, hblks, hbp); + if (error) + goto bread_err2; + offset = xlog_align(log, blk_no, hblks, hbp); + } else { + /* This LR is split across physical log end */ + if (blk_no != log->l_logBBsize) { + /* some data before physical log end */ + ASSERT(blk_no <= INT_MAX); + split_hblks = log->l_logBBsize - (int)blk_no; + ASSERT(split_hblks > 0); + if ((error = xlog_bread(log, blk_no, + split_hblks, hbp))) + goto bread_err2; + offset = xlog_align(log, blk_no, + split_hblks, hbp); + } + /* + * Note: this black magic still works with + * large sector sizes (non-512) only because: + * - we increased the buffer size originally + * by 1 sector giving us enough extra space + * for the second read; + * - the log start is guaranteed to be sector + * aligned; + * - we read the log end (LR header start) + * _first_, then the log start (LR header end) + * - order is important. + */ + bufaddr = XFS_BUF_PTR(hbp); + XFS_BUF_SET_PTR(hbp, + bufaddr + BBTOB(split_hblks), + BBTOB(hblks - split_hblks)); + wrapped_hblks = hblks - split_hblks; + error = xlog_bread(log, 0, wrapped_hblks, hbp); + if (error) + goto bread_err2; + XFS_BUF_SET_PTR(hbp, bufaddr, hblks); + if (!offset) + offset = xlog_align(log, 0, + wrapped_hblks, hbp); + } + rhead = (xlog_rec_header_t *)offset; + error = xlog_valid_rec_header(log, rhead, + split_hblks ? blk_no : 0); + if (error) + goto bread_err2; + + bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + blk_no += hblks; + + /* Read in data for log record */ + if (blk_no + bblks <= log->l_logBBsize) { + error = xlog_bread(log, blk_no, bblks, dbp); + if (error) + goto bread_err2; + offset = xlog_align(log, blk_no, bblks, dbp); + } else { + /* This log record is split across the + * physical end of log */ + offset = NULL; + split_bblks = 0; + if (blk_no != log->l_logBBsize) { + /* some data is before the physical + * end of log */ + ASSERT(!wrapped_hblks); + 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_err2; + offset = xlog_align(log, blk_no, + split_bblks, dbp); + } + /* + * Note: this black magic still works with + * large sector sizes (non-512) only because: + * - we increased the buffer size originally + * by 1 sector giving us enough extra space + * for the second read; + * - the log start is guaranteed to be sector + * aligned; + * - we read the log end (LR header start) + * _first_, then the log start (LR header end) + * - order is important. + */ + bufaddr = XFS_BUF_PTR(dbp); + XFS_BUF_SET_PTR(dbp, + bufaddr + BBTOB(split_bblks), + BBTOB(bblks - split_bblks)); + if ((error = xlog_bread(log, wrapped_hblks, + bblks - split_bblks, dbp))) + goto bread_err2; + XFS_BUF_SET_PTR(dbp, bufaddr, + XLOG_BIG_RECORD_BSIZE); + if (!offset) + offset = xlog_align(log, wrapped_hblks, + bblks - split_bblks, dbp); + } + xlog_unpack_data(rhead, offset, log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, offset, pass))) + goto bread_err2; + 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, hblks, hbp))) + goto bread_err2; + offset = xlog_align(log, blk_no, hblks, hbp); + rhead = (xlog_rec_header_t *)offset; + error = xlog_valid_rec_header(log, rhead, blk_no); + if (error) + goto bread_err2; + bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp))) + goto bread_err2; + offset = xlog_align(log, blk_no+hblks, bblks, dbp); + xlog_unpack_data(rhead, offset, log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, offset, pass))) + goto bread_err2; + blk_no += bblks + hblks; + } + } - return error; + bread_err2: + xlog_put_bp(dbp); + bread_err1: + xlog_put_bp(hbp); + return error; } /* @@ -3520,14 +3737,14 @@ bread_err1: * 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) +xlog_do_log_recovery( + xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk) { int error; -#ifdef DEBUG - int i; -#endif + + ASSERT(head_blk != tail_blk); /* * First do a pass to find all of the cancelled buf log items. @@ -3551,11 +3768,15 @@ xlog_do_log_recovery(xlog_t *log, */ 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); +#ifdef DEBUG + { + int i; + + 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; @@ -3567,9 +3788,10 @@ xlog_do_log_recovery(xlog_t *log, * Do the actual recovery */ STATIC int -xlog_do_recover(xlog_t *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk) +xlog_do_recover( + xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk) { int error; xfs_buf_t *bp; @@ -3631,7 +3853,7 @@ xlog_do_recover(xlog_t *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. @@ -3639,22 +3861,18 @@ xlog_do_recover(xlog_t *log, * Return error or zero. */ int -xlog_recover(xlog_t *log, int readonly) +xlog_recover( + xlog_t *log, + int readonly) { - xfs_daddr_t head_blk, tail_blk; - int error; + 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 @@ -3666,36 +3884,21 @@ xlog_recover(xlog_t *log, int readonly) * under the vfs layer, so we can get away with it unless * the device itself is read-only, in which case we fail. */ -#ifdef __KERNEL__ if ((error = xfs_dev_is_read_only(log->l_mp, "recovery required"))) { return error; } -#else - if (readonly) { - 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; } return error; -} /* xlog_recover */ - +} /* * In the first part of recovery we replay inodes and buffers and build @@ -3707,7 +3910,9 @@ xlog_recover(xlog_t *log, int readonly) * in the real-time portion of the file system. */ int -xlog_recover_finish(xlog_t *log, int mfsi_flags) +xlog_recover_finish( + xlog_t *log, + int mfsi_flags) { /* * Now we're ready to do the transactions needed for the @@ -3729,23 +3934,16 @@ xlog_recover_finish(xlog_t *log, int mfs (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_DEBUG, @@ -3753,7 +3951,7 @@ xlog_recover_finish(xlog_t *log, int mfs log->l_mp->m_fsname); } return 0; -} /* xlog_recover_finish */ +} #if defined(DEBUG) @@ -3762,7 +3960,8 @@ xlog_recover_finish(xlog_t *log, int mfs * are consistent with the superblock counters. */ void -xlog_recover_check_summary(xlog_t *log) +xlog_recover_check_summary( + xlog_t *log) { xfs_mount_t *mp; xfs_agf_t *agfp; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_mac.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_mac.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_mac.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_mac.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" static xfs_mac_label_t *mac_low_high_lp; static xfs_mac_label_t *mac_high_low_lp; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_macros.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_macros.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_macros.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_macros.c 2003-08-17 21:26:18.000000000 +0200 @@ -32,8 +32,40 @@ #define XFS_MACRO_C -#include - +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_ialloc.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_rw.h" +#include "xfs_log_priv.h" +#include "xfs_da_btree.h" +#include "xfs_attr_leaf.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_bit.h" #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_ISNULLDSTARTBLOCK) int diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_mount.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_mount.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_mount.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_mount.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,7 +30,36 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_rtalloc.h" +#include "xfs_bmap.h" +#include "xfs_error.h" +#include "xfs_bit.h" +#include "xfs_rw.h" +#include "xfs_quota.h" +#include "xfs_fsops.h" STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); STATIC int xfs_uuid_mount(xfs_mount_t *); @@ -438,7 +467,11 @@ xfs_readsb(xfs_mount_t *mp) bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size), extra_flags); - ASSERT(bp); + if (!bp || XFS_BUF_ISERROR(bp)) { + cmn_err(CE_WARN, "XFS: SB read failed"); + error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM; + goto fail; + } ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); @@ -453,9 +486,7 @@ xfs_readsb(xfs_mount_t *mp) error = xfs_mount_validate_sb(mp, &(mp->m_sb)); if (error) { cmn_err(CE_WARN, "XFS: SB validate failed"); - XFS_BUF_UNMANAGE(bp); - xfs_buf_relse(bp); - return error; + goto fail; } /* @@ -465,9 +496,8 @@ xfs_readsb(xfs_mount_t *mp) cmn_err(CE_WARN, "XFS: device supports only %u byte sectors (not %u)", sector_size, mp->m_sb.sb_sectsize); - XFS_BUF_UNMANAGE(bp); - xfs_buf_relse(bp); - return XFS_ERROR(ENOSYS); + error = ENOSYS; + goto fail; } /* @@ -480,7 +510,11 @@ xfs_readsb(xfs_mount_t *mp) sector_size = mp->m_sb.sb_sectsize; bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size), extra_flags); - ASSERT(bp); + if (!bp || XFS_BUF_ISERROR(bp)) { + cmn_err(CE_WARN, "XFS: SB re-read failed"); + error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM; + goto fail; + } ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); } @@ -489,6 +523,13 @@ xfs_readsb(xfs_mount_t *mp) xfs_buf_relse(bp); ASSERT(XFS_BUF_VALUSEMA(bp) > 0); return 0; + + fail: + if (bp) { + XFS_BUF_UNMANAGE(bp); + xfs_buf_relse(bp); + } + return error; } @@ -517,16 +558,7 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb mp->m_blockmask = sbp->sb_blocksize - 1; mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; mp->m_blockwmask = mp->m_blockwsize - 1; - - - if (XFS_SB_VERSION_HASLOGV2(sbp)) { - if (sbp->sb_logsunit <= 1) { - mp->m_lstripemask = 1; - } else { - mp->m_lstripemask = - 1 << xfs_highbit32(sbp->sb_logsunit >> BBSHIFT); - } - } + INIT_LIST_HEAD(&mp->m_del_inodes); /* * Setup for attributes, in case they get created. @@ -573,8 +605,6 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; } -extern void xfs_refcache_sbdirty(struct super_block*); - /* * xfs_mountfs * @@ -591,7 +621,6 @@ int xfs_mountfs( vfs_t *vfsp, xfs_mount_t *mp, - dev_t dev, int mfsi_flags) { xfs_buf_t *bp; @@ -604,11 +633,10 @@ xfs_mountfs( __uint64_t ret64; __int64_t update_flags; uint quotamount, quotaflags; - int agno, noio; + int agno; int uuid_mounted = 0; int error = 0; - noio = dev == 0 && mp->m_sb_bp != NULL; if (mp->m_sb_bp == NULL) { if ((error = xfs_readsb(mp))) { return (error); @@ -701,6 +729,8 @@ xfs_mountfs( } else mp->m_maxicount = 0; + mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog); + /* * XFS uses the uuid from the superblock as the unique * identifier for fsid. We can not use the uuid from the volume @@ -797,22 +827,20 @@ xfs_mountfs( error = XFS_ERROR(E2BIG); goto error1; } - if (!noio) { - error = xfs_read_buf(mp, mp->m_ddev_targp, - d - XFS_FSS_TO_BB(mp, 1), - XFS_FSS_TO_BB(mp, 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; + error = xfs_read_buf(mp, mp->m_ddev_targp, + d - XFS_FSS_TO_BB(mp, 1), + XFS_FSS_TO_BB(mp, 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) && + if (((mfsi_flags & XFS_MFSI_CLIENT) == 0) && mp->m_logdev_targp != mp->m_ddev_targp) { 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) { @@ -850,13 +878,6 @@ xfs_mountfs( } /* - * Set up timer list structure for nfs refcache - */ - init_timer(&mp->m_sbdirty_timer); - mp->m_sbdirty_timer.function = - (void (*)(unsigned long)) xfs_refcache_sbdirty; - - /* * Copies the low order bits of the timestamp and the randomly * set "sequence" number out of a UUID. */ @@ -896,10 +917,6 @@ xfs_mountfs( * 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 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_mount.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_mount.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_mount.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_mount.h 2003-08-17 21:26:19.000000000 +0200 @@ -68,6 +68,7 @@ typedef struct xfs_trans_reservations { ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks)) #else struct cred; +struct log; struct vfs; struct vnode; struct xfs_mount_args; @@ -79,7 +80,6 @@ struct xfs_iocore; struct xfs_bmbt_irec; struct xfs_bmap_free; -#define SPLDECL(s) unsigned long s #define AIL_LOCK_T lock_t #define AIL_LOCKINIT(x,y) spinlock_init(x,y) #define AIL_LOCK_DESTROY(x) spinlock_destroy(x) @@ -296,13 +296,14 @@ typedef struct xfs_mount { 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 */ + struct list_head m_del_inodes; /* inodes to reclaim */ 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 */ + struct log *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 */ @@ -350,6 +351,7 @@ typedef struct xfs_mount { 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_maxioffset; /* maximum inode offset */ __uint64_t m_resblks; /* total reserved blocks */ __uint64_t m_resblks_avail;/* available reserved blocks */ #if XFS_BIG_FILESYSTEMS @@ -357,7 +359,6 @@ typedef struct xfs_mount { #endif int m_dalign; /* stripe unit */ int m_swidth; /* stripe width */ - int m_lstripemask; /* log stripe mask */ int m_sinoalign; /* stripe unit inode alignmnt */ int m_attr_magicpct;/* 37% of the blocksize */ int m_dir_magicpct; /* 37% of the dir blocksize */ @@ -383,8 +384,6 @@ typedef struct xfs_mount { * snapshot */ sv_t m_wait_unfreeze;/* waiting to unfreeze */ atomic_t m_active_trans; /* number trans frozen */ - struct timer_list m_sbdirty_timer;/* superblock dirty timer - * for nfs refcache */ } xfs_mount_t; /* @@ -419,8 +418,6 @@ typedef struct xfs_mount { * 32 bits in size */ #define XFS_MOUNT_NOLOGFLUSH 0x00010000 -#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) - /* * Default minimum read and write sizes. */ @@ -445,6 +442,9 @@ typedef struct xfs_mount { #define XFS_WSYNC_READIO_LOG 15 /* 32K */ #define XFS_WSYNC_WRITEIO_LOG 14 /* 16K */ +#define XFS_MAXIOFFSET(mp) ((mp)->m_maxioffset) + +#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) #define xfs_force_shutdown(m,f) \ VFS_FORCE_SHUTDOWN((XFS_MTOVFS(m)), f, __FILE__, __LINE__) @@ -540,7 +540,7 @@ typedef struct xfs_mod_sb { extern xfs_mount_t *xfs_mount_init(void); extern void xfs_mod_sb(xfs_trans_t *, __int64_t); extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); -extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int); +extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, int); extern int xfs_unmountfs(xfs_mount_t *, struct cred *); extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_qmops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_qmops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_qmops.c 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_qmops.c 2003-08-17 21:26:18.000000000 +0200 @@ -29,7 +29,20 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" + +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" + #ifndef CONFIG_XFS_QUOTA STATIC struct xfs_dquot * diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_rename.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_rename.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_rename.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_rename.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,33 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_error.h" +#include "xfs_quota.h" +#include "xfs_rw.h" +#include "xfs_utils.h" +#include "xfs_trans_space.h" +#include "xfs_da_btree.h" +#include "xfs_dir_leaf.h" +#include "xfs_dmapi.h" /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_rtalloc.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_rtalloc.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_rtalloc.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_rtalloc.c 2003-08-17 21:26:18.000000000 +0200 @@ -34,7 +34,37 @@ * Free realtime space allocation for XFS. */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_bmap.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_fsops.h" +#include "xfs_error.h" +#include "xfs_rw.h" +#include "xfs_inode_item.h" +#include "xfs_trans_space.h" /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_rw.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_rw.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_rw.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_rw.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,8 +30,39 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include - +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_itable.h" +#include "xfs_btree.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_attr.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_acl.h" +#include "xfs_mac.h" +#include "xfs_attr.h" +#include "xfs_error.h" +#include "xfs_buf_item.h" +#include "xfs_rw.h" /* * This is a subroutine for xfs_write() and other writers (xfs_ioctl) @@ -377,21 +408,11 @@ xfs_inval_cached_pages( 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; /* - * Timer callback to mark SB dirty, make sure we keep purging refcache - */ -void -xfs_refcache_sbdirty(struct super_block *sb) -{ - sb->s_dirt = 1; -} - -/* * Insert the given inode into the reference cache. */ void @@ -613,15 +634,13 @@ xfs_refcache_purge_some(xfs_mount_t *mp) xfs_inode_t *ip; int iplist_index; xfs_inode_t **iplist; - int purge_count; if ((xfs_refcache == NULL) || (xfs_refcache_count == 0)) { return; } iplist_index = 0; - purge_count = xfs_params.refcache_purge; - iplist = (xfs_inode_t **)kmem_zalloc(purge_count * + iplist = (xfs_inode_t **)kmem_zalloc(xfs_refcache_purge_count * sizeof(xfs_inode_t *), KM_SLEEP); spin_lock(&xfs_refcache_lock); @@ -634,7 +653,7 @@ xfs_refcache_purge_some(xfs_mount_t *mp) * 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 < purge_count; i++) { + for (i = 0; i < xfs_refcache_purge_count; i++) { ip = xfs_refcache[xfs_refcache_index]; if (ip != NULL) { xfs_refcache[xfs_refcache_index] = NULL; @@ -653,20 +672,6 @@ xfs_refcache_purge_some(xfs_mount_t *mp) spin_unlock(&xfs_refcache_lock); /* - * If there are still entries in the refcache, - * set timer to mark the SB dirty to make sure that - * we hit sync even if filesystem is idle, so that we'll - * purge some more later. - */ - if (xfs_refcache_count) { - del_timer_sync(&mp->m_sbdirty_timer); - mp->m_sbdirty_timer.data = - (unsigned long)LINVFS_GET_IP(XFS_ITOV(mp->m_rootip))->i_sb; - mp->m_sbdirty_timer.expires = jiffies + 2*HZ; - add_timer(&mp->m_sbdirty_timer); - } - - /* * Now drop the inodes we collected. */ for (i = 0; i < iplist_index; i++) { @@ -674,7 +679,7 @@ xfs_refcache_purge_some(xfs_mount_t *mp) VN_RELE(XFS_ITOV(iplist[i])); } - kmem_free(iplist, purge_count * + kmem_free(iplist, xfs_refcache_purge_count * sizeof(xfs_inode_t *)); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_sb.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_sb.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_sb.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_sb.h 2003-08-17 21:26:19.000000000 +0200 @@ -81,7 +81,7 @@ struct xfs_mount; XFS_SB_VERSION_OKREALFBITS | \ XFS_SB_VERSION_OKSASHFBITS) #define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na,sflag) \ - (((ia) || (dia) || (extflag) || (dirv2) || (na)) ? \ + (((ia) || (dia) || (extflag) || (dirv2) || (na) || (sflag)) ? \ (XFS_SB_VERSION_4 | \ ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \ ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,7 +30,35 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_error.h" +#include "xfs_trans_priv.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_quota.h" +#include "xfs_trans_space.h" STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *); @@ -172,6 +200,7 @@ xfs_trans_dup( 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; + PFLAGS_DUP(&tp->t_pflags, &ntp->t_pflags); XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp); @@ -210,7 +239,7 @@ xfs_trans_reserve( rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; /* Mark this thread as being in a transaction */ - current->flags |= PF_FSTRANS; + PFLAGS_SET_FSTRANS(&tp->t_pflags); /* * Attempt to reserve the needed disk blocks by decrementing @@ -221,7 +250,7 @@ xfs_trans_reserve( error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, -blocks, rsvd); if (error != 0) { - current->flags &= ~PF_FSTRANS; + PFLAGS_RESTORE(&tp->t_pflags); return (XFS_ERROR(ENOSPC)); } tp->t_blk_res += blocks; @@ -294,7 +323,7 @@ undo_blocks: tp->t_blk_res = 0; } - current->flags &= ~PF_FSTRANS; + PFLAGS_RESTORE(&tp->t_pflags); return (error); } @@ -706,13 +735,13 @@ shut_us_down: if (commit_lsn == -1 && !shutdown) shutdown = XFS_ERROR(EIO); } + PFLAGS_RESTORE(&tp->t_pflags); xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0); xfs_trans_free_busy(tp); xfs_trans_free(tp); XFS_STATS_INC(xfsstats.xs_trans_empty); if (commit_lsn_p) *commit_lsn_p = commit_lsn; - current->flags &= ~PF_FSTRANS; return (shutdown); } #if defined(XLOG_NOLOG) || defined(DEBUG) @@ -795,8 +824,8 @@ shut_us_down: * had pinned, clean up, free trans structure, and return error. */ if (error || commit_lsn == -1) { + PFLAGS_RESTORE(&tp->t_pflags); xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); - current->flags &= ~PF_FSTRANS; return XFS_ERROR(EIO); } @@ -822,15 +851,6 @@ shut_us_down: * 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; - error = xfs_log_notify(mp, commit_iclog, &(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; @@ -841,7 +861,9 @@ shut_us_down: * waiting for an item to unlock. */ error = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb)); -#endif + + /* mark this thread as no longer being in a transaction */ + PFLAGS_RESTORE(&tp->t_pflags); /* * Once all the items of the transaction have been copied @@ -878,9 +900,6 @@ shut_us_down: XFS_STATS_INC(xfsstats.xs_trans_async); } - /* mark this thread as no longer being in a transaction */ - current->flags &= ~PF_FSTRANS; - return (error); } @@ -1080,12 +1099,13 @@ xfs_trans_cancel( } xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags); } + + /* mark this thread as no longer being in a transaction */ + PFLAGS_RESTORE(&tp->t_pflags); + xfs_trans_free_items(tp, flags); xfs_trans_free_busy(tp); xfs_trans_free(tp); - - /* mark this thread as no longer being in a transaction */ - current->flags &= ~PF_FSTRANS; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans.h linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans.h --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans.h 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans.h 2003-08-17 21:26:19.000000000 +0200 @@ -409,6 +409,7 @@ typedef struct xfs_trans { xfs_trans_header_t t_header; /* header for in-log trans */ unsigned int t_busy_free; /* busy descs free */ xfs_log_busy_chunk_t t_busy; /* busy/async free blocks */ + xfs_pflags_t t_pflags; /* saved pflags state */ } xfs_trans_t; #endif /* __KERNEL__ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_ail.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_ail.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_ail.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_ail.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,19 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_log.h" +#include "xfs_trans_priv.h" +#include "xfs_error.h" 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 *); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_buf.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_buf.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_buf.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_buf.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,21 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_buf_item.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_trans_priv.h" +#include "xfs_error.h" +#include "xfs_rw.h" STATIC xfs_buf_t *xfs_trans_buf_item_match(xfs_trans_t *, xfs_buftarg_t *, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_extfree.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_extfree.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_extfree.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_extfree.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,18 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_trans_priv.h" +#include "xfs_extfree_item.h" /* * This routine is called to allocate an "extent free intention" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_inode.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_inode.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_inode.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_inode.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,30 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include - +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_trans_priv.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" #ifdef XFS_TRANS_DEBUG STATIC void diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_item.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_item.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_trans_item.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_trans_item.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,8 +30,12 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include - +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" STATIC int xfs_trans_unlock_chunk(xfs_log_item_chunk_t *, int, int, xfs_lsn_t); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_utils.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_utils.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_utils.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_utils.c 2003-08-17 21:26:18.000000000 +0200 @@ -30,7 +30,30 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_error.h" +#include "xfs_quota.h" +#include "xfs_rw.h" +#include "xfs_itable.h" +#include "xfs_utils.h" /* * xfs_get_dir_entry is used to get a reference to an inode given diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_vfsops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_vfsops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_vfsops.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_vfsops.c 2003-08-17 21:26:19.000000000 +0200 @@ -32,7 +32,44 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_alloc_btree.h" +#include "xfs_btree.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_ag.h" +#include "xfs_error.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_rw.h" +#include "xfs_buf_item.h" +#include "xfs_extfree_item.h" +#include "xfs_quota.h" +#include "xfs_dmapi.h" +#include "xfs_dir2_trace.h" +#include "xfs_acl.h" +#include "xfs_attr.h" +#include "xfs_clnt.h" +#include "xfs_log_priv.h" STATIC int xfs_sync(bhv_desc_t *, int, cred_t *); @@ -59,10 +96,6 @@ xfs_init(void) #endif /* DEBUG */ #ifdef XFS_DABUF_DEBUG extern lock_t xfs_dabuf_global_lock; -#endif - extern int xfs_refcache_size; - -#ifdef XFS_DABUF_DEBUG spinlock_init(&xfs_dabuf_global_lock, "xfsda"); #endif @@ -140,8 +173,6 @@ xfs_init(void) xfs_init_procfs(); xfs_sysctl_register(); - xfs_refcache_size = xfs_params.refcache_size; - /* * The inode hash table is created on a per mounted * file system bases. @@ -207,7 +238,7 @@ xfs_start_flags( /* * 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 + * Before the mount call ends we will convert * these to FSBs. */ mp->m_dalign = ap->sunit; @@ -215,11 +246,11 @@ xfs_start_flags( } if (ap->logbufs != 0 && ap->logbufs != -1 && - (ap->logbufs < XLOG_NUM_ICLOGS || + (ap->logbufs < XLOG_MIN_ICLOGS || ap->logbufs > XLOG_MAX_ICLOGS)) { cmn_err(CE_WARN, "XFS: invalid logbufs value: %d [not %d-%d]", - ap->logbufs, XLOG_NUM_ICLOGS, XLOG_MAX_ICLOGS); + ap->logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); return XFS_ERROR(EINVAL); } mp->m_logbufs = ap->logbufs; @@ -534,7 +565,6 @@ xfs_unmount( * out of the reference cache, and delete the timer. */ xfs_refcache_purge_mp(mp); - del_timer_sync(&mp->m_sbdirty_timer); XFS_bflush(mp->m_ddev_targp); error = xfs_unmount_flush(mp, 0); @@ -583,6 +613,8 @@ out: return XFS_ERROR(error); } +#define REMOUNT_READONLY_FLAGS (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT) + STATIC int xfs_mntupdate( bhv_desc_t *bdp, @@ -605,10 +637,10 @@ xfs_mntupdate( if (*flags & MS_RDONLY) { xfs_refcache_purge_mp(mp); pagebuf_delwri_flush(mp->m_ddev_targp, 0, NULL); - xfs_finish_reclaim_all(mp); + xfs_finish_reclaim_all(mp, 0); do { - VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error); + VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error); pagebuf_delwri_flush(mp->m_ddev_targp, PBDF_WAIT, &pincount); } while (pincount); @@ -834,19 +866,14 @@ xfs_sync( * 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 + * interface as explained above under xfs_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( +STATIC int +xfs_sync_inodes( xfs_mount_t *mp, int flags, int xflags, @@ -862,12 +889,10 @@ xfs_syncsub( 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; @@ -946,16 +971,6 @@ xfs_syncsub( 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; @@ -1001,27 +1016,23 @@ xfs_syncsub( 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 ((xfs_ipincount(ip) == 0) && + if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) { + ip = ip->i_mnext; + } else if ((xfs_ipincount(ip) == 0) && xfs_iflock_nowait(ip)) { - IPOINTER_INSERT(ip, mp); + IPOINTER_INSERT(ip, mp); - xfs_finish_reclaim(ip, 1, - XFS_IFLUSH_DELWRI_ELSE_SYNC); + xfs_finish_reclaim(ip, 1, + XFS_IFLUSH_DELWRI_ELSE_ASYNC); - XFS_MOUNT_ILOCK(mp); - mount_locked = B_TRUE; - IPOINTER_REMOVE(ip, mp); - } else { - xfs_iunlock(ip, XFS_ILOCK_EXCL); - ip = ip->i_mnext; - } - continue; + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + IPOINTER_REMOVE(ip, mp); + } else { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + ip = ip->i_mnext; } + continue; } if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) { @@ -1133,21 +1144,9 @@ xfs_syncsub( 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); - } + 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); - } + VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF); } xfs_ilock(ip, XFS_ILOCK_SHARED); @@ -1403,16 +1402,55 @@ xfs_syncsub( ASSERT(ipointer_in == B_FALSE); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(last_error); +} + +/* + * xfs sync routine for internal use + * + * This routine supports all of the flags defined for the generic VFS_SYNC + * interface as explained above under xfs_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. + * + */ +int +xfs_syncsub( + xfs_mount_t *mp, + int flags, + int xflags, + int *bypassed) +{ + int error = 0; + int last_error = 0; + uint log_flags = XFS_LOG_FORCE; + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + + /* + * 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) + log_flags |= XFS_LOG_SYNC; + + xfs_log_force(mp, (xfs_lsn_t)0, log_flags); + + if (flags & (SYNC_ATTR|SYNC_DELWRI)) { + if (flags & SYNC_BDFLUSH) + xfs_finish_reclaim_all(mp, 1); + else + error = xfs_sync_inodes(mp, flags, xflags, bypassed); + } + /* * 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. + * the log again. */ - if (!(flags & SYNC_BDFLUSH)) { - log_flags = XFS_LOG_FORCE; - if (flags & SYNC_WAIT) { - log_flags |= XFS_LOG_SYNC; - } + if (flags & SYNC_DELWRI) { xfs_log_force(mp, (xfs_lsn_t)0, log_flags); } @@ -1448,11 +1486,10 @@ xfs_syncsub( * 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; + if (XFS_BUF_ISPINNED(bp)) + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + if (!(flags & SYNC_WAIT)) + XFS_BUF_BFLAGS(bp) |= XFS_B_ASYNC; error = xfs_bwrite(mp, bp); } if (error) { @@ -1461,11 +1498,11 @@ xfs_syncsub( } /* - * If this is the 30 second sync, then kick some entries out of + * If this is the periodic 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) { + if (flags & SYNC_REFCACHE) { xfs_refcache_purge_some(mp); } @@ -1473,8 +1510,9 @@ xfs_syncsub( * Now check to see if the log needs a "dummy" transaction. */ - if (xfs_log_need_covered(mp)) { + if (!(flags & SYNC_REMOUNT) && xfs_log_need_covered(mp)) { xfs_trans_t *tp; + xfs_inode_t *ip; /* * Put a dummy transaction in the log to tell @@ -1485,7 +1523,6 @@ xfs_syncsub( XFS_ICHANGE_LOG_RES(mp), 0, 0, 0))) { xfs_trans_cancel(tp, 0); - kmem_free(ipointer, sizeof(xfs_iptr_t)); return error; } @@ -1497,6 +1534,7 @@ xfs_syncsub( xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_trans_commit(tp, 0, NULL); xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_log_force(mp, (xfs_lsn_t)0, log_flags); } /* @@ -1510,7 +1548,6 @@ xfs_syncsub( } } - kmem_free(ipointer, sizeof(xfs_iptr_t)); return XFS_ERROR(last_error); } @@ -1609,7 +1646,7 @@ xfs_parseargs( if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_LOGBUFS); - return -EINVAL; + return EINVAL; } args->logbufs = simple_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { @@ -1618,7 +1655,7 @@ xfs_parseargs( if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_LOGBSIZE); - return -EINVAL; + return EINVAL; } last = strlen(value) - 1; if (value[last] == 'K' || value[last] == 'k') { @@ -1632,28 +1669,28 @@ xfs_parseargs( if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_LOGDEV); - return -EINVAL; + return EINVAL; } strncpy(args->logname, value, MAXNAMELEN); } else if (!strcmp(this_char, MNTOPT_MTPT)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_MTPT); - return -EINVAL; + return EINVAL; } strncpy(args->mtpt, value, MAXNAMELEN); } else if (!strcmp(this_char, MNTOPT_RTDEV)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_RTDEV); - return -EINVAL; + return EINVAL; } strncpy(args->rtname, value, MAXNAMELEN); } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_BIOSIZE); - return -EINVAL; + return EINVAL; } iosize = simple_strtoul(value, &eov, 10); args->flags |= XFSMNT_IOSIZE; @@ -1669,7 +1706,7 @@ xfs_parseargs( #ifndef XFS_BIG_FILESYSTEMS printk("XFS: %s option not allowed on this system\n", MNTOPT_INO64); - return -EINVAL; + return EINVAL; #endif } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { args->flags |= XFSMNT_NOALIGN; @@ -1677,14 +1714,14 @@ xfs_parseargs( if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_SUNIT); - return -EINVAL; + return EINVAL; } dsunit = simple_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", MNTOPT_SWIDTH); - return -EINVAL; + return EINVAL; } dswidth = simple_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_NOUUID)) { @@ -1698,33 +1735,33 @@ printk("XFS: osyncisdsync is now the def printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n"); } else { printk("XFS: unknown mount option [%s].\n", this_char); - return -EINVAL; + return EINVAL; } } if (args->flags & XFSMNT_NORECOVERY) { if ((vfsp->vfs_flag & VFS_RDONLY) == 0) { printk("XFS: no-recovery mounts must be read-only.\n"); - return -EINVAL; + return EINVAL; } } if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { printk( "XFS: sunit and swidth options incompatible with the noalign option\n"); - return -EINVAL; + return EINVAL; } if ((dsunit && !dswidth) || (!dsunit && dswidth)) { printk("XFS: sunit and swidth must be specified together\n"); - return -EINVAL; + return EINVAL; } if (dsunit && (dswidth % dsunit != 0)) { printk( "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)\n", dswidth, dsunit); - return -EINVAL; + return EINVAL; } if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_vnodeops.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_vnodeops.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfs_vnodeops.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfs_vnodeops.c 2003-08-17 21:26:19.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,45 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include +#include "xfs.h" +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_itable.h" +#include "xfs_btree.h" +#include "xfs_ialloc.h" +#include "xfs_alloc.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode_item.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_rw.h" +#include "xfs_error.h" +#include "xfs_bit.h" +#include "xfs_rtalloc.h" +#include "xfs_quota.h" +#include "xfs_utils.h" +#include "xfs_trans_space.h" +#include "xfs_dir_leaf.h" +#include "xfs_dmapi.h" +#include "xfs_mac.h" +#include "xfs_log_priv.h" /* @@ -280,6 +318,9 @@ xfs_setattr( vp = BHV_TO_VNODE(bdp); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + /* * Cannot set certain attributes. */ @@ -540,7 +581,8 @@ xfs_setattr( /* * Can't change extent size if any extents are allocated. */ - if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) && + if ((ip->i_d.di_nextents || ip->i_delayed_blks) && + (mask & XFS_AT_EXTSIZE) && ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != vap->va_extsize) ) { code = XFS_ERROR(EINVAL); /* EFBIG? */ @@ -620,7 +662,7 @@ xfs_setattr( 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) { + } 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); @@ -663,7 +705,7 @@ xfs_setattr( 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) || + } else if ((vap->va_size <= ip->i_d.di_size) || ((vap->va_size == 0) && ip->i_d.di_nextents)) { /* * signal a sync transaction unless @@ -1248,7 +1290,7 @@ xfs_inactive_free_eofblocks( * 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); + last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp)); map_len = last_fsb - end_fsb; if (map_len <= 0) return (0); @@ -3724,9 +3766,7 @@ xfs_inode_flush( int flags) { xfs_inode_t *ip; - xfs_dinode_t *dip; xfs_mount_t *mp; - xfs_buf_t *bp; int error = 0; ip = XFS_BHVTOI(bdp); @@ -3772,41 +3812,30 @@ xfs_inode_flush( * now, they get caught later by xfs_sync. */ if (flags & FLUSH_INODE) { - if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { - if ((xfs_ipincount(ip) == 0) && xfs_iflock_nowait(ip)) { - int flush_flags; + int flush_flags; -#if 0 - /* not turning this on until some - * performance analysis is done - */ - if (flags & FLUSH_SYNC) - flush_flags = XFS_IFLUSH_SYNC; - else -#endif - flush_flags = XFS_IFLUSH_DELWRI; + if (xfs_ipincount(ip)) + return EAGAIN; - xfs_ifunlock(ip); + if (flags & FLUSH_SYNC) { + xfs_ilock(ip, XFS_ILOCK_SHARED); + xfs_iflock(ip); + } else if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { + if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) { xfs_iunlock(ip, XFS_ILOCK_SHARED); - error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0); - if (error) - goto eagain; - xfs_buf_relse(bp); - - if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED) == 0) - goto eagain; - - if ((xfs_ipincount(ip) == 0) && - xfs_iflock_nowait(ip)) - error = xfs_iflush(ip, flush_flags); - } else { - error = EAGAIN; + return EAGAIN; } - xfs_iunlock(ip, XFS_ILOCK_SHARED); } else { -eagain: - error = EAGAIN; + return EAGAIN; } + + if (flags & FLUSH_SYNC) + flush_flags = XFS_IFLUSH_SYNC; + else + flush_flags = XFS_IFLUSH_ASYNC; + + error = xfs_iflush(ip, flush_flags); + xfs_iunlock(ip, XFS_ILOCK_SHARED); } return error; @@ -3925,6 +3954,7 @@ xfs_reclaim( */ if (!ip->i_update_core && (ip->i_itemp == NULL)) { xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_iflock(ip); return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); } else { xfs_mount_t *mp = ip->i_mount; @@ -3932,6 +3962,8 @@ xfs_reclaim( /* Protect sync from us */ XFS_MOUNT_ILOCK(mp); vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); + ip->i_flags |= XFS_IRECLAIMABLE; XFS_MOUNT_IUNLOCK(mp); } return 0; @@ -3946,19 +3978,20 @@ xfs_finish_reclaim( xfs_ihash_t *ih = ip->i_hash; int error; - if (!locked) - xfs_ilock(ip, XFS_ILOCK_EXCL); - /* The hash lock here protects a thread in xfs_iget_core from * racing with us on linking the inode back with a vnode. * Once we have the XFS_IRECLAIM flag set it will not touch * us. */ write_lock(&ih->ih_lock); - if (ip->i_flags & XFS_IRECLAIM || (!locked && XFS_ITOV_NULL(ip))) { + if ((ip->i_flags & XFS_IRECLAIM) || + (!(ip->i_flags & XFS_IRECLAIMABLE) && + (XFS_ITOV_NULL(ip) == NULL))) { write_unlock(&ih->ih_lock); - if (!locked) + if (locked) { + xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); + } return(1); } ip->i_flags |= XFS_IRECLAIM; @@ -3977,6 +4010,7 @@ xfs_finish_reclaim( */ if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { if (!locked) { + xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_iflock(ip); } @@ -4000,48 +4034,49 @@ xfs_finish_reclaim( ASSERT(ip->i_update_core == 0); ASSERT(ip->i_itemp == NULL || ip->i_itemp->ili_format.ilf_fields == 0); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } else if (locked) { + /* + * We are not interested in doing an iflush if we're + * in the process of shutting down the filesystem forcibly. + * So, just reclaim the inode. + */ + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_EXCL); } - xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_ireclaim(ip); return 0; } int -xfs_finish_reclaim_all(xfs_mount_t *mp) +xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) { int purged; + struct list_head *curr, *next; xfs_inode_t *ip; - vnode_t *vp; int done = 0; while (!done) { purged = 0; XFS_MOUNT_ILOCK(mp); - ip = mp->m_inodes; - if (ip == NULL) { + list_for_each_safe(curr, next, &mp->m_del_inodes) { + ip = list_entry(curr, xfs_inode_t, i_reclaim); + if (noblock) { + if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) + continue; + if (xfs_ipincount(ip) || + !xfs_iflock_nowait(ip)) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + continue; + } + } + XFS_MOUNT_IUNLOCK(mp); + xfs_finish_reclaim(ip, noblock, + XFS_IFLUSH_DELWRI_ELSE_ASYNC); + purged = 1; 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, XFS_IFLUSH_ASYNC); - purged = 1; - break; - } - } while (ip != mp->m_inodes); done = !purged; } @@ -4600,9 +4635,9 @@ xfs_change_file_space( 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 > XFS_MAXIOFFSET(mp)) || (bf->l_start + llen < 0) - || (bf->l_start + llen > XFS_MAX_FILE_OFFSET)) + || (bf->l_start + llen > XFS_MAXIOFFSET(mp))) return XFS_ERROR(EINVAL); bf->l_whence = 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfsidbg.c linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfsidbg.c --- linux-2.4.20-wolk4.6-fullkernel/fs/xfs/xfsidbg.c 2003-05-03 01:54:10.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/fs/xfs/xfsidbg.c 2003-08-17 21:26:19.000000000 +0200 @@ -30,9 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include -#include "quota/xfs_qm.h" +#include "xfs.h" #include "pagebuf/page_buf_internal.h" #include @@ -41,7 +39,49 @@ #include #include -MODULE_AUTHOR("SGI "); +#include "xfs_macros.h" +#include "xfs_types.h" +#include "xfs_inum.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dir.h" +#include "xfs_dir2.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_alloc.h" +#include "xfs_ag.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_btree.h" +#include "xfs_buf_item.h" +#include "xfs_extfree_item.h" +#include "xfs_inode_item.h" +#include "xfs_attr_sf.h" +#include "xfs_dir_sf.h" +#include "xfs_dir2_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_bmap.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_attr_leaf.h" +#include "xfs_dir_leaf.h" +#include "xfs_dir2_data.h" +#include "xfs_dir2_leaf.h" +#include "xfs_dir2_block.h" +#include "xfs_dir2_node.h" +#include "xfs_dir2_trace.h" +#include "xfs_log_priv.h" +#include "xfs_log_recover.h" +#include "xfs_rw.h" +#include "xfs_bit.h" +#include "xfs_quota.h" +#include "xfs_log_recover.h" +#include "quota/xfs_qm.h" + +MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION("Additional kdb commands for debugging XFS"); MODULE_LICENSE("GPL"); EXPORT_NO_SYMBOLS; @@ -1366,33 +1406,40 @@ printflags(register uint64_t flags, } -static void printvnode(vnode_t *vp, unsigned long addr) +static void printbhv(bhv_desc_t *bdp) { - bhv_desc_t *bh; kdb_symtab_t symtab; + if (bdp == NULL) { + kdb_printf("NULL bhv\n"); + return; + } + + kdb_printf("bhv at 0x%p\n", bdp); + while (bdp) { + if (kdbnearsym((unsigned long)bdp->bd_ops, &symtab)) + kdb_printf(" ops %s", symtab.sym_name); + else + kdb_printf(" ops %s/0x%p", "???", (void *)bdp->bd_ops); + + kdb_printf(" vobj 0x%p pdata 0x%p next 0x%p\n", + bdp->bd_vobj, bdp->bd_pdata, bdp->bd_next); + + bdp = bdp->bd_next; + } +} + +static void printvnode(vnode_t *vp, unsigned long addr) +{ kdb_printf("vnode: 0x%lx type ", addr); if ((size_t)vp->v_type >= sizeof(vnode_type)/sizeof(vnode_type[0])) kdb_printf("out of range 0x%x", vp->v_type); else kdb_printf("%s", vnode_type[vp->v_type]); - kdb_printf(" v_bh %p\n", &vp->v_bh); - - if ((bh = vp->v_bh.bh_first)) { - kdb_printf(" v_inode 0x%p v_bh->bh_first 0x%p pobj 0x%p\n", - LINVFS_GET_IP((struct vnode *) addr), - bh, bh->bd_pdata); + kdb_printf(" v_bh 0x%p\n", &vp->v_bh); - if (kdbnearsym((unsigned long)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 ", - LINVFS_GET_IP((struct vnode *) addr)); - } + printbhv(vp->v_fbhv); printflags((__psunsigned_t)vp->v_flag, tab_vflags, "flag ="); kdb_printf("\n"); @@ -1437,7 +1484,38 @@ static void print_vfs(vfs_t *vfs, unsigned long addr) { kdb_printf("vfsp at 0x%lx", addr); - kdb_printf(" vfs_fbhv 0x%p sb 0x%p\n", vfs->vfs_fbhv, vfs->vfs_super); + kdb_printf(" vfs_flag 0x%x\n", vfs->vfs_flag); + kdb_printf(" vfs_super 0x%p", vfs->vfs_super); + kdb_printf(" vfs_bh 0x%p\n", &vfs->vfs_bh); + + printbhv(vfs->vfs_fbhv); +} + +static int kdbm_bhv( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + bhv_desc_t *bh; + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + bh = (bhv_desc_t *)addr; + + printbhv(bh); + + return 0; } static int kdbm_vfs( @@ -2132,6 +2210,7 @@ static struct xif { char *args; char *help; } xfsidbg_funcs[] = { + { "bhv", kdbm_bhv, "", "Dump bhv chain"}, { "vn", kdbm_vn, "", "Dump inode/vnode/trace"}, { "vnode", kdbm_vnode, "", "Dump vnode"}, { "vfs", kdbm_vfs, "", "Dump vfs"}, @@ -2925,9 +3004,9 @@ xfs_inode_item_print(xfs_inode_log_item_ kdb_printf("\n"); return; } - kdb_printf("inode 0x%p ino 0x%llu logged %d flags: ", + kdb_printf("inode 0x%p ino 0x%llu pushbuf %d logged %d flags: ", ilip->ili_inode, (unsigned long long) ilip->ili_format.ilf_ino, - ilip->ili_logged); + ilip->ili_pushbuf_flag, 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", @@ -2937,10 +3016,9 @@ xfs_inode_item_print(xfs_inode_log_item_ 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("size %d ", ilip->ili_format.ilf_size); + printflags(ilip->ili_format.ilf_fields, ilf_fields, "fields:"); + printflags(ilip->ili_last_fields, ilf_fields, " last fields: "); kdb_printf("\n"); kdb_printf(" flush lsn %s last lsn %s\n", xfs_fmtlsn(&(ilip->ili_flush_lsn)), @@ -3030,19 +3108,20 @@ xfs_prdinode_core(xfs_dinode_core_t *dip 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", + kdb_printf("nlink %d uid %d gid %d projid %d flushiter %u\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", + (uint)INT_GET(dip->di_projid, convert), + (uint)INT_GET(dip->di_flushiter, convert)); + kdb_printf("atime %u:%u mtime %ud:%u ctime %u:%u\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("size 0x%Ld ", 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), @@ -4266,8 +4345,10 @@ xfsidbg_xlog(xlog_t *log) 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("l_iclog_hsize %d l_iclog_heads %d\n", - log->l_iclog_hsize, log->l_iclog_heads); + kdb_printf("l_stripemask %d l_iclog_hsize %d l_iclog_heads %d\n", + log->l_stripemask, log->l_iclog_hsize, log->l_iclog_heads); + kdb_printf("l_sectbb_log %u l_sectbb_mask %u\n", + log->l_sectbb_log, log->l_sectbb_mask); 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", @@ -4473,10 +4554,10 @@ xfsidbg_xlogitem(xfs_log_item_t *lip) 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", + kdb_printf("ail forw 0x%p ail back 0x%p lsn %s\ndesc %p ops 0x%p", 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); + 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) { @@ -4709,7 +4790,6 @@ xfsidbg_xmount(xfs_mount_t *mp) (xfs_dfiloff_t)mp->m_dirfreeblk); kdb_printf("chsize %d chash 0x%p\n", mp->m_chsize, mp->m_chash); - kdb_printf("m_lstripemask %d\n", mp->m_lstripemask); kdb_printf("m_frozen %d m_active_trans %d\n", mp->m_frozen, mp->m_active_trans.counter); if (mp->m_fsname != NULL) @@ -4817,7 +4897,7 @@ xfsidbg_xnode(xfs_inode_t *ip) kdb_printf("transp 0x%p &itemp 0x%p\n", ip->i_transp, ip->i_itemp); - kdb_printf("&lock 0x%p &iolock 0x%p", + kdb_printf("&lock 0x%p &iolock 0x%p ", &ip->i_lock, &ip->i_iolock); kdb_printf("&flock 0x%p (%d) pincount 0x%x\n", @@ -4825,10 +4905,10 @@ xfsidbg_xnode(xfs_inode_t *ip) xfs_ipincount(ip)); 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("new_size %Ld\n", ip->i_iocore.io_new_size); printflags((int)ip->i_flags, tab_flags, "flags"); kdb_printf("\n"); - kdb_printf("update_core 0x%x update size 0x%x\n", + kdb_printf("update_core %d update size %d\n", (int)(ip->i_update_core), (int) ip->i_update_size); kdb_printf("gen 0x%x delayed blks %d", ip->i_gen, @@ -4879,13 +4959,8 @@ xfsidbg_xchashlist(xfs_chashlist_t *chl) xfs_inode_t *ip; while (chl != NULL) { -#ifdef DEBUG - kdb_printf("hashlist inode 0x%p blkno %Ld buf 0x%p", - chl->chl_ip, chl->chl_blkno, chl->chl_buf); -#else - kdb_printf("hashlist inode 0x%p blkno %lld", - chl->chl_ip, (long long) chl->chl_blkno); -#endif + kdb_printf("hashlist inode 0x%p blkno %lld buf 0x%p", + chl->chl_ip, (long long) chl->chl_blkno, chl->chl_buf); kdb_printf("\n"); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/grsecurity/gracl.c linux-2.4.20-wolk4.7-fullkernel/grsecurity/gracl.c --- linux-2.4.20-wolk4.6-fullkernel/grsecurity/gracl.c 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/grsecurity/gracl.c 2003-08-17 21:28:28.000000000 +0200 @@ -33,7 +33,7 @@ static struct name_db inodev_set; static struct admin_pw pwent; /* password entry */ static u8 acl_admin_value; -static spinlock_t gr_proc_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_MUTEX(gr_proc_sem); rwlock_t gr_inode_lock = RW_LOCK_UNLOCKED; extern char *gr_shared_page[NR_CPUS]; @@ -1351,7 +1351,7 @@ gr_proc_handler(ctl_table * table, int w if (!write) return -EPERM; - spin_lock(&gr_proc_lock); + down(&gr_proc_sem); arg = (struct gr_arg *) buffer; @@ -1418,13 +1418,16 @@ gr_proc_handler(ctl_table * table, int w GR_RELOADI_ACL_FLD); error = -EAGAIN; } else if (!(chkpw(&usermode, &pwent))) { + lock_kernel(); gr_status &= ~GR_READY; free_variables(); - if (!(error2 = gracl_init(&usermode))) + if (!(error2 = gracl_init(&usermode))) { + unlock_kernel(); security_alert_good(GR_RELOAD_ACL_MSG, GR_RELOAD_ACL_FLD, GR_VERSION); - else { + } else { + unlock_kernel(); error = error2; security_alert(GR_RELOADF_ACL_MSG, GR_RELOADF_ACL_FLD, GR_VERSION, @@ -1520,7 +1523,7 @@ gr_proc_handler(ctl_table * table, int w } out: - spin_unlock(&gr_proc_lock); + up(&gr_proc_sem); return error; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/grsecurity/gracl_ip.c linux-2.4.20-wolk4.7-fullkernel/grsecurity/gracl_ip.c --- linux-2.4.20-wolk4.6-fullkernel/grsecurity/gracl_ip.c 2003-05-03 02:11:53.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/grsecurity/gracl_ip.c 2003-08-17 21:28:32.000000000 +0200 @@ -25,6 +25,58 @@ #define GR_BIND 0x01 #define GR_CONNECT 0x02 +static const char * gr_protocols[256] = { + "ip", "icmp", "igmp", "ggp", "ipencap", "st", "tcp", "cbt", + "egp", "igp", "bbn-rcc", "nvp", "pup", "argus", "emcon", "xnet", + "chaos", "udp", "mux", "dcn", "hmp", "prm", "xns-idp", "trunk-1", + "trunk-2", "leaf-1", "leaf-2", "rdp", "irtp", "iso-tp4", "netblt", "mfe-nsp", + "merit-inp", "sep", "3pc", "idpr", "xtp", "ddp", "idpr-cmtp", "tp++", + "il", "ipv6", "sdrp", "ipv6-route", "ipv6-frag", "idrp", "rsvp", "gre", + "mhrp", "bna", "ipv6-crypt", "ipv6-auth", "i-nlsp", "swipe", "narp", "mobile", + "tlsp", "skip", "ipv6-icmp", "ipv6-nonxt", "ipv6-opts", "unknown:61", "cftp", "unknown:63", + "sat-expak", "kryptolan", "rvd", "ippc", "unknown:68", "sat-mon", "visa", "ipcv", + "cpnx", "cphb", "wsn", "pvp", "br-sat-mon", "sun-nd", "wb-mon", "wb-expak", + "iso-ip", "vmtp", "secure-vmtp", "vines", "ttp", "nfsnet-igp", "dgp", "tcf", + "eigrp", "ospf", "sprite-rpc", "larp", "mtp", "ax.25", "ipip", "micp", + "scc-sp", "etherip", "encap", "unknown:99", "gmtp", "ifmp", "pnni", "pim", + "aris", "scps", "qnx", "a/n", "ipcomp", "snp", "compaq-peer", "ipx-in-ip", + "vrrp", "pgm", "unknown:114", "l2tp", "ddx", "iatp", "stp", "srp", + "uti", "smp", "sm", "ptp", "isis", "fire", "crtp", "crdup", + "sscopmce", "iplt", "sps", "pipe", "sctp", "fc", "unkown:134", "unknown:135", + "unknown:136", "unknown:137", "unknown:138", "unknown:139", "unknown:140", "unknown:141", "unknown:142", "unknown:143", + "unknown:144", "unknown:145", "unknown:146", "unknown:147", "unknown:148", "unknown:149", "unknown:150", "unknown:151", + "unknown:152", "unknown:153", "unknown:154", "unknown:155", "unknown:156", "unknown:157", "unknown:158", "unknown:159", + "unknown:160", "unknown:161", "unknown:162", "unknown:163", "unknown:164", "unknown:165", "unknown:166", "unknown:167", + "unknown:168", "unknown:169", "unknown:170", "unknown:171", "unknown:172", "unknown:173", "unknown:174", "unknown:175", + "unknown:176", "unknown:177", "unknown:178", "unknown:179", "unknown:180", "unknown:181", "unknown:182", "unknown:183", + "unknown:184", "unknown:185", "unknown:186", "unknown:187", "unknown:188", "unknown:189", "unknown:190", "unknown:191", + "unknown:192", "unknown:193", "unknown:194", "unknown:195", "unknown:196", "unknown:197", "unknown:198", "unknown:199", + "unknown:200", "unknown:201", "unknown:202", "unknown:203", "unknown:204", "unknown:205", "unknown:206", "unknown:207", + "unknown:208", "unknown:209", "unknown:210", "unknown:211", "unknown:212", "unknown:213", "unknown:214", "unknown:215", + "unknown:216", "unknown:217", "unknown:218", "unknown:219", "unknown:220", "unknown:221", "unknown:222", "unknown:223", + "unknown:224", "unknown:225", "unknown:226", "unknown:227", "unknown:228", "unknown:229", "unknown:230", "unknown:231", + "unknown:232", "unknown:233", "unknown:234", "unknown:235", "unknown:236", "unknown:237", "unknown:238", "unknown:239", + "unknown:240", "unknown:241", "unknown:242", "unknown:243", "unknown:244", "unknown:245", "unknown:246", "unknown:247", + "unknown:248", "unknown:249", "unknown:250", "unknown:251", "unknown:252", "unknown:253", "unknown:254", "unknown:255", + }; + +static const char * gr_socktypes[11] = { + "unknown:0", "stream", "dgram", "raw", "rdm", "seqpacket", "unknown:6", + "unknown:7", "unknown:8", "unknown:9", "packet" + }; + +static __inline__ const char * +gr_proto_to_name(unsigned char proto) +{ + return gr_protocols[proto]; +} + +static __inline__ const char * +gr_socktype_to_name(unsigned char type) +{ + return gr_socktypes[type]; +} + int gr_search_socket(const int domain, const int type, const int protocol) { @@ -65,8 +117,8 @@ gr_search_socket(const int domain, const goto exit; } - security_alert(GR_SOCK_MSG, GR_SOCK_FLD, domain, type, protocol, - DEFAULTSECARGS); + security_alert(GR_SOCK_MSG, GR_SOCK_FLD, "inet", gr_socktype_to_name(type), + gr_proto_to_name(protocol), DEFAULTSECARGS); return 0; exit: @@ -116,12 +168,14 @@ gr_search_connectbind(const int mode, co if (mode == GR_BIND) security_alert(GR_BIND_ACL_MSG, GR_BIND_ACL_FLD, - NIPQUAD(ip_addr), ip_port, type, - sk->protocol, DEFAULTSECARGS); + NIPQUAD(ip_addr), ip_port, + gr_socktype_to_name(type), gr_proto_to_name(sk->protocol), + DEFAULTSECARGS); else if (mode == GR_CONNECT) security_alert(GR_CONNECT_ACL_MSG, GR_CONNECT_ACL_FLD, - NIPQUAD(ip_addr), ip_port, type, - sk->protocol, DEFAULTSECARGS); + NIPQUAD(ip_addr), ip_port, + gr_socktype_to_name(type), gr_proto_to_name(sk->protocol), + DEFAULTSECARGS); return 0; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/grsecurity/grsec_mem.c linux-2.4.20-wolk4.7-fullkernel/grsecurity/grsec_mem.c --- linux-2.4.20-wolk4.6-fullkernel/grsecurity/grsec_mem.c 2003-05-03 02:11:53.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/grsecurity/grsec_mem.c 2003-08-17 21:28:32.000000000 +0200 @@ -42,8 +42,9 @@ int gr_handle_mem_mmap(const unsigned long offset, struct vm_area_struct *vma) { if (offset < __pa(high_memory) && - (pgprot_val(vma->vm_page_prot) & PROT_WRITE) && - (offset != 0xa0000 || ((vma->vm_end - vma->vm_start) > 0x20000))) { + (pgprot_val(vma->vm_page_prot) & PROT_WRITE) && + !(offset == 0xf0000 && ((vma->vm_end - vma->vm_start) <= 0x10000)) && + !(offset == 0xa0000 && ((vma->vm_end - vma->vm_start) <= 0x20000))) { security_alert(GR_MEM_MMAP_MSG, GR_MEM_MMAP_FLD, DEFAULTSECARGS); return -EPERM; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/byteorder.h linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/byteorder.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/byteorder.h 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/byteorder.h 2001-11-22 20:46:18.000000000 +0100 @@ -24,44 +24,22 @@ static __inline__ __const__ __u32 ___arc return x; } -/* gcc should generate this for open coded C now too. May be worth switching to - it because inline assembly cannot be scheduled. -AK */ static __inline__ __const__ __u16 ___arch__swab16(__u16 x) { - __asm__("xchgb %b0,%h0" /* swap bytes */ - : "=q" (x) - : "0" (x)); + __asm__("xchgb %b0,%h0" /* swap bytes */ \ + : "=q" (x) \ + : "0" (x)); \ return x; } -#ifndef __STRICT_ANSI__ -static inline __u64 ___arch__swab64(__u64 val) -{ - union { - struct { __u32 a,b; } s; - __u64 u; - } v; - v.u = val; -#ifdef CONFIG_X86_BSWAP - asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" - : "=r" (v.s.a), "=r" (v.s.b) - : "0" (v.s.a), "1" (v.s.b)); -#else - v.s.a = ___arch__swab32(v.s.a); - v.s.b = ___arch__swab32(v.s.b); - asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b)); -#endif - return v.u; -} - -#define __BYTEORDER_HAS_U64__ -#define __arch__swab64(x) ___arch__swab64(x) - -#endif /* !__STRICT_ANSI__ */ - #define __arch__swab32(x) ___arch__swab32(x) #define __arch__swab16(x) ___arch__swab16(x) +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + #endif /* __GNUC__ */ #include diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/cpufeature.h linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/cpufeature.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/cpufeature.h 2003-05-03 02:33:29.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/cpufeature.h 2003-08-17 21:31:42.000000000 +0200 @@ -10,9 +10,9 @@ /* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */ #define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT) -#define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */ +#define NCAPINTS 6 /* Currently we have 4 32-bit words worth of info */ -/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */ +/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ #define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */ #define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */ @@ -65,6 +65,17 @@ #define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */ #define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */ +/* cpu types for specific tunings: */ +#define X86_FEATURE_K8 (3*32+ 4) /* Opteron, Athlon64 */ +#define X86_FEATURE_K7 (3*32+ 5) /* Athlon */ +#define X86_FEATURE_P3 (3*32+ 6) /* P3 */ +#define X86_FEATURE_P4 (3*32+ 7) /* P4 */ + +/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ +#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ + +/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ +#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) #define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability) @@ -76,6 +87,7 @@ #define cpu_has_tsc boot_cpu_has(X86_FEATURE_TSC) #define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE) #define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE) +#define cpu_has_sse2 boot_cpu_has(X86_FEATURE_XMM2) #define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC) #define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8) #define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR) @@ -87,6 +99,7 @@ #define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR) #define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR) #define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR) +#define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE) #endif /* __ASM_I386_CPUFEATURE_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/hw_irq.h linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/hw_irq.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/hw_irq.h 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/hw_irq.h 2003-08-17 21:31:38.000000000 +0200 @@ -144,6 +144,7 @@ extern char _stext, _etext; asmlinkage void x(void); \ asmlinkage void call_##x(void); \ __asm__( \ +"\n .text" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ "pushl $"#v"-256\n\t" \ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/kdb.h linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/kdb.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/kdb.h 2003-05-13 12:18:56.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/kdb.h 2003-08-17 21:26:24.000000000 +0200 @@ -41,7 +41,7 @@ * is intended to be used from interrupt level, it must use * a non-maskable entry method. */ -#define KDB_ENTER() if (kdb_on && !KDB_IS_RUNNING()) { asm("\tint $129\n"); } +#define KDB_ENTER() do {if (kdb_on && !KDB_IS_RUNNING()) { asm("\tint $129\n"); }} while(0) /* * Needed for exported symbols. diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/keyboard.h linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/keyboard.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/keyboard.h 2003-05-13 12:20:12.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/keyboard.h 2003-08-17 21:31:40.000000000 +0200 @@ -13,12 +13,17 @@ #ifdef __KERNEL__ +#include #include #include #include #include #include +#ifndef CONFIG_PSKEYBOARD +#define kbd_controller_present() 0 +#endif + #define KEYBOARD_IRQ 1 #define DISABLE_KBD_DURING_INTERRUPTS 0 @@ -50,10 +55,17 @@ extern unsigned char pckbd_sysrq_xlate[1 "keyboard", NULL) /* How to access the keyboard macros on this platform. */ +#ifdef CONFIG_PSKEYBOARD #define kbd_read_input() inb(KBD_DATA_REG) #define kbd_read_status() inb(KBD_STATUS_REG) #define kbd_write_output(val) outb(val, KBD_DATA_REG) #define kbd_write_command(val) outb(val, KBD_CNTL_REG) +#else +#define kbd_read_input() 0 +#define kbd_read_status() 0 +#define kbd_write_output(val) +#define kbd_write_command(val) +#endif /* Some stoneage hardware needs delays after some operations. */ #define kbd_pause() do { } while(0) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/msr.h linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/msr.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-i386/msr.h 2003-05-03 02:33:19.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-i386/msr.h 2003-08-17 21:31:42.000000000 +0200 @@ -110,6 +110,7 @@ /* VIA Cyrix defined MSRs*/ #define MSR_VIA_FCR 0x1107 #define MSR_VIA_LONGHAUL 0x110a +#define MSR_VIA_RNG 0x110b #define MSR_VIA_BCR2 0x1147 /* Transmeta defined MSRs */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-sh/ioctl.h linux-2.4.20-wolk4.7-fullkernel/include/asm-sh/ioctl.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-sh/ioctl.h 2003-05-03 01:54:08.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-sh/ioctl.h 2001-10-15 22:36:48.000000000 +0200 @@ -1,4 +1,4 @@ -/* $Id: ioctl.h,v 1.1 1999/09/18 17:29:53 gniibe Exp $ +/* $Id: ioctl.h,v 1.1 2000/04/14 16:48:21 mjd Exp $ * * linux/ioctl.h for Linux by H.H. Bergman. */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-sparc64/unistd.h linux-2.4.20-wolk4.7-fullkernel/include/asm-sparc64/unistd.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-sparc64/unistd.h 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-sparc64/unistd.h 2003-08-17 21:30:38.000000000 +0200 @@ -276,9 +276,9 @@ #define __NR_new_s_context 256 #define __NR_set_ipv4root 257 -/* RSBAC - we use 270 */ +/* RSBAC - we just use 235, which seems to be unused */ #ifdef CONFIG_RSBAC -#define __NR_rsbac 270 +#define __NR_rsbac 235 #endif #define _syscall0(type,name) \ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/asm-x86_64/unistd.h linux-2.4.20-wolk4.7-fullkernel/include/asm-x86_64/unistd.h --- linux-2.4.20-wolk4.6-fullkernel/include/asm-x86_64/unistd.h 2003-05-03 02:37:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/asm-x86_64/unistd.h 2003-08-17 21:30:38.000000000 +0200 @@ -484,11 +484,6 @@ __SYSCALL(__NR_io_cancel, sys_io_cancel) #define __NR_syscall_max __NR_io_cancel -/* RSBAC */ -#ifdef CONFIG_RSBAC -#define __NR_rsbac __NR_security -#endif - #ifndef __NO_STUBS #define __syscall_clobber "r11","rcx","memory" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/brlock.h linux-2.4.20-wolk4.7-fullkernel/include/linux/brlock.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/brlock.h 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/brlock.h 2003-08-17 21:31:35.000000000 +0200 @@ -37,7 +37,6 @@ enum brlock_indices { BR_AIO_REQ_LOCK, BR_LRU_LOCK, BR_HIPAC_LOCK, - BR_PAGECACHE_LOCK, __BR_END }; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms.h 2003-05-03 03:22:27.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,554 +0,0 @@ -/* -*- linux-c -*- */ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/include/linux/evms/evms.h - * - * EVMS kernel header file - * - */ - -#ifndef __EVMS_INCLUDED__ -#define __EVMS_INCLUDED__ 1 - -#include -#include -#include -#include - -/** - * version info - **/ -#define EVMS_MAJOR_VERSION 1 -#define EVMS_MINOR_VERSION 2 -#define EVMS_PATCHLEVEL_VERSION 1 - -/** - * general defines section - **/ -#define FALSE 0 -#define TRUE 1 - -#define MAX_EVMS_VOLUMES 256 -#define EVMS_VOLUME_NAME_SIZE 127 -#define IBM_OEM_ID 8112 -#define EVMS_INITIAL_CRC 0xFFFFFFFF -#define EVMS_MAGIC_CRC 0x31415926 -#define EVMS_VSECTOR_SIZE 512 -#define EVMS_VSECTOR_SIZE_SHIFT 9 - -#define DEV_PATH "/dev" -#define EVMS_DIR_NAME "evms" -#define EVMS_DEV_NAME "block_device" -#define EVMS_DEV_NODE_PATH DEV_PATH "/" EVMS_DIR_NAME "/" -#define EVMS_DEVICE_NAME DEV_PATH "/" EVMS_DIR_NAME "/" EVMS_DEV_NAME - -/** - * kernel logging levels defines - **/ -#define EVMS_INFO_CRITICAL 0 -#define EVMS_INFO_SERIOUS 1 -#define EVMS_INFO_ERROR 2 -#define EVMS_INFO_WARNING 3 -#define EVMS_INFO_DEFAULT 5 -#define EVMS_INFO_DETAILS 6 -#define EVMS_INFO_DEBUG 7 -#define EVMS_INFO_EXTRA 8 -#define EVMS_INFO_ENTRY_EXIT 9 -#define EVMS_INFO_EVERYTHING 10 - -/** - * kernel logging level variable - **/ -extern int evms_info_level; - -/** - * LOG MACROS to make evms log messages - * look much cleaner in the source. - **/ -#define EVMS_LOG_PREFIX "evms: " -#define evmsLOG(info_level, prspec) { if (evms_info_level >= info_level) printk prspec; } -#define LOG_CRITICAL(msg, args...) evmsLOG(EVMS_INFO_CRITICAL, (KERN_CRIT EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_SERIOUS(msg, args...) evmsLOG(EVMS_INFO_SERIOUS, (KERN_ERR EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_ERROR(msg, args...) evmsLOG(EVMS_INFO_ERROR, (KERN_ERR EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_WARNING(msg, args...) evmsLOG(EVMS_INFO_WARNING, (KERN_WARNING EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_DEFAULT(msg, args...) evmsLOG(EVMS_INFO_DEFAULT, (KERN_INFO EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_DETAILS(msg, args...) evmsLOG(EVMS_INFO_DETAILS, (KERN_INFO EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_DEBUG(msg, args...) evmsLOG(EVMS_INFO_DEBUG, (KERN_INFO EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_EXTRA(msg, args...) evmsLOG(EVMS_INFO_EXTRA, (KERN_INFO EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_ENTRY_EXIT(msg, args...) evmsLOG(EVMS_INFO_ENTRY_EXIT, (KERN_INFO EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) -#define LOG_EVERYTHING(msg, args...) evmsLOG(EVMS_INFO_EVERYTHING, (KERN_INFO EVMS_LOG_PREFIX LOG_PREFIX msg, ## args)) - -/** - * Macros to cleanly print 64-bit numbers on both 32-bit and 64-bit machines. - * Use these in place of %Ld, %Lu, and %Lx. - **/ -#if BITS_PER_LONG > 32 -#define PFD64 "%ld" -#define PFU64 "%lu" -#define PFX64 "%lx" -#else -#define PFD64 "%Ld" -#define PFU64 "%Lu" -#define PFX64 "%Lx" -#endif - -/** - * helpful PROCFS macro - **/ -#define PROCPRINT(msg, args...) (sz += sprintf(page + sz, msg, ## args));\ - if (sz < off)\ - off -= sz, sz = 0;\ - else if (sz >= off + count)\ - goto out - -/** - * PluginID convenience macros - * - * An EVMS PluginID is a 32-bit number with the following bit positions: - * Top 16 bits: OEM identifier. See IBM_OEM_ID. - * Next 4 bits: Plugin type identifier. See evms_plugin_code. - * Lowest 12 bits: Individual plugin identifier within a given plugin type. - **/ -#define SetPluginID(oem, type, id) ((oem << 16) | (type << 12) | id) -#define GetPluginOEM(pluginid) (pluginid >> 16) -#define GetPluginType(pluginid) ((pluginid >> 12) & 0xf) -#define GetPluginID(pluginid) (pluginid & 0xfff) - -/** - * enum evms_plugin_type - evms plugin types - **/ -enum evms_plugin_code { - EVMS_NO_PLUGIN = 0, - EVMS_DEVICE_MANAGER, - EVMS_SEGMENT_MANAGER, - EVMS_REGION_MANAGER, - EVMS_FEATURE, - EVMS_ASSOCIATIVE_FEATURE, - EVMS_FILESYSTEM_INTERFACE_MODULE, - EVMS_CLUSTER_MANAGER_INTERFACE_MODULE, - EVMS_DISTRIBUTED_LOCK_MANAGER_INTERFACE_MODULE -}; - -/** - * struct evms_version - - * @major: changes when incompatible difference are introduced - * @minor: changes when additions are made - * @patchlevel: reflects bug level fixes within a particular major/minor pair - * - * generic versioning info used by EVMS - **/ -struct evms_version { - u32 major; - u32 minor; - u32 patchlevel; -}; - -/** - * struct evms_plugin_header - kernel plugin header record - * @id: plugin id - * @version: plugin version - * @required_services_version: required common services version - * @fops: table of function operations - * - * kernel plugin header record - **/ -struct evms_plugin_header { - u32 id; - struct evms_version version; - struct evms_version required_services_version; - struct evms_plugin_fops *fops; -}; - -/** - * struct evms_feature_header - EVMS generic on-disk header for features - * @signature: unique magic number - * @crc: structure's crc - * @version: feature header version - * @engine_version: created by this evms engine version - * @flags: feature characteristics, bit definitions below. - * @feature_id: indicates which feature this header is describing - * @sequence_number: describes most recent copy of redundant metadata - * @alignment_padding: used when objects are moved between different sized devices - * @feature_data1_start_lsn: object relative start of 1st copy feature data - * @feature_data1_size: size of 1st copy of feature data - * @feature_data2_start_lsn: object relative start of 2nd copy feature data - * @feature_data2_size: size of 2nd copy of feature data - * @volume_serial_number: unique/persistent volume identifier - * @volume_system_id: unique/persistent minor number - * @object_depth: depth of object in volume tree - * @object_name: object's name - * @volume_name: volume name object is a part of - * @pad: padding to make structure be 512 byte aligned - * - * generic on-disk header used to describe any EVMS feature - * NOTE: 2nd copy of feature data is optional, if used set start_lsn to 0. - **/ -struct evms_feature_header { - u32 signature; - u32 crc; - struct evms_version version; - struct evms_version engine_version; - u32 flags; - u32 feature_id; - u64 sequence_number; - u64 alignment_padding; - u64 feature_data1_start_lsn; - u64 feature_data1_size; - u64 feature_data2_start_lsn; - u64 feature_data2_size; - u64 volume_serial_number; - u32 volume_system_id; - u32 object_depth; - u8 object_name[EVMS_VOLUME_NAME_SIZE + 1]; - u8 volume_name[EVMS_VOLUME_NAME_SIZE + 1]; - u8 pad[152]; -}; - -/** - * field evms_feature_header.signature majic number - **/ -#define EVMS_FEATURE_HEADER_SIGNATURE 0x54414546 /* FEAT */ -/** - * field evms_feature_header.flags defines - **/ -#define EVMS_FEATURE_ACTIVE (1<<0) -#define EVMS_FEATURE_VOLUME_COMPLETE (1<<1) -#define EVMS_VOLUME_DATA_OBJECT (1<<16) -#define EVMS_VOLUME_DATA_STOP (1<<17) -/** - * struct evms_feature_header version info - **/ -#define EVMS_FEATURE_HEADER_MAJOR 3 -#define EVMS_FEATURE_HEADER_MINOR 0 -#define EVMS_FEATURE_HEADER_PATCHLEVEL 0 - -/** - * EVMS specific error codes - **/ -#define EVMS_FEATURE_FATAL_ERROR 257 -#define EVMS_VOLUME_FATAL_ERROR 258 -#define EVMS_FEATURE_INCOMPLETE_ERROR 259 - -/** - * struct evms_volume_info - exported volume info - * @volume_sn: unique volume identifier - * @volume_minor: persistent device minor assigned to this volume - * @volume_name: persistent name assigned to this volume - * - * a collection of volume specific info - **/ -struct evms_volume_info { - u64 volume_sn; - u32 volume_minor; - u8 volume_name[EVMS_VOLUME_NAME_SIZE + 1]; -}; - -/** - * struct evms_logical_node - generic kernel storage object - * @total_vsectors: 0 size of this object in 512 byte units - * @plugin: 8 plugin that created/owns/manages this storage object - * @private: 12 location for owner to store private info - * @flags: 16 storage object characteristics (set/used by plugins) - * bit definitions located in evms_common.h - * @iflags: 20 internal flags (used exclusively by the framework, not for plugins to use/set) - * bit definitions below. - * @hardsector_size: 24 assumed physical sector size of underlying device - * @block_size: 28 default block size for this object - * @system_id: 32 system indicator (set by the segment manager) - * @volume_info: 36 persistent volume info, used only by EVMS volumes - * @feature_header: 40 generic on-disk metadata describing any EVMS feature - * @next: 44 linked list field - * @name: 48 storage object name - * 176 - * - * generic kernel storage object - */ -struct evms_logical_node { - u64 total_vsectors; - struct evms_plugin_header *plugin; - void *private; - u32 flags; - u32 iflags; - int hardsector_size; - int block_size; - u32 system_id; - struct evms_volume_info *volume_info; - struct evms_feature_header *feature_header; - struct evms_logical_node *next; - u8 name[EVMS_VOLUME_NAME_SIZE + 1]; -}; - -/** - * fields evms_logical_node.flags & evms_logical_volume.flags defines - **/ -#define EVMS_FLAGS_WIDTH 32 -#define EVMS_VOLUME_FLAG (1<<0) -#define EVMS_VOLUME_PARTIAL_FLAG (1<<1) -#define EVMS_VOLUME_PARTIAL (1<<1) -#define EVMS_VOLUME_SET_READ_ONLY (1<<2) -#define EVMS_VOLUME_READ_ONLY (1<<2) -/** - * these bits define volume status - **/ -#define EVMS_MEDIA_CHANGED (1<<20) -#define EVMS_DEVICE_UNPLUGGED (1<<21) -/** - * these bits used for removable status - **/ -#define EVMS_DEVICE_MEDIA_PRESENT (1<<24) -#define EVMS_DEVICE_PRESENT (1<<25) -#define EVMS_DEVICE_LOCKABLE (1<<26) -#define EVMS_DEVICE_REMOVABLE (1<<27) - -/** - * fields evms_logical_node.iflags defines - **/ -#define EVMS_FEATURE_BOTTOM (1<<0) -#define EVMS_TOP_SEGMENT (1<<1) - -/** - * macro to obtain a node's name from either EVMS or compatibility volumes - **/ -#define EVMS_GET_NODE_NAME(node) ((node->flags & EVMS_VOLUME_FLAG) ? \ - node->volume_info->volume_name : \ - node->name) - -/** - * macro used to transform to/from userland device handles and device storage object nodes - **/ -#define EVMS_HANDLE_KEY 0x0123456789ABCDEF -#define DEV_HANDLE_TO_NODE(handle) ((struct evms_logical_node *)(unsigned long)((handle) ^ EVMS_HANDLE_KEY)) -#define NODE_TO_DEV_HANDLE(node) (((u64)(unsigned long)(node)) ^ EVMS_HANDLE_KEY) - -/** - * struct evms_logical_volume - logical volume info - * @name: logical volume name - * @node: logical volume storage object - * @flags: characteristics of logical volume - * @quiesced: quiesce state info - * @vfs_quiesced: vfs quiesce state info - * @opens: count of times the volume has been opened - * @requests_in_progress: count of in-flight I/Os - * @wait_queue: used when volume is quiesced - * @devfs_handle: handle for devfs - * @request_queue: unique request queue - * - * contains all the fields needed to manage to a logical volume - **/ -struct evms_logical_volume { - u8 *name; - struct evms_logical_node *node; - int flags; - int quiesced; - int vfs_quiesced; - atomic_t opens; - atomic_t requests_in_progress; - wait_queue_head_t wait_queue; - devfs_handle_t devfs_handle; - request_queue_t request_queue; -}; - -/** - * field evms_logical_volume.flags defines - **/ -/** - * queued flags bits - **/ -#define EVMS_REQUESTED_DELETE (1<<5) -#define EVMS_REQUESTED_QUIESCE (1<<6) -#define EVMS_REQUESTED_VFS_QUIESCE (1<<7) -/** - * this bit indicates corruption - **/ -#define EVMS_VOLUME_CORRUPT (1<<8) -/** - * these bits define the source of the corruption - **/ -#define EVMS_VOLUME_SOFT_DELETED (1<<9) -#define EVMS_DEVICE_UNAVAILABLE (1<<10) - -/* - * The following function table is used for all plugins. - */ -/** - * struct evms_plugin_fops - evms plugin's table of function operations - * @discover: volume discovery entry point - * @end_discover: final discovery entry point - * @delete: delete volume entry point - * @read: asynchronous read entry point - * @write: asynchronous write entry point - * @init_io: synchronous io entry point - * @ioctl: generic ioctl entry point - * @direct_ioctl: non-generic ioctl entry point - * - * evms plugin's table of function operations - **/ -struct evms_plugin_fops { - int (*discover) (struct evms_logical_node **); - int (*end_discover) (struct evms_logical_node **); - int (*delete) (struct evms_logical_node *); - void (*read) (struct evms_logical_node *, struct buffer_head *); - void (*write) (struct evms_logical_node *, struct buffer_head *); - int (*init_io) (struct evms_logical_node *, int, u64, - u64, void *); - int (*ioctl) (struct evms_logical_node *, struct inode *, - struct file *, u32, unsigned long); - int (*direct_ioctl) (struct inode *, struct file *, - u32, unsigned long); -}; - -/** - * convenience macros to use plugin's fops entry points - **/ -#define DISCOVER(node, list) ((node)->plugin->fops->discover(list)) -#define END_DISCOVER(node, list) ((node)->plugin->fops->end_discover(list)) -#define DELETE(node) ((node)->plugin->fops->delete(node)) -#define R_IO(node, bh) ((node)->plugin->fops->read(node, bh)) -#define W_IO(node, bh) ((node)->plugin->fops->write(node, bh)) -#define INIT_IO(node, rw_flag, start_sec, num_secs, buf_addr) ((node)->plugin->fops->init_io(node, rw_flag, start_sec, num_secs, buf_addr)) -#define IOCTL(node, inode, file, cmd, arg) ((node)->plugin->fops->ioctl(node, inode, file, cmd, arg)) -#define DIRECT_IOCTL(reg_record, inode, file, cmd, arg) ((reg_record)->plugin->fops->direct_ioctl(inode, file, cmd, arg)) - -/** - * struct evms_list_node - generic non-imbedded list node object - * @item: ptr to object in list - * @next: ptr to next item in list - * - * light weight generic non-imbedded list object definition - **/ -struct evms_list_node { - void *item; - struct evms_list_node *next; -}; - -/** - * struct evms_pool_mgmt - anchor block for private pool management - * @cachep: kmem_cache_t variable - * @member_size: size of each element in the pool - * @head: - * @waiters: count of waiters - * @wait_queue: list of waiters - * @name: name of the pool (must be less than 20 chars) - * - * anchor block for private pool management - **/ -struct evms_pool_mgmt { - kmem_cache_t *cachep; - int member_size; - void *head; - atomic_t waiters; - wait_queue_head_t wait_queue; - u8 *name; -}; - -/* - * Notes: - * All of the following kernel thread functions belong to EVMS base. - * These functions were copied from md_core.c - */ -#define EVMS_THREAD_WAKEUP 0 -/** - * struct evms_thread - * @run: - * @data: - * @wqueue: thread wait queue - * @flags: thread attributes - * @event: event completion - * @tsk: task info - * @name: thread name - * - * data structure for creating/managing a kernel thread - **/ -struct evms_thread { - void (*run) (void *data); - void *data; - wait_queue_head_t wqueue; - unsigned long flags; - struct completion *event; - struct task_struct *tsk; - const u8 *name; -}; - -/** - * EVMS (common services) exported functions prototypes - * - * since these function names are global, evms_cs_ has been prepended - * to each function name, to ensure they do not collide with any - * other global functions in the kernel. - **/ -#define EVMS_COMMON_SERVICES_MAJOR 0 -#define EVMS_COMMON_SERVICES_MINOR 6 -#define EVMS_COMMON_SERVICES_PATCHLEVEL 0 - -extern int evms_cs_check_version(struct evms_version *, struct evms_version *); -extern int evms_cs_allocate_logical_node(struct evms_logical_node **); -extern void evms_cs_deallocate_volume_info(struct evms_logical_node *); -extern void evms_cs_deallocate_logical_node(struct evms_logical_node *); -extern int evms_cs_register_plugin(struct evms_plugin_header *); -extern int evms_cs_unregister_plugin(struct evms_plugin_header *); -extern int evms_cs_add_logical_node_to_list(struct evms_logical_node **, - struct evms_logical_node *); -extern int evms_cs_remove_logical_node_from_list(struct evms_logical_node **, - struct evms_logical_node *); -extern int evms_cs_kernel_ioctl(struct evms_logical_node *, u32, unsigned long); -inline unsigned long evms_cs_size_in_vsectors(long long); -inline int evms_cs_log2(long long); -extern u32 evms_cs_calculate_crc(u32, void *, u32); -#define EVMS_BLOCKABLE TRUE -extern struct evms_pool_mgmt *evms_cs_create_pool(int, u8 *, - void (*ctor)(void *, kmem_cache_t *, - unsigned long), - void (*dtor)(void *, kmem_cache_t *, - unsigned long)); -extern void *evms_cs_allocate_from_pool(struct evms_pool_mgmt *, int); -extern void evms_cs_deallocate_to_pool(struct evms_pool_mgmt *, void *); -extern void evms_cs_destroy_pool(struct evms_pool_mgmt *); -extern int evms_cs_register_for_end_io_notification(void *, - struct buffer_head *, - void *callback_function); -extern struct evms_list_node **evms_cs_lookup_item_in_list(struct evms_list_node **, - void *); -extern int evms_cs_add_item_to_list(struct evms_list_node **, void *); -extern int evms_cs_remove_item_from_list(struct evms_list_node **, void *); -extern int evms_cs_register_device(struct evms_logical_node *); -extern int evms_cs_unregister_device(struct evms_logical_node *); -extern int evms_cs_find_next_device(struct evms_logical_node *, - struct evms_logical_node **); -extern void evms_cs_signal_event(int); -extern struct evms_thread *evms_cs_register_thread(void (*run)(void *), - void *data, const u8 *name); -extern void evms_cs_unregister_thread(struct evms_thread *thread); -extern void evms_cs_wakeup_thread(struct evms_thread *thread); -extern void evms_cs_interrupt_thread(struct evms_thread *thread); -extern struct proc_dir_entry *evms_cs_get_evms_proc_dir(void); -extern int evms_cs_volume_request_in_progress(kdev_t, int, int *); -extern void evms_cs_invalidate_volume(struct evms_logical_node *topmost_node); - -/* EVMS exported global variables */ -extern struct evms_pool_mgmt *evms_bh_pool; -extern u8 *evms_primary_string; -extern u8 *evms_secondary_string; - -/* Have to include this at the end, since it depends - * on structures and definitions in this file. - */ -#include - -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_aix.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_aix.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_aix.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_aix.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,428 +0,0 @@ -/* -* The following structures are nested within the structures used by the -* system management routines. These structures and sizes were pulled from the AIX -* src tree. -*/ -#define LVM_MAXLPS 65535 /* max number of logical partitions allowed */ -#define LVM_NAMESIZ 64 /* maximum size for the logical volume name */ -#define LVM_NUMCOPIES 3 /* max number of copies allowed of a logical partition */ -#define LVM_MAXVGS 255 -#define LVM_MAXPVS 32 -#define LVM_MAXLVS 256 -#define AIX_MIN_BLOCK_SIZE 4096 -#define VGSA_BT_PV 127 -#define NBPI 32 -#define TRUE 1 -#define OFFSET_CONSTANT 144 -#define SLEEP_TIME 0 -#define MAXLVS_OFFSET 16 -#define PHYS_VOL_OFFSET 34 -#define AIX_PVHPP_LENGTH PHYS_VOL_OFFSET -#define MAX_SECTORS_NAMELIST 32 -#define AIX_DEFAULT_MIRRORING 1 -#define AIX_FIRST_MIRROR 2 -#define AIX_MAX_MIRRORS 3 // AIX defines ALL copies as mirrors - 3 mirrors MAX - 1 orig and 2 copies - -#define EVMS_AIX_FEATURE_ID 3 - -#define EVMS_AIX_RESYNC_MIRRORS 1 - -#define PSN_LVM_REC 7 -#define PSN_VGSA_REC 128 -#define PSN_NAMELIST_REC 2065 -#define PSN_VGT_TRAILER 135 -#define PSN_LVE_REC 1 -#define PSN_PPH_OFFSET 17 -#define PSN_PVH_INCREMENT 17 -#define AIX_MIN_PVH_SIZE 271 // used to find the PV header info for Pv's other than 0 -#define AIX_SECTOR_SIZE 512 -#define MAX_PPENT_SECTOR 16 -#define NAME_LEN 128 /* don't change!!! */ -#define UUID_LEN 32 /* don't change!!! */ -#define MAX_SECTORS_LV_ENTRIES 16 -#define AIX_MIN_MIRROR_POOL 10 -#define AIX_MIRROR_POOL_CHANGE 10 - -#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 LV_BMAP _IOWR ( 0xfe, 0x30, 1) - -#define LV_ACTIVE 0x01 /* lv_status */ -#define LV_SPINDOWN 0x02 /* " */ -#define LV_ERROR 0x99 /* " */ - -#define VG_ACTIVE 0x01 /* vg_status */ - -#define AIX_LV_READ 0x00 /* lv_access */ -#define AIX_LV_WRITE 0x01 /* " */ -#define EVMS_LV_NEW 0x10 // volume was created during the current discovery pass -#define EVMS_LV_INCOMPLETE 0x20 // volume has an incomplete LE map -#define EVMS_LV_INVALID 0x40 // volume has a memory-corruption problem - -/* vg flags */ -#define AIX_VG_DIRTY 0x01 // group has had a new PV added during this discovery -#define AIX_VG_INCOMPLETE 0x20 // volume group is incomplete - -#define AIX_LVM_LVUNDEF 0 /* the logical volume is not defined to a */ -/* volume group */ -#define AIX_LVM_LVDEFINED 1 /* the logical volume is defined to a */ -/* volume group */ -#define AIX_LVM_LVSTALE 2 /* the logical volume has stale logical */ -/* partitions */ -#define AIX_LVM_LVMIRBKP 4 /* the logical volume is an online mirror backup */ -/* We are skipping '3' since it is used by CMDLVM_LVSTALE */ -/* as an addition of LVM_LVDEFINE + LVM_LVSTALE, and is */ -/* defined in src/bos/usr/sbin/lvm/include/ls.h */ - - - -#define LOG_PREFIX "--AIXlvm: " - -// Entries in the list of physical volumes (PV) -// in a volume group (VG) - -struct unique_id { - u32 word1; - u32 word2; - u32 word3; - u32 word4; -}; - -struct partition_list_entry { - struct evms_logical_node * logical_node; - u32 pv_number; - u32 block_size; // bytes - u32 hard_sect_size; // bytes - struct partition_list_entry * next; - -}; - -// Table for mapping logical extents (LE) to physical extents (PE) -struct pe_table_entry { - struct partition_list_entry * owning_pv; - u64 pe_sector_offset; - char pp_state; -}; - -// Logical volumes (LV) in a volume group (VG) -struct aix_logical_volume { - u32 lv_number; - u64 lv_size; // Sectors - u32 lv_access; // Flags: LV_READ, LV_WRITE, LN_NEW - u32 lv_status; // Flags: LV_ACTIVE, LV_SPINDOWN -// u32 lv_minor; // Device minor number - u32 mirror_copies; // Do we have mirroring and how many ? -// u32 mirror_number; // mirror number - which copy is this ? -// u32 mirror_iterations; // Which mirror should we be writing to ? - u32 stripes; - u32 stripe_size; // Sectors - u32 stripe_size_shift; // Number of bits to shift right instead of dividing by stripe_size - u32 pe_size; // Sectors - u32 pe_size_shift; // Number of bits to shift right instead of dividing by pe_size - u32 num_le; // Number of entries in the le_to_pe_map -// u32 new_volume; // Flag to indicate if this volume needs to be exported - struct aix_volume_group * group; // Pointer back to parent volume group - unsigned char name[EVMS_VOLUME_NAME_SIZE+1]; // Dev-tree volume name (eg: /dev/group0/vol0) - struct pe_table_entry * le_to_pe_map; // Mapping of logical to physical extents - struct pe_table_entry * le_to_pe_map_mir1; // Mapping of logical to physical extents for mirror 1 - struct pe_table_entry * le_to_pe_map_mir2; // Mapping of logical to physical extents for mirror 2 - struct evms_logical_node * volume_node; // Pointer to the parent EVMS node representing this volume - -}; - -// Volume groups (VG) -struct aix_volume_group { - struct unique_id vg_id; // volume group number */ - struct partition_list_entry * partition_list; // List of partitions/segments/PVs that make up this VG - struct aix_logical_volume ** volume_list; // Array of volumes found in this VG. - struct aix_volume_group * next; // Pointer to the next VG - struct vg_header * AIXvgh; // Pointer to valid data area on disk for the VG - s32 vgda_psn; // Which VGDA we should use -// u32 numpvs; // Number of PVs found on this VG. - u32 numlvs; // Number of LVs found on this VG. - u32 hard_sect_size; // The largest hard_sect_size and block_size - u32 block_size; // values of all partitions in this group. - u32 flags; // -// u32 lv_max; // maximum logical volumes */ - u32 pe_size; // physical extent size in sectors */ - u32 partition_count; // actual partitions found for this group - u32 CleanVGInfo; // Do we have a clean VG Info to work with ? - u32 vgda_len; // length of the volume group descriptor area */ -}; - -struct aix_resync_struct { - u64 master_offset; - u64 slave1_offset; - u64 slave2_offset; - struct partition_list_entry * master_part; // - struct partition_list_entry * slave1_part; // - struct partition_list_entry * slave2_part; // - struct aix_logical_volume * resync_vol; - struct aix_logical_volume * next_resync_vol; -}; - -struct aix_mirror_bh { - atomic_t remaining; - s32 iteration; // 'have we finished' count, used from IRQ handlers - u32 le; // In case we have to flag this pp as stale later. - s32 cmd; - u64 mir_sector1; - u64 mir_sector2; - struct buffer_head *master_bh; - struct buffer_head bh_req; - struct aix_mirror_bh *mirror_bh_list; - struct evms_logical_node *node; // map to evms node (READ only) - struct evms_logical_node *mir_node1; // - struct evms_logical_node *mir_node2; // - struct aix_mirror_bh *next_r1; // next for retry or in free list - char sync_flag; // Flag for resyncing of mirrored PPs -}; - -struct aix_volume_resync_ioctl { - char object_name[EVMS_VOLUME_NAME_SIZE+1]; // Input - Name of bbr object from feature header - s32 force; -}; - -struct timestruc { - int tv_sec; - int tv_nsec; - -}; - -struct aix_ipl_rec_area { - u32 IPL_record_id; /* This physical volume contains a */ - /* valid IPL record if and only if */ - /* this field contains IPLRECID */ - -#define IPLRECID 0xc9c2d4c1 /* Value is EBCIDIC 'IBMA' */ - - char reserved1[20]; - u32 formatted_cap; /* Formatted capacity. The number of */ - /* sectors available after formatting*/ - /* The presence or absence of bad */ - /* blocks does not alter this value. */ - - char last_head; /* THIS IS DISKETTE INFORMATION */ - /* The number of heads minus 1. Heads*/ - /* are number from 0 to last_head. */ - - char last_sector; /* THIS IS DISKETTE INFORMATION */ - /* The number of sectors per track. */ - /* Sectors are numbered from 1 to */ - /* last_sector. */ - - char reserved2[6]; - - u32 boot_code_length; /* Boot code length in sectors. A 0 */ - /* value implies no boot code present*/ - - u32 boot_code_offset; /* Boot code offset. Must be 0 if no */ - /* boot code present, else contains */ - /* byte offset from start of boot */ - /* code to first instruction. */ - - u32 boot_lv_start; /* Contains the PSN of the start of */ - /* the BLV. */ - - u32 boot_prg_start; /* Boot code start. Must be 0 if no */ - /* boot code present, else contains */ - /* the PSN of the start of boot code.*/ - - u32 boot_lv_length; /* BLV length in sectors. */ - - u32 boot_load_add; /* 512 byte boundary load address for*/ - /* boot code. */ - - char boot_frag; /* Boot code fragmentation flag. Must*/ - /* be 0 if no fragmentation allowed, */ - /* else must be 0x01. */ - - char boot_emulation; /* ROS network emulation flag */ - /* 0x0 => not an emul support image */ - /* 0x1 => ROS network emulation code */ - /* 0x2 => AIX code supporting ROS emul*/ - - char reserved3[2]; - - u16 basecn_length; /* Number of sectors for base */ - /* customization. Normal mode. */ - - u16 basecs_length; /* Number of sectors for base */ - /* customization. Service mode. */ - - u32 basecn_start; /* Starting PSN value for base */ - /* customization. Normal mode. */ - - u32 basecs_start; /* Starting PSN value for base */ - /* customization. Service mode. */ - - char reserved4[24]; - - u32 ser_code_length; /* Service code length in sectors. */ - /* A 0 value implies no service code */ - /* present. */ - - u32 ser_code_offset; /* Service code offset. Must be 0 if */ - /* no service code is present, else */ - /* contains byte offset from start of*/ - /* service code to first instruction.*/ - - u32 ser_lv_start; /* Contains the PSN of the start of */ - /* the SLV. */ - - u32 ser_prg_start; /* Service code start. Must be 0 if */ - /* service code is not present, else */ - /* contains the PSN of the start of */ - /* service code. */ - - u32 ser_lv_length; /* SLV length in sectors. */ - - u32 ser_load_add; /* 512 byte boundary load address for*/ - /* service code. */ - - char ser_frag; /* Service code fragmentation flag. */ - /* Must be 0 if no fragmentation */ - /* allowed, else must be 0x01. */ - - char ser_emulation; /* ROS network emulation flag */ - /* 0x0 => not an emul support image */ - /* 0x1 => ROS network emulation code */ - /* 0x2 => AIX code supporting ROS emul*/ - - char reserved5[2]; - - struct unique_id pv_id; /* The unique identifier for this */ - /* physical volume. */ - char dummy[512 - 128 - sizeof(struct unique_id)]; -}; - - -struct AIXlvm_rec -/* structure which describes the physical volume LVM record */ { - u32 lvm_id; /* LVM id field which identifies whether the PV is a member of a volume group */ - -#define AIX_LVM_LVMID 0x5F4C564D /* LVM id field of ASCII "_LVM" */ - - struct unique_id vg_id; /* the id of the volume group to which this physical volume belongs */ - u32 lvmarea_len; /* the length of the LVM reserved area */ - u32 vgda_len; /* length of the volume group descriptor area */ - s32 vgda_psn [2]; /* the physical sector numbers of the beginning of the volume group descriptor area copies on this disk */ - s32 reloc_psn; /* the physical sector number of the beginning of a pool of blocks */ - /* (located at the end of the PV) which are reserved for the relocation of bad blocks */ - u32 reloc_len; /* the length in number of sectors of the pool of bad block relocation blocks */ - s16 pv_num; /* the physical volume number within the volume group of this physical volume */ - s16 pp_size; /* the size in bytes for the partition, expressed as a power of 2 (i.e., the partition size is 2 to the power pp_size) */ - u32 vgsa_len; /* length of the volume group status area */ - s32 vgsa_psn [2]; /* the physical sector numbers of the beginning of the volume group status area copies on this disk */ - s16 version; /* the version number of this volume group descriptor and status area */ - -#define LVM_VERSION_1 1 /* first version - AIX 3.0 */ -#define LVM_STRIPE_ENHANCE 2 /* version with striped lv's - AIX 4.1 */ -#define LVM_1024_PPSIZE 3 /* ppsizes of 512 and 1024 */ -#define LVM_GT_1016 4 /* version with support for > 1016 pps/pv */ -#define LVM_MAX_VERSION LVM_GT_1016 /* max version # */ - - char res1 [450]; /* reserved area */ - -}; - - - -/* II.Volume Group Descriptor Area */ - -struct vgsa_area { - struct timestruc b_tmstamp; /* Beginning timestamp */ - u32 pv_missing [(LVM_MAXPVS + (NBPI -1)) / NBPI]; /* Bit per PV */ - unsigned char stalepp [LVM_MAXPVS] [VGSA_BT_PV]; - s16 factor; - char resv[10]; /* Padding */ - struct timestruc e_tmstamp; /* Ending timestamp */ - -} ; - -struct vg_header { - struct timestruc vg_timestamp; /* time of last update */ - struct unique_id vg_id; /* unique id for volume group */ - s16 numlvs; /* number of lvs in vg */ - s16 maxlvs; /* max number of lvs allowed in vg */ - s16 pp_size; /* size of pps in the vg */ - s16 numpvs; /* number of pvs in the vg */ - s16 total_vgdas; /* number of copies of vg */ - /* descriptor area on disk */ - s16 vgda_size; /* size of volume group descriptor */ - s16 bigvg; - s16 quorum; - s16 auto_varyon; - s32 checksum; - s32 bigda_size; -}; - -struct lv_entries { - s16 lvname; /* name of LV */ - s16 res1; /* reserved area */ - s32 maxsize; /* maximum number of partitions allowed */ - char lv_state; /* state of logical volume */ - char mirror; /* none,single, or double */ - s16 mirror_policy; /* type of writing used to write */ - s32 num_lps; /* number of logical partitions on the lv */ - /* base 1 */ - char permissions; /* read write or read only */ - char bb_relocation; /* specifies if bad block */ - /* relocation is desired */ - char write_verify; /* verify all writes to the LV */ - char mirwrt_consist; /* mirror write consistency flag */ - u16 stripe_exp; /* stripe size in exponent value */ - u16 striping_width; /* stripe width */ - u16 lv_avoid; - u16 child_minor_num; - char res4[4]; /* reserved area on disk */ -}; - - -struct pv_header { - struct unique_id pv_id; /* unique identifier of PV */ - u16 pp_count; /* number of physical partitions */ - /* on PV */ - char pv_state; /* state of physical volume */ - char res1; /* reserved area on disk */ - s32 psn_part1; /* physical sector number of 1st pp */ - s16 pvnum_vgdas;/* number of vg descriptor areas */ - /* on the physical volume */ - s16 pv_num; /* PV number */ - u32 res2; /* reserved area on disk */ - -}; - -struct pp_entries { - s16 lv_index; /* index to lv pp is on */ - s16 res_1; /* reserved area on disk */ - u32 lp_num; /* log. part. number */ - char copy; /* the copy of the logical partition */ - /* that this pp is allocated for */ - char pp_state; /* current state of pp */ - char fst_alt_vol; /* pv where partition allocation for*/ - /* first mirror begins */ - char snd_alt_vol; /* pv where partition allocation for*/ - /* second mirror begins */ - s16 fst_alt_part; /* partition to begin first mirror */ - s16 snd_alt_part; /*partition to begin second mirror */ - u64 res_3; /* reserved area on disk */ - u64 res_4; /* reserved area on disk */ -}; - -struct namelist { - char name[LVM_MAXLVS][LVM_NAMESIZ]; -}; - -struct vg_trailer { - struct timestruc timestamp; /* time of last update */ - s16 concurrency; - /* MS Nibble = concurrent capable */ - /* LS Nibble = concurrent auto-varyon */ - s16 res_2; - s32 res_3; /* reserved area on disk */ - u64 res_4; /* reserved area on disk */ - u64 res_5; /* reserved area on disk */ -}; - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_bbr_k.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_bbr_k.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_bbr_k.h 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_bbr_k.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,222 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* linux/include/linux/evms/evms_bbr_k.h - * - * Kernel header file for Bad Block Relocation (BBR) Feature - * - * BBR feature is designed to remap I/O write failures to another safe location - * on disk. Note that most disk drives have BBR built into them, this means - * that our software BBR will be only activated when all hardware BBR - * replacement sectors have been used. - */ - -#ifndef __EVMS_BBR_K__ -#define __EVMS_BBR_K__ 1 - -#define EVMS_BBR_VERSION_MAJOR 1 -#define EVMS_BBR_VERSION_MINOR 1 -#define EVMS_BBR_VERSION_PATCHLEVEL 2 - -#define EVMS_BBR_COMMON_SERVICES_MAJOR 0 -#define EVMS_BBR_COMMON_SERVICES_MINOR 6 -#define EVMS_BBR_COMMON_SERVICES_PATCHLEVEL 0 - -#define EVMS_BBR_FEATURE_ID 6 -#define EVMS_BBR_SIGNATURE 0x42627246 /* BbrF */ -#define EVMS_BBR_TABLE_SIGNATURE 0x42627254 /* BbrT */ - -#define EVMS_BBR_ENTRIES_PER_SECT 31 -#define BBR_POOL_NAME_LENGTH 20 -#define BBR_STOP_REMAP (1<<0) -#define BBR_BH_USE_EVMS_CALLBACK (1<<0) - -/* BBR direct ioctl commands. - * - * BBR_GET_INFO_CMD: Return total number of sectors that are currently - * remapped for the specified BBR object. - * BBR_STOP_REMAP_CMD: Stop remapping. Do not remap any new sectors or even - * honor any existing remaps for the specified BBR object - * until the next rediscover command is received. - * BBR_SECTOR_IO_CMD: Process an I/O from the engine directly through the - * specified BBR object in the kernel. - */ -#define BBR_GET_INFO_CMD 1 -#define BBR_STOP_REMAP_CMD 2 -#define BBR_SECTOR_IO_CMD 3 - -/** - * struct evms_bbr_table_entry - * @bad_sect: LBA of bad location. - * @replacement_sect: LBA of new location. - * - * Structure to describe one BBR remap. - */ -struct evms_bbr_table_entry { - u64 bad_sect; - u64 replacement_sect; -}; - -/** - * struct evms_bbr_table - * @signature: Signature on each BBR table sector. - * @crc: CRC for this table sector. - * @sequence_number: Used to resolve conflicts when primary and secondary - * tables do not match. - * @in_use_cnt: Number of in-use table entries. - * @entries: Actual table of remaps. - * - * Structure to describe each sector of the metadata table. Each sector in this - * table can describe 31 remapped sectors. - */ -struct evms_bbr_table { - u32 signature; - u32 crc; - u32 sequence_number; - u32 in_use_cnt; - struct evms_bbr_table_entry entries[EVMS_BBR_ENTRIES_PER_SECT]; -}; - -/** - * struct evms_bbr_metadata - * @signature: 0 EVMS_BBR_SIGNATURE - * @crc: 4 - * @block_size: 8 Block size in bytes. - * @flags: 12 Global flags used by BBR. - * @sequence_number: 16 - * @start_sect_bbr_table: 24 LBA of start of BBR table. - * @nr_sects_bbr_table: 32 Number of sectors in the BBR table. - * @start_replacement_sect: 40 LBA of start of replacement sectors. - * @nr_replacement_blks: 48 Number of replacement sectors. - * @pads: 56 - * - * On-disk metadata identifying an object as a BBR object. - */ -struct evms_bbr_metadata { - u32 signature; - u32 crc; - u32 block_size; - u32 flags; - u64 sequence_number; - u64 start_sect_bbr_table; - u64 nr_sects_bbr_table; - u64 start_replacement_sect; - u64 nr_replacement_blks; - u8 pads[456]; -}; - -/** - * struct evms_notify_bbr - * @object_name: Input - Name of BBR object from feature header. - * @count: Output - Number of remapped sectors. - * @start_sect: Input - Start sector for sector_io. - * @nr_sect: Input - Number of sectors for sector_io. - * @buffer: Input/Output - Pointer to data buffer for sector_io. - * @rw: Input - READ or WRITE for sector_io. - */ -struct evms_notify_bbr { - u8 object_name[EVMS_VOLUME_NAME_SIZE+1]; - u64 count; - u64 start_sect; - u64 nr_sect; - u8 * buffer; - s32 rw; -}; - -/** - * struct bbr_runtime_remap - * - * Node in the binary tree used to keep track of remaps. - */ -struct bbr_runtime_remap { - struct evms_bbr_table_entry remap; - struct bbr_runtime_remap * left; - struct bbr_runtime_remap * right; -}; - -/** - * struct bbr_private - * @next: List of all bbr_private structures. - * @node: Output node. - * @source: Consumed node. - * @bbr_table: Copy of metadata table. - * @lba_table1: LBA of primary BBR table. - * @lba_table2: LBA of secondary BBR table. - * @nr_sects_bbr_table: Size of each BBR table. - * @nr_replacement_blks: Number of replacement sectors. - * @start_replacement_sect: LBA of start of replacement sectors. - * @blksize_in_sects: Size of each sector. - * @in_use_replacement_blks: Current number of remaps. - * @remap_root: Binary tree containing all remaps. - * @bbr_id_lock: Lock for the binary tree. - * @flag: BBR_STOP_REMAP - */ -struct bbr_private { - struct bbr_private * next; - struct evms_logical_node * node; - struct evms_logical_node * source; - struct evms_bbr_table * bbr_table; - u64 lba_table1; - u64 lba_table2; - u64 nr_sects_bbr_table; - u64 nr_replacement_blks; - u64 start_replacement_sect; - u32 blksize_in_sects; - atomic_t in_use_replacement_blks; - struct bbr_runtime_remap * remap_root; - spinlock_t bbr_id_lock; - u32 flag; -}; - -/** - * struct bbr_io_buffer - * @bbr_io_list: Thread's list of bbr_io_buf's. - * @bbr_id: Object for this request. - * @bh: Original buffer_head. - * @org_end_io: Saved callback address from original buffer_head. - * @org_private: Saved private data address from original buffer_head. - * @org_rsector: Saved sector value from original buffer_head. - * @org_dev: Saved b_rdev field from original buffer_head. - * @complete: Completion structure used by init_io. - * @rw: READ or WRITE. - * @rc: Return code from bbr_io_handler. - * - * Structure used to track each write request. - */ -struct bbr_io_buffer { - struct list_head bbr_io_list; - struct bbr_private * bbr_id; - struct buffer_head * org_bh; - struct completion * complete; - s32 rw; - s32 rc; -}; - -#ifdef EVMS_BBR_DEBUG -static void print_meta_data(struct evms_bbr_metadata * md); -static void print_bbr_table_sector(struct evms_bbr_table * bbr_table); -static void print_remap_list(struct bbr_private * bbr_id); -#define BBR_DEBUG_PRINT_META_DATA(md) print_meta_data(md) -#define BBR_DEBUG_PRINT_TABLE_SECTOR(table) print_bbr_table_sector(table) -#define BBR_DEBUG_PRINT_REMAP_LIST(bbr_id) print_remap_list(bbr_id) -#else -#define BBR_DEBUG_PRINT_META_DATA(md) -#define BBR_DEBUG_PRINT_TABLE_SECTOR(table) -#define BBR_DEBUG_PRINT_REMAP_LIST(bbr_id) -#endif - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_drivelink.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_drivelink.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_drivelink.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_drivelink.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,125 +0,0 @@ -/* -*- linux-c -*- */ -/* - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/include/linux/evms_drvlink.h - * - * EVMS DriveLink Feature kernel header file - * - */ - -#ifndef __EVMS_DRIVELINK_INCLUDED__ -#define __EVMS_DRIVELINK_INCLUDED__ - -#define EVMS_DRIVELINK_FEATURE_ID 1 -#define EVMS_DRIVELINK_SIGNATURE 0x4C767244 //DrvL -#define EVMS_DRIVELINK_MAX_ENTRIES 60 - -/* - * feature data version defines - */ -#define DRIVELINK_METADATA_MAJOR 2 -#define DRIVELINK_METADATA_MINOR 0 -#define DRIVELINK_METADATA_PATCHLEVEL 0 - -static struct evms_version metadata_ver = { - .major = DRIVELINK_METADATA_MAJOR, - .minor = DRIVELINK_METADATA_MINOR, - .patchlevel = DRIVELINK_METADATA_PATCHLEVEL -}; - -/** - * struct evms_dl_ordering_table_entry - ordering table entry structure definition - * @child_sn: child serial number - * @child_size: in sectors - * - * ordering table entry struction definition - **/ -struct evms_dl_ordering_table_entry { - u64 child_serial_number; - u64 child_vsize; -}; - -/** - * struct evms_drivelink_metadata - on-disk metadata definition - * @signature: drivelink metadata magic number - * @crc: crc of entire structure - * @version: drivelink metadata version - * @flags: - * @sequence_number: used to determine most recent redundant data - * @child_sn: child object serial number - * @parent_sn: parent object serial number - * @child_count: count of child objects of parent - * @pad: used for alignment of following table - * @ordering_table: table of child ordering entries - * - * drivelink on-disk metadata definition - **/ -struct evms_drivelink_metadata { - u32 signature; - u32 crc; - struct evms_version version; - u32 flags; - u64 sequence_number; - u64 child_serial_number; - u64 parent_serial_number; - u64 child_count; - u64 pad; - struct evms_dl_ordering_table_entry - ordering_table[EVMS_DRIVELINK_MAX_ENTRIES]; -}; - -#ifdef __KERNEL__ -/** - * struct runtime_entry - in-memory metadata entry description - * @block_size: largest block size of all children - * @voffset: relative offset of child object within parent object (in 512 byte units) - * @vsize: child object size (in 512 byte units) - * @child_node: child storage object - * @child_metadata: child's on-disk metadata - * - * drivelink's in-memory metadata entry description - **/ -struct runtime_entry { - u64 block_size; - u64 voffset; - u64 vsize; - struct evms_logical_node *child_node; - struct evms_drivelink_metadata *child_metadata; -}; - -/** - * struct runtime_data - in-memory metadata description - * @block_size: largest block size of all children - * @voffset: relative offset of child object within parent object (in 512 byte units) - * @vsize: child object size (in 512 byte units) - * @child_node: child storage object - * @child_metadata: child's on-disk metadata - * - * drivelink's in-memory metadata description - **/ -struct runtime_data { - u64 block_size; - u64 parent_sn; - u64 child_count; - struct runtime_entry *child_table; -}; -#endif - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_ioctl.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_ioctl.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_ioctl.h 2003-05-03 03:22:27.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_ioctl.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,478 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - 2002 - * - * 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 - */ -/* - * EVMS kernel ioctl header file - * - * This file contains all information about the ioctl interface. - */ - -#ifndef __EVMS_IOCTL_INCLUDED__ -#define __EVMS_IOCTL_INCLUDED__ - -#include - -/* IOCTL interface version definitions */ -#define EVMS_IOCTL_INTERFACE_MAJOR 12 -#define EVMS_IOCTL_INTERFACE_MINOR 0 -#define EVMS_IOCTL_INTERFACE_PATCHLEVEL 0 - -/* IOCTL definitions */ -enum evms_ioctl_cmds { - /* version commands */ - EVMS_GET_IOCTL_VERSION_NUMBER = 0, - EVMS_GET_VERSION_NUMBER, - - /* EVMS internal commands */ - EVMS_GET_DISK_LIST_NUMBER = 0x40, - EVMS_CHECK_MEDIA_CHANGE_NUMBER, - EVMS_REVALIDATE_DISK_NUMBER, - EVMS_OPEN_VOLUME_NUMBER, - EVMS_CLOSE_VOLUME_NUMBER, - EVMS_QUIESCE_VOLUME_NUMBER, - EVMS_CHECK_DEVICE_STATUS_NUMBER, - EVMS_UPDATE_DEVICE_INFO_NUMBER, - - /* configuration commands */ - EVMS_GET_INFO_LEVEL_NUMBER = 0x80, - EVMS_SET_INFO_LEVEL_NUMBER, - EVMS_REDISCOVER_VOLUMES_NUMBER, - EVMS_DELETE_VOLUME_NUMBER, - EVMS_PLUGIN_IOCTL_NUMBER, - EVMS_PROCESS_NOTIFY_EVENT_NUMBER, - - /* query info commands */ - EVMS_GET_LOGICAL_DISK_NUMBER = 0xC0, - EVMS_GET_LOGICAL_DISK_INFO_NUMBER, - EVMS_SECTOR_IO_NUMBER, - EVMS_GET_MINOR_NUMBER, - EVMS_GET_VOLUME_DATA_NUMBER, - EVMS_GET_PLUGIN_NUMBER, - EVMS_COMPUTE_CSUM_NUMBER, - EVMS_GET_BMAP_NUMBER, - EVMS_CHECK_MOUNT_STATUS_NUMBER, - EVMS_CHECK_OPEN_STATUS_NUMBER, - - /* commands for non-EVMS apps */ - EVMS_GET_VOL_STRIPE_INFO_NUMBER = 0xF0, -}; - -/* version commands */ -#define EVMS_GET_IOCTL_VERSION _IOR(EVMS_MAJOR, EVMS_GET_IOCTL_VERSION_NUMBER, struct evms_version) -#define EVMS_GET_VERSION _IOR(EVMS_MAJOR, EVMS_GET_VERSION_NUMBER, struct evms_version) - -/* EVMS internal commands */ -#define EVMS_GET_DISK_LIST _IOWR(EVMS_MAJOR, EVMS_GET_DISK_LIST_NUMBER, struct evms_list_node **) -#define EVMS_CHECK_MEDIA_CHANGE _IO(EVMS_MAJOR, EVMS_CHECK_MEDIA_CHANGE_NUMBER) -#define EVMS_REVALIDATE_DISK _IO(EVMS_MAJOR, EVMS_REVALIDATE_DISK_NUMBER) -#define EVMS_OPEN_VOLUME _IO(EVMS_MAJOR, EVMS_OPEN_VOLUME_NUMBER) -#define EVMS_CLOSE_VOLUME _IO(EVMS_MAJOR, EVMS_CLOSE_VOLUME_NUMBER) - -/** - * struct evms_quiesce_vol_pkt - ioctl packet definition - * @command: 0 = unquiesce, 1 = quiesce - * @minor: minor device number of target volume - * @do_vfs: 0 = do nothing, 1 = also perform equivalent VFS operation - * @status: returned operation status - * - * ioctl packet definition for EVMS_QUIESCE_VOLUME - **/ -struct evms_quiesce_vol_pkt { - s32 command; - s32 minor; - s32 do_vfs; - s32 status; -}; -/** - * defines for evms_quiesce_vol_pkt.command field - **/ -#define EVMS_UNQUIESCE 0 -#define EVMS_QUIESCE 1 -/** - * defines for evms_quiesce_vol_pkt.do_vfs field - * located below struct evms_delete_vol_pkt definition - **/ - -#define EVMS_QUIESCE_VOLUME _IOR(EVMS_MAJOR, EVMS_QUIESCE_VOLUME_NUMBER, struct evms_quiesce_vol_pkt) -#define EVMS_CHECK_DEVICE_STATUS _IOR(EVMS_MAJOR, EVMS_CHECK_DEVICE_STATUS_NUMBER, int) -#define EVMS_UPDATE_DEVICE_INFO _IO(EVMS_MAJOR, EVMS_UPDATE_DEVICE_INFO_NUMBER) - -/* configuration commands */ -#define EVMS_GET_INFO_LEVEL _IOR(EVMS_MAJOR, EVMS_GET_INFO_LEVEL_NUMBER, int) -#define EVMS_SET_INFO_LEVEL _IOW(EVMS_MAJOR, EVMS_SET_INFO_LEVEL_NUMBER, int) - -/** - * struct evms_rediscover_pkt - rediscover volume ioctl packet definition - * @status: return operation status - * @drive_count: count of drives being probed, 0xffffffff for all disks - * @drive_array: array of drive handles to be probed - * - * ioctl packet definition for EVMS_REDISCOVER_VOLUMES ioctl - **/ -struct evms_rediscover_pkt { - s32 status; - u32 drive_count; - u64 *drive_array; -}; -/** - * defines for evms_delete_vol_pkt.command field - **/ -#define EVMS_SOFT_DELETE 0 -#define EVMS_HARD_DELETE 1 -/** - * defines evms_rediscover_pkt.drive_count field - **/ -#define REDISCOVER_ALL_DEVICES 0xFFFFFFFF - -#define EVMS_REDISCOVER_VOLUMES _IOWR(EVMS_MAJOR, EVMS_REDISCOVER_VOLUMES_NUMBER, struct evms_rediscover_pkt) - -/** - * struct evms_delete_vol_pkt - delete volume ioctl packet definition - * @command: 0 = soft delete, 1 = hard delete - * @minor: minor device num of target volume - * @do_vfs: 0 = do nothing, 1 = perform VFS operation(s) - * @associative_minor: optional minor device num of associative volume, 0 when unused - * @author returned operation status - * - * ioctl packet definition for EVMS_DELETE_VOLUME ioctl - **/ -struct evms_delete_vol_pkt { - s32 command; - s32 minor; - s32 do_vfs; - s32 associative_minor; - s32 status; -}; -/** - * field evms_delete_vol_pkt defines - * @EVMS_VFS_DO_NOTHING: - * @EVMS_VFS_DO: - * - * NOTE: these defines are also used with evms_quiesce_vol_pkt. - **/ -#define EVMS_VFS_DO_NOTHING 0 -#define EVMS_VFS_DO 1 - -#define EVMS_DELETE_VOLUME _IOR(EVMS_MAJOR, EVMS_DELETE_VOLUME_NUMBER, struct evms_delete_vol_pkt) - -/** - * struct evms_plugin_ioctl_pkt - generic plugin ioctl packet definition - * @feature_id: plugin ID of feature to receive this ioctl - * @feature_command: feature specific ioctl command - * @status: 0 = completed, 0 != error - * @feature_ioctl_data: ptr to feature specific ioctl struct - * - * ioctl packet definition for EVMS_PLUGIN_IOCTL ioctl - **/ -struct evms_plugin_ioctl_pkt { - u32 feature_id; - s32 feature_command; - s32 status; - u32 data_size; - void *feature_ioctl_data; -}; - -#define EVMS_PLUGIN_IOCTL _IOR(EVMS_MAJOR, EVMS_PLUGIN_IOCTL_NUMBER, struct evms_plugin_ioctl_pkt) - -/** - * struct evms_event - evms event structure - * @pid: PID to act on - * @eventid: event id to respond to - * @signo: signal # to send when event occurs - * - * contains process event notification info - **/ -struct evms_event { - s32 pid; - s32 eventid; - s32 signo; -}; -/** - * field evms_event_pkt.eventid defines - **/ -#define EVMS_EVENT_END_OF_DISCOVERY 0 - -/** - * struct evms_notify_pkt - evms event notification ioctl packet definition - * @command: 0 = unregister, 1 = register - * @status: returned operation status - * @eventry: event structure - * - * ioctl packet definition for EVMS_PROCESS_NOTIFY_EVENT ioctl - **/ -struct evms_notify_pkt { - s32 command; - s32 status; - struct evms_event eventry; -}; -/** - * field evms_notify_pkt.command defines - **/ -#define EVMS_EVENT_UNREGISTER 0 -#define EVMS_EVENT_REGISTER 1 - -#define EVMS_PROCESS_NOTIFY_EVENT _IOWR(EVMS_MAJOR, EVMS_PROCESS_NOTIFY_EVENT_NUMBER, struct evms_notify_pkt) - -/* query info commands */ - -/** - * struct evms_user_disk_pkt - get disk handle ioctl packet definition - * @command: 0 = first disk, 1 = next disk - * @status: 0 = no more disks, 1 = valid disk info - * @disk_handle: only valid when status == 1 - * - * ioctl packet definition for EVMS_GET_LOGICAL_DISK ioctl - **/ -struct evms_user_disk_pkt { - s32 command; - s32 status; - u64 disk_handle; -}; -/** - * field evms_user_disk_pkt.command defines - **/ -#define EVMS_FIRST_DISK 0 -#define EVMS_NEXT_DISK 1 -/** - * field evms_user_disk_pkt.status defines - **/ -#define EVMS_DISK_INVALID 0 -#define EVMS_DISK_VALID 1 - -#define EVMS_GET_LOGICAL_DISK _IOWR(EVMS_MAJOR, EVMS_GET_LOGICAL_DISK_NUMBER, struct evms_user_disk_pkt) - -/** - * evms_user_disk_info_pkt - disk info packet definition - * @disk_handle: kernel handle to specified device - * @total_sectors: size of device in 512 byte units - * @geo_cylinders: device geometry: cylinders - * @geo_sectors: device geometry: sectors - * @geo_heads: device geometry: heads - * @disk_dev: kernel device info, used by MD plugin - * @block_size: reported block size - * @hardsect_size: reported physical sector size - * @status: return operation status - * @flags: device characteristics - * @disk_name: legacy name for the device - * - * ioctl packet definition for EVMS_GET_LOGICAL_DISK_INFO ioctl - **/ -struct evms_user_disk_info_pkt { - u64 disk_handle; - u64 total_sectors; - u64 geo_cylinders; - u32 geo_sectors; - u32 geo_heads; - u32 disk_dev; - u32 block_size; - u32 hardsect_size; - u32 status; - u32 flags; - u8 disk_name[EVMS_VOLUME_NAME_SIZE + 1]; -}; -/** - * field evms_user_disk_info_pkt.flags define in evms.h - **/ - -#define EVMS_GET_LOGICAL_DISK_INFO _IOWR(EVMS_MAJOR, EVMS_GET_LOGICAL_DISK_INFO_NUMBER, struct evms_user_disk_info_pkt) - -/** - * struct evms_sector_io_pkt - sector io ioctl packet definition - * @disk_handle: disk handle of target device - * @starting_sector: disk relative starting sector - * @sector_count: count of sectors - * @io_flag: 0 = read, 1 = write - * @status: return operation status - * @buffer_address: user buffer address - * - * ioctl packet definition for EVMS_SECTOR_IO ioctl - **/ -struct evms_sector_io_pkt { - u64 disk_handle; - u64 starting_sector; - u64 sector_count; - s32 io_flag; - s32 status; - u8 *buffer_address; -}; -/** - * field evms_sector_io_pkt.io_flag defines - **/ -#define EVMS_SECTOR_IO_READ 0 -#define EVMS_SECTOR_IO_WRITE 1 - -#define EVMS_SECTOR_IO _IOWR(EVMS_MAJOR, EVMS_SECTOR_IO_NUMBER, struct evms_sector_io_pkt) - -/** - * struct evms_user_minor_pkt - get a list of device minors, one at a time - * @command: 0 = first volume, 1 = next volume - * @status: returned operation status - * @minor: returned minor number, only valid when status == 1 - * - * ioctl packet definition for EVMS_GET_MINOR ioctl - **/ -struct evms_user_minor_pkt { - s32 command; - s32 status; - s32 minor; -}; -/** - * field evms_user_minor_pkt.command defines - **/ -#define EVMS_FIRST_VOLUME 0 -#define EVMS_NEXT_VOLUME 1 -/** - * field evms_user_minor_pkt.status defines - **/ -#define EVMS_VOLUME_INVALID 0 -#define EVMS_VOLUME_VALID 1 - -#define EVMS_GET_MINOR _IOWR(EVMS_MAJOR, EVMS_GET_MINOR_NUMBER, struct evms_user_minor_pkt) - -/** - * struct evms_volume_data_pkt - volume data packet definition - * @minor: minor device number of target volume - * @flags: returned volume characteristics - * @volume_name: returned volume name - * @status: returned operation status - * - * ioctl packet definition for EVMS_GET_VOLUME_DATA ioctl - **/ -struct evms_volume_data_pkt { - s32 minor; - s32 flags; - s32 status; - u8 volume_name[EVMS_VOLUME_NAME_SIZE + 1]; -}; -/** - * field evms_volume_data_pkt.flags defines found in evms_common.h - **/ - -#define EVMS_GET_VOLUME_DATA _IOWR(EVMS_MAJOR, EVMS_GET_VOLUME_DATA_NUMBER, struct evms_volume_data_pkt) - -/** - * struct evms_kernel_plugin_pkt - get kernel plugin ioctl packet definition - * @command: 0 = first plugin, 1 = next plugin - * @id: returned plugin id - * @version: returned plugin version info - * @status: returned operation status - * - * ioctl packet definition for EVMS_GET_PLUGIN ioctl - **/ -struct evms_kernel_plugin_pkt { - s32 command; - u32 id; - struct evms_version version; - s32 status; -}; -/** - * field evms_kernel_plugin_pkt.command defines - **/ -#define EVMS_FIRST_PLUGIN 0 -#define EVMS_NEXT_PLUGIN 1 -/** - * field evms_kernel_plugin_pkt.status defines - **/ -#define EVMS_PLUGIN_INVALID 0 -#define EVMS_PLUGIN_VALID 1 - -#define EVMS_GET_PLUGIN _IOWR(EVMS_MAJOR, EVMS_GET_PLUGIN_NUMBER, struct evms_kernel_plugin_pkt) - -/** - * struct evms_compute_csum_pkt - compute checksum ioctl packet definition - * @buffer_address: - * @buffer_size: - * @insum: - * @outsum: - * @status: - * - * ioctl packet definition for EVMS_COMPUTE_CSUM ioctl - **/ -struct evms_compute_csum_pkt { - u8 *buffer_address; - s32 buffer_size; - u32 insum; - u32 outsum; - s32 status; -}; - -#define EVMS_COMPUTE_CSUM _IOWR(EVMS_MAJOR, EVMS_COMPUTE_CSUM_NUMBER, struct evms_compute_csum_pkt) - -/** - * struct evms_get_bmap_pkt - get bmap data ioctl packet definition - * @rsector: input, volume relative rsector value - * output, disk relative rsector value - * @dev output, physical device - * @status: output, operation status - * - * ioctl packet definition for EVMS_GET_BMAP ioctl - **/ -struct evms_get_bmap_pkt { - u64 rsector; - u32 dev; - s32 status; -}; - -#define EVMS_GET_BMAP _IOWR(EVMS_MAJOR, EVMS_GET_BMAP_NUMBER, struct evms_get_bmap_pkt) - -/** - * struct evms_mount_status_pkt - ioctl packet definition - * @minor: input, minor of volume to check - * @mounted: output, TRUE (1) if mounted, FALSE (0) if not - * @status: output, operation completion status - * - * ioctl packet definition for EVMS_CHECK_MOUNT_STATUS ioctl. - **/ -struct evms_mount_status_pkt { - u32 minor; - u32 mounted; - s32 status; -}; - -#define EVMS_CHECK_MOUNT_STATUS _IOWR(EVMS_MAJOR, EVMS_CHECK_MOUNT_STATUS_NUMBER, struct evms_mount_status_pkt) - -/** - * struct evms_open_status_pkt - ioctl packet definition - * @minor: input, minor of volume to check - * @opens: output, 0 (FALSE) if not, count (TRUE) of opens - * @status: output, operation completion status - * - * ioctl packet definition for EVMS_CHECK_OPEN_STATUS ioctl. - **/ -struct evms_open_status_pkt { - u32 minor; - u32 opens; - s32 status; -}; - -#define EVMS_CHECK_OPEN_STATUS _IOWR(EVMS_MAJOR, EVMS_CHECK_OPEN_STATUS_NUMBER, struct evms_open_status_pkt) - -/** - * struct evms_vol_stripe_info_pkt - ioctl packet definition - * @size: the stripe unit specified in 512 byte block units - * @width: the number of stripe members or RAID data disks - * - * ioctl packet definition for EVMS_GET_VOL_STRIPE_INFO ioctl. - **/ -struct evms_vol_stripe_info_pkt { - u32 size; - u32 width; -}; - -#define EVMS_GET_VOL_STRIPE_INFO _IOR(EVMS_MAJOR, EVMS_GET_VOL_STRIPE_INFO_NUMBER, struct evms_vol_stripe_info_pkt) -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_linear.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_linear.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_linear.h 2003-05-03 03:22:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_linear.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,33 +0,0 @@ -#ifndef __EVMS_LINEAR_H -#define __EVMS_LINEAR_H - -#include - -struct dev_info { - struct evms_logical_node *node; - kdev_t dev; - unsigned long size; - unsigned long offset; -}; - -typedef struct dev_info dev_info_t; - -struct linear_hash -{ - dev_info_t *dev0, *dev1; -}; - -struct linear_private_data -{ - struct linear_hash *hash_table; - dev_info_t disks[MD_SB_DISKS]; - dev_info_t *smallest; - int nr_zones; -}; - - -typedef struct linear_private_data linear_conf_t; - -#define mddev_to_conf(mddev) ((linear_conf_t *) mddev->private) - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_lvm.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_lvm.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_lvm.h 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_lvm.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,481 +0,0 @@ -/* -*- linux-c -*- */ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/include/linux/evms_lvm.h - * - * EVMS LVM VGE kernel header file - */ - -#ifndef __EVMS_LVM_H__ -#define __EVMS_LVM_H__ - -#define EVMS_LVM_VERSION_MAJOR 1 -#define EVMS_LVM_VERSION_MINOR 1 -#define EVMS_LVM_VERSION_PATCH 2 - -/* The following definitions and data structures are copied from lvm.h and - * liblvm.h from the LVM 0.9.1beta8 distribution. Since the metadata format - * changed in beta8, lvm.h changed significantly enough that this module would - * no longer compile. Instead of requiring evms users to install the latest lvm - * release, the required definitions and data structures will now be included - * in this header file. - */ - -#define MAX_VG 99 -#define MAX_LV 256 -#define MAX_PV 256 -#define NAME_LEN 128 -#define UUID_LEN 32 -#define LVM_VGDA_ALIGN 4096UL -#define LVM_PV_DISK_BASE 0L -#define LVM_PV_DISK_SIZE 1024L -#define LVM_VG_DISK_BASE round_up(LVM_PV_DISK_BASE + LVM_PV_DISK_SIZE, \ - LVM_VGDA_ALIGN) -#define LVM_VG_DISK_SIZE (8*512L) - -/* - * Status flags - */ -/* lv->lv_status */ -#define LV_ACTIVE 0x01 -/* lv->lv_access */ -#define LV_READ 0x01 -#define LV_WRITE 0x02 -#define LV_SNAPSHOT 0x04 -#define LV_SNAPSHOT_ORG 0x08 - -/** - * struct lv_COW_table_disk_v1 - * @pv_org_number: - * @pv_org_rsector: - * @pv_snap_number: - * @pv_snap_rsector: - * - * Copy-On-Write tables in disk format (version 1). - **/ -struct lv_COW_table_disk { - u64 pv_org_number; - u64 pv_org_rsector; - u64 pv_snap_number; - u64 pv_snap_rsector; -}; - -/** - * struct pe_disk - * @lv_num: - * @le_num: - * - * Disk stored PE map entry definition. - **/ -struct pe_disk { - u16 lv_num; - u16 le_num; -}; - -/** - * struct lvm_disk_data - * @base: - * @size: - * - * Disk stored PV, VG, LV and PE size and offset information. - */ -struct lvm_disk_data { - u32 base; - u32 size; -}; - -/** - * struct pv_disk - * @id: - * @version: - * @pv_on_disk: - * @vg_on_disk: - * @pv_uuidlist_on_disk: - * @lv_on_disk: - * @pe_on_disk: - * @pv_uuid: - * @vg_name: - * @system_id: used by vgexport/vgimport - * @pv_major: - * @pv_number: - * @pv_status: - * @pv_allocatable: - * @pv_size: - * @lv_cur - * @pe_size: - * @pe_total: - * @pe_allocated: - * @pe_start: in sectors (new in version 2) - * - * Physical volume on disk metadata definition (version 2). - */ -struct pv_disk { - u8 id[2]; - u16 version; - struct lvm_disk_data pv_on_disk; - struct lvm_disk_data vg_on_disk; - struct lvm_disk_data pv_uuidlist_on_disk; - struct lvm_disk_data lv_on_disk; - struct lvm_disk_data pe_on_disk; - u8 pv_uuid[NAME_LEN]; - u8 vg_name[NAME_LEN]; - u8 system_id[NAME_LEN]; - u32 pv_major; - u32 pv_number; - u32 pv_status; - u32 pv_allocatable; - u32 pv_size; - u32 lv_cur; - u32 pe_size; - u32 pe_total; - u32 pe_allocated; - u32 pe_start; -}; - -/** - * struct lv_disk - * @lv_name: - * @vg_name: - * @lv_access: - * @lv_status: - * @lv_open: - * @lv_dev: - * @lv_number: - * @lv_mirror_copies: - * @lv_recovery: - * @lv_schedule: - * @lv_size: - * @lv_snapshot_minor: minor number of original - * @lv_chunk_size: chuck size for snapshots - * @lv_dummy: - * @lv_allocated_le: - * @lv_stripes: - * @lv_stripesize: - * @lv_badblock: - * @lv_allocated: - * @lv_io_timeout: - * @lv_read_ahead: - * - * Logical volume metadata definition (version 3). - */ -struct lv_disk { - u8 lv_name[NAME_LEN]; - u8 vg_name[NAME_LEN]; - u32 lv_access; - u32 lv_status; - u32 lv_open; - u32 lv_dev; - u32 lv_number; - u32 lv_mirror_copies; - u32 lv_recovery; - u32 lv_schedule; - u32 lv_size; - u32 lv_snapshot_minor; - u16 lv_chunk_size; - u16 dummy; - u32 lv_allocated_le; - u32 lv_stripes; - u32 lv_stripesize; - u32 lv_badblock; - u32 lv_allocation; - u32 lv_io_timeout; - u32 lv_read_ahead; -}; - -/** - * struct vg_disk - * @vg_uuid: Volume group UUID - * @vg_name_dummy: Remainder of version 1 VG name - * @vg_number: Volume group number - * @vg_access: Read/Write - * @vg_status: Active or not - * @lv_max: Maximum logical volumes - * @lv_cur: Current logical volumes - * @lv_open: Open logical volumes - * @pv_max: Maximum physical volumes - * @pv_cur: Current physical volumes - * @pv_act: Active physical volumes - * @dummy: - * @vgda: Volume group descriptor arrays - * @pe_size: Physical extent size in sectors - * @pe_total: Total of physical extents - * @pe_allocated: Allocated physical extents - * @pvg_total: Physical volume groups - * - * Volume group metadata definition (version 2). - */ -struct vg_disk { - u8 vg_uuid[UUID_LEN]; - u8 vg_name_dummy[NAME_LEN - UUID_LEN]; - u32 vg_number; - u32 vg_access; - u32 vg_status; - u32 lv_max; - u32 lv_cur; - u32 lv_open; - u32 pv_max; - u32 pv_cur; - u32 pv_act; - u32 dummy; - u32 vgda; - u32 pe_size; - u32 pe_total; - u32 pe_allocated; - u32 pvg_total; -}; - -/* Useful inlines */ -static inline ulong round_up(ulong n, ulong size) -{ - size--; - return (n + size) & ~size; -} - -static inline ulong div_up(ulong n, ulong size) -{ - return round_up(n, size) / size; -} - -/* End of lvm.h imported data structures. */ - -#define DEV_DIRECTORY "/dev/" -#define LVM_DEV_DIRECTORY "lvm/" -#define LVM_PROC_NAME "lvm" -#define LVM_PROC_VG_NAME "VGs" -#define LVM_PROC_LV_NAME "LVs" -#define LVM_PROC_PV_NAME "PVs" -#define LVM_PROC_GLOBAL_NAME "global" -#define IO_BUFFER_SECTORS 8 - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,9) -#define max(a,b) (((a)>(b))?(a):(b)) -#endif - -/* Structure for doing PV remove ioctls. */ - -#define EVMS_LVM_PV_REMOVE_IOCTL 0x01 -#define EVMS_LVM_SNAPSHOT_STAT_IOCTL 0x02 - -/** - * struct lvm_pv_remove_ioctl - * @vg_uuid: Volume group UUID - * @pv_number: Physical volume number - * @next: Link to next packet (engine-use only) - * - * PV remove ioctl packet definition. - */ -struct lvm_pv_remove_ioctl { - u8 vg_uuid[UUID_LEN]; - u32 pv_number; - struct lvm_pv_remove_ioctl * next; -}; - -/** - * struct lvm_snapshot_stat_ioctl - * @vg_uuid: Volume group UUID - * @lv_number: Logical volume number - * @next_free_chuck: - * @lv_status: - * - * Snapshot statistics ioctl packet definition. - **/ -struct lvm_snapshot_stat_ioctl { - u8 vg_uuid[UUID_LEN]; - u32 lv_number; - u64 next_free_chunk; - u32 lv_status; -}; - -/** - * struct lvm_physical_volume - * @logical_node: Storage object - * @pv: Copy of on-disk PV struct - * @pe_map: - * @pv_number: - * @next: Pointer to next entry - * - * Entries in the list of physical volumes (PV) in a volume group (VG). - */ -struct lvm_physical_volume { - struct evms_logical_node * logical_node; - struct pv_disk * pv; - struct pe_disk * pe_map; - u32 pv_number; - struct lvm_physical_volume * next; -}; - -/** - * struct le_table_entry - * @owning_pv: - * @pe_sector_offset: - * - * Table entry definition for mapping logical - * extents (LE) to physical extents (PE). - */ -struct le_table_entry { - struct lvm_physical_volume * owning_pv; - u64 pe_sector_offset; -}; - -/** - * struct snapshot_map_entry - * @org_sector: - * @snap_sector: - * @snap_pv: - * @next: - * @prev: - * - * Snapshot remapping entry structure definition. - */ -struct snapshot_map_entry { - u64 org_sector; - u64 snap_sector; - struct lvm_physical_volume * snap_pv; - struct snapshot_map_entry * next; - struct snapshot_map_entry * prev; -}; - -#define MAX_HASH_CHAIN_ENTRIES 10 -#define CHUNK_DATA_BUFFER_SIZE 128 - -/** - * struct lvm_logical_volume - * @lv_number: - * @lv_size: In sectors - * @lv_access: Flags: LV_READ, LV_WRITE, LV_SNAPSHOT, - * LV_SNAPSHOT_ROG, EVMS_LV* - * @lv_status: Flags: LV_ACTIVE, LV_SPINDOWN - * @lv_minor: Device minor number - * @stripes: - * @stripe_size: In sectors - * @stripe_size_shift: # of bits to shift right instead of dividing by stripe_size - * @pe_size: In sectors - * @pe_size_shift: Number of bits to shift right instead of dividing by pe_size - * @num_le: Number of entries in the le-to-pe map - * @group: Pointer back to parent volume group - * @name: Dev-tree volume name (eg. /dev/group0/vol0) - * @le_map: Mapping of logical to physical extents - * @volume_node: Pointer to parent EVMS object representing this volume - * @chunk_size: In sectors - * @num_chunks: lv_size / chunk_size - * @snap_org_minor: Minor number of snapshot original - * @next_cow_entry: Index into current COW table - * @current_cow_sector: Logical sector of current COW table - * @next_free_chunk: Starting logical sector of next free chunk - * @hash_table_size: Number of pointers in each hash table - * @cow_table: Pointer to one sector's worth of COW tables. - * @chunk_data_buffer: Buffer reading data when doing copy-on-write - * @snap_semaphore: For locking during snapshot IO operations - * @snapshot_map: Pointer to remapping hash tables - * @snapshot_next: Linked list of volumes being snapshotted - * @snapshot_org: Pointer to volume being snapshotted - * - * In-memory representation of an LVM LV. - */ -struct lvm_logical_volume { - u32 lv_number; - u64 lv_size; - u32 lv_access; - u32 lv_status; - u32 lv_minor; - u32 stripes; - u32 stripe_size; - u32 stripe_size_shift; - u32 pe_size; - u32 pe_size_shift; - u32 num_le; - struct lvm_volume_group * group; - u8 name[NAME_LEN]; - struct le_table_entry * le_map; - struct evms_logical_node * volume_node; - u32 chunk_size; - u32 num_chunks; - u32 snap_org_minor; - u32 next_cow_entry; - u64 current_cow_sector; - u64 next_free_chunk; - u32 hash_table_size; - struct lv_COW_table_disk * cow_table; - u8 * chunk_data_buffer; - struct semaphore snap_semaphore; - struct snapshot_map_entry *** snapshot_map; - struct lvm_logical_volume * snapshot_next; - struct lvm_logical_volume * snapshot_org; -}; - -/* lv_access: - * EVMS_LV_NEW: Volume was created during the current discovery pass. - * EVMS_LV_INCOMPLETE: Volume has an incomplete LE map. - * EVMS_LV_INVALID: Volume has a memory-corruption problem. - * EVMS_LV_QUIESCED: Volume is in quiesced state. - * EVMS_LV_EXPORTED: Volume has been exported during this EVMS discovery pass. - */ -#define EVMS_LV_NEW 0x10 -#define EVMS_LV_INCOMPLETE 0x20 -#define EVMS_LV_INVALID 0x40 -#define EVMS_LV_QUIESCED 0x80 -#define EVMS_LV_EXPORTED 0x100 - -/** - * struct lvm_volume_group - * @vg: Copy of on-disk VG metadata - * @pv_list: List of PVs that make up this group - * @volume_list: Array of volumes - * @lv_array: Array of LV metadata - * @lv_array_disk: - * @uuid_list: List of PV UUIDs - * @vg_uuid: UUID from the VG metadata - * @vg_name: Name from the PV metadata - * @pv_count: # of PVs found in this group - * @volume_count: # of LVs found in this group - * @hard_sect_size: Largest hardsector size of all PVs in this group - * @block_size: Largest block size of all PVs in this group - * @flags: EVMS_VG* - * @next_group: Linked list - * - * In-memory representation of an LVM VG. - */ -struct lvm_volume_group { - struct vg_disk * vg; - struct lvm_physical_volume * pv_list; - struct lvm_logical_volume * volume_list[MAX_LV + 1]; - struct lv_disk * lv_array; - struct lv_disk * lv_array_disk; - u8 * uuid_list; - u8 vg_uuid[UUID_LEN]; - u8 vg_name[NAME_LEN]; - u32 pv_count; - u32 volume_count; - s32 hard_sect_size; - s32 block_size; - u32 flags; - struct lvm_volume_group * next_group; -}; - -/* flags - * EVMS_VG_DIRTY: Group is new or has had a PV added - * during this discovery. - * EVMS_VG_PARTIAL_PVS: Group contains at least one partial PV. - * EVMS_VG_REMOVABLE_PVS: Group contains at least one removable PV. - */ -#define EVMS_VG_DIRTY (1 << 0) -#define EVMS_VG_PARTIAL_PVS (1 << 1) -#define EVMS_VG_REMOVABLE_PVS (1 << 2) - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md.h 2003-05-03 03:22:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,120 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * linux/include/linux/evms/evms_md.h - * - * EVMS Linux MD Region Manager Public Header File - * - * 'evms_md.h' is an EVMS version of linux/include/linux/raid/md.h modified - * by Cuong (Mike) Tran , January 2002. - * - */ - -#ifndef __EVMS_MD_INCLUDED -#define __EVMS_MD_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -/* - * 'md_p.h' holds the 'physical' layout of RAID devices - * 'md_u.h' holds the user <=> kernel API - * - * 'md_k.h' holds kernel internal definitions - */ - -#include -#include -#include - -/* - * Different major versions are not compatible. - * Different minor versions are only downward compatible. - * Different patchlevel versions are downward and upward compatible. - */ -#define EVMS_MD_MAJOR_VERSION 1 -#define EVMS_MD_MINOR_VERSION 1 -#define EVMS_MD_PATCHLEVEL_VERSION 2 - -#define MD_MAJOR_VERSION 0 -#define MD_MINOR_VERSION 90 -#define MD_PATCHLEVEL_VERSION 0 - -#define EVMS_MD_COMMON_SERVICES_MAJOR 0 -#define EVMS_MD_COMMON_SERVICES_MINOR 5 -#define EVMS_MD_COMMON_SERVICES_PATCHLEVEL 0 - - -extern int evms_md_size[MAX_MD_DEVS]; - -extern void evms_md_add_mddev_mapping (mddev_t *mddev, kdev_t dev, void *data); -extern void evms_md_del_mddev_mapping (mddev_t *mddev, kdev_t dev); -extern char * evms_md_partition_name (struct evms_logical_node *node); -extern int evms_register_md_personality (int p_num, mdk_personality_t *p); -extern int evms_unregister_md_personality (int p_num); - -extern int evms_md_update_sb (mddev_t *mddev); -extern int evms_md_check_ordering (mddev_t *mddev); -extern void evms_md_print_devices (void); - -extern int evms_md_sync_io( - struct evms_logical_node *node, /* evms node for the MD array */ - int rw, /* READ / WRITE */ - u64 sector, /* starting sector */ - u64 total_nr_sects, /* total number of sectors */ - void *data ); /* pointer to buffer */ - -extern int evms_md_partial_sync_io( - struct evms_logical_node *node, /* evms node for the MD array */ - int rw, /* READ / WRITE */ - u64 sector, /* starting sector */ - u32 *nsects, /* on input: the total number of sectors for the request */ - /* on output, number of sectors completed */ - void *data); /* pointer to buffer */ - - -extern int evms_md_do_sync(mddev_t *mddev, mdp_disk_t *spare); -extern void evms_md_done_sync(mddev_t *mddev, int blocks, int ok); -extern void evms_md_sync_acct(kdev_t dev, unsigned long nr_sectors); -extern void evms_md_recover_arrays (void); -extern int evms_md_error (mddev_t *mddev, struct evms_logical_node *node); -extern int evms_md_error_dev(mddev_t *mddev, kdev_t dev); - -#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); evms_md_print_devices(); } - - -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md_k.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md_k.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md_k.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md_k.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,483 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/include/linux/evms/evms_md_k.h - * - * EVMS Linux MD Region Manager Public Header File - * - * 'evms_md_k.h' is an EVMS version of linux/include/linux/raid/md_k.h modified - * by Cuong (Mike) Tran , January 2002. - * - */ - -#ifndef __EVMS_MD_K_INC__ -#define __EVMS_MD_K_INC__ - -#define EVMS_MD_SECTS_PER_PAGE (PAGE_SIZE >> EVMS_VSECTOR_SIZE_SHIFT) -#define EVMS_MD_SECTS_PER_PAGE_MASK (~(EVMS_MD_SECTS_PER_PAGE-1)) - -#define MD_RESERVED 0UL -#define LINEAR 1UL -#define RAID0 2UL -#define RAID1 3UL -#define RAID5 4UL -#define TRANSLUCENT 5UL -#define HSM 6UL -#define MULTIPATH 7UL -#define MAX_PERSONALITY 8UL - -static inline int pers_to_level (int pers) -{ - switch (pers) { - case MULTIPATH: return -4; - case HSM: return -3; - case TRANSLUCENT: return -2; - case LINEAR: return -1; - case RAID0: return 0; - case RAID1: return 1; - case RAID5: return 5; - } - BUG(); - return MD_RESERVED; -} - -static inline int level_to_pers (int level) -{ - switch (level) { - case -3: return HSM; - case -2: return TRANSLUCENT; - case -1: return LINEAR; - case 0: return RAID0; - case 1: return RAID1; - case 4: - case 5: return RAID5; - } - return MD_RESERVED; -} - -typedef struct mddev_s mddev_t; -typedef struct mdk_rdev_s mdk_rdev_t; - -#if (MINORBITS != 8) -#error MD doesnt handle bigger kdev yet -#endif - -#define MAX_MD_DEVS (1<state & (1 << MD_DISK_FAULTY); -} - -static inline int disk_active(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_ACTIVE); -} - -static inline int disk_sync(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_SYNC); -} - -static inline int disk_spare(mdp_disk_t * d) -{ - return !disk_sync(d) && !disk_active(d) && !disk_faulty(d); -} - -static inline int disk_removed(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_REMOVED); -} - -static inline void mark_disk_faulty(mdp_disk_t * d) -{ - d->state |= (1 << MD_DISK_FAULTY); -} - -static inline void mark_disk_active(mdp_disk_t * d) -{ - d->state |= (1 << MD_DISK_ACTIVE); - d->state &= ~(1 << MD_DISK_PENDING_ACTIVE); -} - -static inline void mark_disk_sync(mdp_disk_t * d) -{ - d->state |= (1 << MD_DISK_SYNC); -} - -static inline void mark_disk_spare(mdp_disk_t * d) -{ - d->state = 0; -} - -static inline void mark_disk_removed(mdp_disk_t * d) -{ - d->state = (1 << MD_DISK_FAULTY) | (1 << MD_DISK_REMOVED); -} - -static inline void mark_disk_inactive(mdp_disk_t * d) -{ - d->state &= ~(1 << MD_DISK_ACTIVE); -} - -static inline void mark_disk_nonsync(mdp_disk_t * d) -{ - d->state &= ~(1 << MD_DISK_SYNC); -} - -/* - * MD's 'extended' device - */ -struct mdk_rdev_s -{ - struct md_list_head same_set; /* RAID devices within the same set */ - struct md_list_head all; /* all RAID devices */ - struct md_list_head pending; /* undetected RAID devices */ - struct evms_logical_node *node; /* EVMS device node */ - kdev_t dev; /* Device number */ - kdev_t old_dev; /* "" when it was last imported */ - unsigned long size; /* Device size (in blocks) */ - mddev_t *mddev; /* RAID array if running */ - unsigned long last_events; /* IO event timestamp */ - - struct block_device *bdev; /* block device handle */ - - mdp_super_t *sb; - unsigned long sb_offset; /* in blocks */ - - int virtual_spare; /* "virtual" spare added via IOCTL */ - int alias_device; /* device alias to the same disk */ - int faulty; /* if faulty do not issue IO requests */ - int desc_nr; /* descriptor index in the superblock */ -}; - - -/* - * disk operations in a working array: - */ -#define DISKOP_SPARE_INACTIVE 0 -#define DISKOP_SPARE_WRITE 1 -#define DISKOP_SPARE_ACTIVE 2 -#define DISKOP_HOT_SPARE_ACTIVE 3 -#define DISKOP_HOT_REMOVE_SPARE 4 -#define DISKOP_HOT_REMOVE_DISK 5 -#define DISKOP_HOT_ADD_DISK 6 -#define DISKOP_HOT_DEACTIVATE_DISK 7 - -typedef struct mdk_personality_s mdk_personality_t; - -struct mddev_s -{ - void *private; - mdk_personality_t *pers; - struct evms_logical_node *node; - unsigned long flag; - int nr_raid_disks; - int __minor; - int chunk_size; - mdp_super_t *sb; - int nb_dev; - struct md_list_head disks; - int sb_dirty; - int ro; - unsigned long curr_resync; /* blocks scheduled */ - unsigned long resync_mark; /* a recent timestamp */ - unsigned long resync_mark_cnt;/* blocks written at resync_mark */ - char *name; - int recovery_running; - struct semaphore reconfig_sem; - struct semaphore recovery_sem; - struct semaphore resync_sem; - atomic_t active; - - atomic_t recovery_active; /* blocks scheduled, but not written */ - md_wait_queue_head_t recovery_wait; - - struct md_list_head all_mddevs; - struct md_list_head incomplete_mddevs; - struct md_list_head running_mddevs; -}; - -struct mdk_personality_s -{ - char *name; - int (*sync_io) (mddev_t *mddev, int rw, u64 LSN, u64 nr_sects, void *data); - void (*read)(struct evms_logical_node *node, struct buffer_head *bh); - void (*write)(struct evms_logical_node *node, struct buffer_head *bh); - int (*run)(mddev_t *mddev); - int (*stop)(mddev_t *mddev); - int (*status)(char *page, mddev_t *mddev); - int (*error_handler)(mddev_t *mddev, struct evms_logical_node *node); - -/* - * Some personalities (RAID-1, RAID-5) can have disks hot-added and - * hot-removed. Hot removal is different from failure. (failure marks - * a disk inactive, but the disk is still part of the array) The interface - * to such operations is the 'pers->diskop()' function, can be NULL. - * - * the diskop function can change the pointer pointing to the incoming - * descriptor, but must do so very carefully. (currently only - * SPARE_ACTIVE expects such a change) - */ - int (*diskop) (mddev_t *mddev, mdp_disk_t **descriptor, int state); - - int (*stop_resync)(mddev_t *mddev); - int (*restart_resync)(mddev_t *mddev); - int (*sync_request)(mddev_t *mddev, unsigned long block_nr); - int (*evms_ioctl)(mddev_t *mddev, struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - int (*md_pers_ioctl)(mddev_t *mddev, int cmd, void* pers_arg); -}; - -/** - * EVMS MD instance data structure definition - **/ -struct evms_md { - mddev_t *mddev; - struct evms_plugin_header instance_plugin_hdr; -}; - -#define EVMS_MD_NODE_TO_MDDEV(node) ((struct evms_md *)(node->private))->mddev - -static inline int evms_md_check_boundary(struct evms_logical_node *node, struct buffer_head *bh) -{ - if ((bh->b_rsector + (bh->b_size >> EVMS_VSECTOR_SIZE_SHIFT)) > node->total_vsectors) { - bh->b_end_io(bh, 0); - return -EIO; - } - return 0; -} - -/** - * This structure is used for synchronous I/O - * @rc : error code - * @io_count: number of I/Os - + @wait: wait queue - **/ -struct evms_md_sync_cb { - int rc; - atomic_t io_count; - wait_queue_head_t wait; -}; - - -/** - * This structure is required for activating a spare device - * @next: next spare - * @mddev: target md device - * @spare: spare to activate - **/ -struct evms_md_activate_spare { - struct evms_md_activate_spare *next; - mddev_t *mddev; - mdp_disk_t *spare; -}; - -static inline int incomplete_mddev(mddev_t * mddev) -{ - return (mddev->incomplete_mddevs.next != &mddev->incomplete_mddevs); -} - -/* - * Currently we index md_array directly, based on the minor - * number. This will have to change to dynamic allocation - * once we start supporting partitioning of md devices. - */ -static inline int mdidx (mddev_t * mddev) -{ - return mddev->__minor; -} - -static inline kdev_t mddev_to_kdev(mddev_t * mddev) -{ - return MKDEV(MD_MAJOR, mdidx(mddev)); -} - -extern mdk_rdev_t * evms_md_find_rdev(mddev_t * mddev, kdev_t dev); -extern mdk_rdev_t * evms_md_find_rdev_nr(mddev_t *mddev, int nr); -extern mdp_disk_t *get_spare(mddev_t *mddev); - -/* - * iterates through some rdev ringlist. It's safe to remove the - * current 'rdev'. Dont touch 'tmp' though. - */ -#define ITERATE_RDEV_GENERIC(head,field,rdev,tmp) \ - \ - for (tmp = head.next; \ - rdev = md_list_entry(tmp, mdk_rdev_t, field), \ - tmp = tmp->next, tmp->prev != &head \ - ; ) -/* - * iterates through the 'same array disks' ringlist - */ -#define ITERATE_RDEV(mddev,rdev,tmp) \ - ITERATE_RDEV_GENERIC((mddev)->disks,same_set,rdev,tmp) - -/* - * Same as above, but assumes that the device has rdev->desc_nr numbered - * from 0 to mddev->nb_dev, and iterates through rdevs in ascending order. - */ -#define ITERATE_RDEV_ORDERED(mddev,rdev,i) \ - for (i = 0; rdev = evms_md_find_rdev_nr(mddev, i), i < mddev->nb_dev; i++) - - -/* - * Iterates through all 'RAID managed disks' - */ -#define ITERATE_RDEV_ALL(rdev,tmp) \ - ITERATE_RDEV_GENERIC(all_raid_disks,all,rdev,tmp) - -/* - * Iterates through 'pending RAID disks' - */ -#define ITERATE_RDEV_PENDING(rdev,tmp) \ - ITERATE_RDEV_GENERIC(pending_raid_disks,pending,rdev,tmp) - -/* - * iterates through all used mddevs in the system. - */ -#define ITERATE_MDDEV(mddev,tmp) \ - \ - for (tmp = all_mddevs.next; \ - mddev = md_list_entry(tmp, mddev_t, all_mddevs), \ - tmp = tmp->next, tmp->prev != &all_mddevs \ - ; ) - -/* - * iterates through all incomplete mddevs in the system. - */ -#define ITERATE_INCOMPLETE_MDDEV(mddev,tmp) \ - \ - for (tmp = incomplete_mddevs.next; \ - mddev = list_entry(tmp, mddev_t, incomplete_mddevs), \ - tmp = tmp->next, tmp->prev != &incomplete_mddevs\ - ; ) -/* - * iterates through all running mddevs in the system. - */ -#define ITERATE_RUNNING_MDDEV(mddev,tmp) \ - \ - for (tmp = running_mddevs.next; \ - mddev = list_entry(tmp, mddev_t, running_mddevs), \ - tmp = tmp->next, tmp->prev != &running_mddevs \ - ; ) - -static inline int lock_mddev (mddev_t * mddev) -{ - return down_interruptible(&mddev->reconfig_sem); -} - -static inline void unlock_mddev (mddev_t * mddev) -{ - up(&mddev->reconfig_sem); -} - -#define xchg_values(x,y) do { __typeof__(x) __tmp = x; \ - x = y; y = __tmp; } while (0) - -#define MAX_DISKNAME_LEN 64 - -typedef struct dev_name_s { - struct md_list_head list; - kdev_t dev; - char namebuf [MAX_DISKNAME_LEN]; - char *name; -} dev_name_t; - - -#define __wait_event_lock_irq(wq, condition, lock) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - if (condition) \ - break; \ - spin_unlock_irq(&lock); \ - run_task_queue(&tq_disk); \ - schedule(); \ - spin_lock_irq(&lock); \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_lock_irq(wq, condition, lock) \ -do { \ - if (condition) \ - break; \ - __wait_event_lock_irq(wq, condition, lock); \ -} while (0) - - -#define __wait_disk_event(wq, condition) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - if (condition) \ - break; \ - run_task_queue(&tq_disk); \ - schedule(); \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_disk_event(wq, condition) \ -do { \ - if (condition) \ - break; \ - __wait_disk_event(wq, condition); \ -} while (0) - -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md_p.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md_p.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md_p.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md_p.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,197 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/include/linux/evms/evms_md_p.h - * - * EVMS Linux MD Region Manager Public Header File - * - * 'evms_md_p.h' is an EVMS version of linux/include/linux/raid/md_p.h modified - * by Cuong (Mike) Tran , March 2002. - * - */ - -#ifndef __EVMS_MD_P_INC__ -#define __EVMS_MD_P_INC__ - -/* - * RAID superblock. - * - * The RAID superblock maintains some statistics on each RAID configuration. - * Each real device in the RAID 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 RAID 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 */ -#define MD_DISK_REMOVED 3 /* disk has kind of been removed, but not really or it would not be here */ -#define MD_DISK_NEW 4 /* disk has just been added to the raid set */ -#define MD_DISK_PENDING_ACTIVE 5 /* disk was spare, but should be activated */ - -typedef struct mdp_device_descriptor_s { - __u32 number; /* 0 Device number in the entire set */ - __u32 major; /* 1 Device major number */ - __u32 minor; /* 2 Device minor number */ - __u32 raid_disk; /* 3 The role of the device in the raid set */ - __u32 state; /* 4 Operational state */ - __u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5]; -} mdp_disk_t; - -#define MD_SB_MAGIC 0xa92b4efc - -/* - * Superblock state bits - */ -#define MD_SB_CLEAN 0 -#define MD_SB_ERRORS 1 - -typedef struct mdp_superblock_s { - /* - * Constant generic information - */ - __u32 md_magic; /* 0 MD identifier */ - __u32 major_version; /* 1 major version to which the set conforms */ - __u32 minor_version; /* 2 minor version ... */ - __u32 patch_version; /* 3 patchlevel version ... */ - __u32 gvalid_words; /* 4 Number of used words in this section */ - __u32 set_uuid0; /* 5 Raid set identifier */ - __u32 ctime; /* 6 Creation time */ - __u32 level; /* 7 Raid personality */ - __u32 size; /* 8 Apparent size of each individual disk */ - __u32 nr_disks; /* 9 total disks in the raid set */ - __u32 raid_disks; /* 10 disks in a fully functional raid set */ - __u32 md_minor; /* 11 preferred MD minor device number */ - __u32 not_persistent; /* 12 does it have a persistent superblock */ - __u32 set_uuid1; /* 13 Raid set identifier #2 */ - __u32 set_uuid2; /* 14 Raid set identifier #3 */ - __u32 set_uuid3; /* 15 Raid set identifier #4 */ - __u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 16]; - - /* - * Generic state information - */ - __u32 utime; /* 0 Superblock update time */ - __u32 state; /* 1 State bits (clean, ...) */ - __u32 active_disks; /* 2 Number of currently active disks */ - __u32 working_disks; /* 3 Number of working disks */ - __u32 failed_disks; /* 4 Number of failed disks */ - __u32 spare_disks; /* 5 Number of spare disks */ - __u32 sb_csum; /* 6 checksum of the whole superblock */ -#ifdef __KERNEL__ -#ifdef __BIG_ENDIAN - __u32 events_hi; /* 7 high-order of superblock update count */ - __u32 events_lo; /* 8 low-order of superblock update count */ -#else - __u32 events_lo; /* 7 low-order of superblock update count */ - __u32 events_hi; /* 8 high-order of superblock update count */ -#endif -#else -#if __BYTE_ORDER == __BIG_ENDIAN - __u32 events_hi; /* 7 high-order of superblock update count */ - __u32 events_lo; /* 8 low-order of superblock update count */ -#else - __u32 events_lo; /* 7 low-order of superblock update count */ - __u32 events_hi; /* 8 high-order of superblock update count */ -#endif -#endif - __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 9]; - - /* - * Personality information - */ - __u32 layout; /* 0 the array's physical layout */ - __u32 chunk_size; /* 1 chunk size in bytes */ - __u32 root_pv; /* 2 LV root PV */ - __u32 root_block; /* 3 LV root block */ - __u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 4]; - - /* - * Disks information - */ - mdp_disk_t disks[MD_SB_DISKS]; - - /* - * Reserved - */ - __u32 reserved[MD_SB_RESERVED_WORDS]; - - /* - * Active descriptor - */ - mdp_disk_t this_disk; - -}mdp_super_t; - -static inline __u64 md_event(mdp_super_t *sb) { - __u64 ev = sb->events_hi; - return (ev<<32)| sb->events_lo; -} - -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md_u.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md_u.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_md_u.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_md_u.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,69 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * - * linux/include/linux/evms/evms_md_h.c - * - * EVMS MD Region Manager, User <-> Kernel common file - * - */ - -#ifndef _EVMS_MD_U_INC_ -#define _EVMS_MD_U_INC_ - -#define EVMS_MD_ID 4 -#define MD_SET_PLUGIN_ID SetPluginID(IBM_OEM_ID,EVMS_REGION_MANAGER,EVMS_MD_ID) - -#define EVMS_MD_PERS_IOCTL_CMD 1 /* personality specific ioctl command */ -#define EVMS_MD_ADD 2 -#define EVMS_MD_REMOVE 3 -#define EVMS_MD_ACTIVATE 4 -#define EVMS_MD_DEACTIVATE 5 -#define EVMS_MD_GET_ARRAY_INFO 6 - -/** - * structure definition to use with MD_ADD, MD_REMOVE, MD_ACTIVATE - **/ -struct evms_md_kdev { - u32 major; - u32 minor; -}; - -/** - * structure definition to use with MD_GET_ARRAY_INFO - **/ -#define EVMS_MD_ARRAY_DEGRADED (1<<0) -#define EVMS_MD_ARRAY_SYNCING (1<<1) -struct evms_md_array_info { - u32 state; - mdp_super_t *sb; -}; - -/** - * EVMS MD user/kernel communication - * @mddev_idx: md minor - * @cmd: command for personality - * @arg: specific command structure - **/ -struct evms_md_ioctl { - u32 mddev_idx; - u32 cmd; - void *arg; -}; - -#endif - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_os2.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_os2.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_os2.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_os2.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,386 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - * - * Module: linux/include/linux/evms_os2.h - */ - -/* - * Change History: - * - */ - -/* - * Description: This module defines the disk structures used by the OS/2 - * Logical Volume Manager, including that of the Master - * Boot Record (MBR) and Extended Boot Records (EBR). - * - * Notes: LVM Drive Letter Assignment Tables (DLA_Tables) appear on the - * last sector of each track containing a valid MBR or EBR. Since - * partitions must be track aligned, any track containing an MBR or - * EBR will be almost all empty sectors. We will grab the last - * of these empty sectors for our DLT_Tables. - * - */ - -#ifndef OS2LVM_INCLUDED__ -#define OS2LVM_INCLUDED__ - -/* The following define the values used to indicate that a partition table entry is for an EBR, not a partition. */ -#define EBR_BOOT_INDICATOR 0 -#define EBR_FORMAT_INDICATOR 5 - -/* The following define is used as the default Format_Indicator for new non-primary partitions. */ -#define NEW_LOGICAL_DRIVE_FORMAT_INDICATOR 0x6 - -/* The following define is used as the default Format_Indicator for a new non-active primary partitions. */ -#define NEW_PRIMARY_PARTITION_FORMAT_INDICATOR 0x16 - -/* The following define is used as the default Format_Indicator for a new active primary partition. */ -#define NEW_ACTIVE_PRIMARY_PARTITION_FORMAT_INDICATOR 0x06 - -/* The following define is used to hold the value of the Boot_Indicator for active partitions. */ -#define ACTIVE_PARTITION 0x80 - -/* Define the size of a Partition Name. Partition Names are user defined names given to a partition. */ -#define PARTITION_NAME_SIZE 20 - -/* Define the size of a volume name. Volume Names are user defined names given to a volume. */ -#define VOLUME_NAME_SIZE 20 - -/* Define the size of a disk name. Disk Names are user defined names given to physical disk drives in the system. */ -#define DISK_NAME_SIZE 20 - -/* The name of the filesystem in use on a partition. This name may be up to 12 ( + NULL terminator) characters long. */ -#define FILESYSTEM_NAME_SIZE 20 - -/* The comment field is reserved but is not currently used. This is for future expansion and use. */ -#define COMMENT_SIZE 81 - -/* Define the minimum number of sectors to reserve on the disk for Boot Manager. */ -#define BOOT_MANAGER_SIZE 2048 - -#define OS2_BYTES_PER_SECTOR 512 -#define OS2_SECTOR_SHIFT 9 - -/*-------------------------------------------------- - * Type definitions - --------------------------------------------------*/ - -/* The following definitions define the drive letter assignment table used by LVM. - For each partition table on the disk, there will be a drive letter assignment table in the last sector - of the track containing the partition table. */ - -/* NOTE: DLA stands for Drive Letter Assignment. */ - -#define DLA_TABLE_SIGNATURE1 0x424D5202L -#define DLA_TABLE_SIGNATURE2 0x44464D50L - -struct dla_entry { /* DE */ - u32 Volume_Serial_Number; /* The serial number of the volume that this partition belongs to. */ - u32 partition_serial; /* The serial number of this partition. */ - u32 Partition_Size; /* The size of the partition, in sectors. */ - u32 Partition_Start; /* The starting sector of the partition. */ - unsigned char On_Boot_Manager_Menu; /* Set to TRUE if this volume/partition is on the Boot Manager Menu. */ - unsigned char Installable; /* Set to TRUE if this volume is the one to install the operating system on. */ - char Drive_Letter; /* The drive letter assigned to the partition. */ - unsigned char Reserved; - char Volume_Name[VOLUME_NAME_SIZE]; /* The name assigned to the volume by the user. */ - char Partition_Name[PARTITION_NAME_SIZE]; /* The name assigned to the partition. */ -}; - -struct dla_table_sector { /* DTS */ - u32 DLA_Signature1; /* The magic signature (part 1) of a Drive Letter Assignment Table. */ - u32 DLA_Signature2; /* The magic signature (part 2) of a Drive Letter Assignment Table. */ - u32 DLA_CRC; /* The 32 bit CRC for this sector. Calculated assuming that this field and all unused space in the sector is 0. */ - u32 Disk_Serial_Number; /* The serial number assigned to this disk. */ - u32 Boot_Disk_Serial_Number; /* The serial number of the disk used to boot the system. This is for conflict resolution when multiple volumes - want the same drive letter. Since LVM.EXE will not let this situation happen, the only way to get this situation - is for the disk to have been altered by something other than LVM.EXE, or if a disk drive has been moved from one - machine to another. If the drive has been moved, then it should have a different Boot_Disk_Serial_Number. Thus, - we can tell which disk drive is the "foreign" drive and therefore reject its claim for the drive letter in question. - If we find that all of the claimaints have the same Boot_Disk_Serial_Number, then we must assign drive letters on - a first come, first serve basis. */ - u32 Install_Flags; /* Used by the Install program. */ - u32 Cylinders; - u32 Heads_Per_Cylinder; - u32 Sectors_Per_Track; - char Disk_Name[DISK_NAME_SIZE]; /* The name assigned to the disk containing this sector. */ - unsigned char Reboot; /* For use by Install. Used to keep track of reboots initiated by install. */ - unsigned char Reserved[3]; /* Alignment. */ - struct dla_entry DLA_Array[4]; /* These are the four entries which correspond to the entries in the partition table. */ -}; - -/* The following definitions define the LVM signature sector which will appear as the last sector in an LVM partition. */ - -#define OS2LVM_PRIMARY_SIGNATURE 0x4A435332L -#define OS2LVM_SECONDARY_SIGNATURE 0x4252444BL - -#define CURRENT_OS2LVM_MAJOR_VERSION_NUMBER 2 /* Define as appropriate. */ -#define CURRENT_OS2LVM_MINOR_VERSION_NUMBER 0 /* Define as appropriate. */ - -/* The following definitions limit the number of LVM features that can be applied to a volume, as well as defining a "NULL" feature for use in feature table entries that are not being used. */ -#define OS2LVM_MAX_FEATURES_PER_VOLUME 10 /* The maximum number of LVM features that can be applied to a volume. */ -#define OS2LVM_NULL_FEATURE 0 /* No feature. Used in all unused entries of the feature array in the LVM Signature sector. */ - -/* The following structure is used to hold the location of the feature specific data for LVM features. */ -typedef struct _LVM_Feature_Data { /* LFD */ - u32 Feature_ID; /* The ID of the feature. */ - u32 Location_Of_Primary_Feature_Data; /* The u32 of the starting sector of the private data for this feature. */ - u32 Location_Of_Secondary_Feature_Data; /* The u32 of the starting sector of the backup copy of the private data for this feature. */ - u32 Feature_Data_Size; /* The number of sectors used by this feature for its private data. */ - u16 Feature_Major_Version_Number; /* The integer portion of the version number of this feature. */ - u16 Feature_Minor_Version_Number; /* The decimal portion of the version number of this feature. */ - unsigned char Feature_Active; /* TRUE if this feature is active on this partition/volume, FALSE otherwise. */ - unsigned char Reserved[3]; /* Alignment. */ -} LVM_Feature_Data; - -/* The following structure defines the LVM Signature Sector. This is the last sector of every partition which is part of an LVM volume. It gives vital - information about the version of LVM used to create the LVM volume that it is a part of, as well as which LVM features (BBR, drive linking, etc.) are - active on the volume that this partition is a part of. */ -typedef struct _LVM_Signature_Sector { /* LSS */ - u32 LVM_Signature1; /* The first part of the magic LVM signature. */ - u32 LVM_Signature2; /* The second part of the magic LVM signature. */ - u32 Signature_Sector_CRC; /* 32 bit CRC for this sector. Calculated using 0 for this field. */ - u32 partition_serial; /* The LVM assigned serial number for this partition. */ - u32 Partition_Start; /* u32 of the first sector of this partition. */ - u32 Partition_End; /* u32 of the last sector of this partition. */ - u32 Partition_Sector_Count; /* The number of sectors in this partition. */ - u32 LVM_Reserved_Sector_Count; /* The number of sectors reserved for use by LVM. */ - u32 Partition_Size_To_Report_To_User; /* The size of the partition as the user sees it - i.e. (the actual size of the partition - LVM reserved sectors) rounded to a track boundary. */ - u32 Boot_Disk_Serial_Number; /* The serial number of the boot disk for the system. If the system contains Boot Manager, then this is the serial number of the disk containing the active copy of Boot Manager. */ - u32 Volume_Serial_Number; /* The serial number of the volume that this partition belongs to. */ - u32 Fake_EBR_Location; /* The location, on disk, of a Fake EBR, if one has been allocated. */ - u16 LVM_Major_Version_Number; /* Major version number of the LVM that created this partition. */ - u16 LVM_Minor_Version_Number; /* Minor version number of the LVM that created this partition. */ - char Partition_Name[PARTITION_NAME_SIZE]; /* User defined partition name. */ - char Volume_Name[VOLUME_NAME_SIZE]; /* The name of the volume that this partition belongs to. */ - LVM_Feature_Data LVM_Feature_Array[OS2LVM_MAX_FEATURES_PER_VOLUME]; /* The feature array. This indicates which LVM features, if any, are active on this volume - and what order they should be applied in. */ - char Drive_Letter; /* The drive letter assigned to the volume that this partition is part of. */ - unsigned char Fake_EBR_Allocated; /* If TRUE, then a fake EBR has been allocated. */ - char Comment[COMMENT_SIZE]; /* User comment. */ - char Disk_Name[DISK_NAME_SIZE]; /* Added to allow BBR to report the name of a disk when bad sectors are encountered on that disk. */ - u32 Sequence_Number; /* This indicates the order that partitions within a volume are used. This number is 1 based. A 0 here indicates that the volume was made by LVM Ver. 1. */ - u32 Next_Aggregate_Number; /* Used during volume creation and expansion when creating unique names for aggregates. */ - /* The remainder of the sector is reserved for future use and should be all zero or else the CRC will not come out correctly. */ -} LVM_Signature_Sector; - -/* The following definitions define the format of a partition table and the Master Boot Record (MBR). */ -typedef struct _Partition_Record { /* PR */ - unsigned char Boot_Indicator; /* 80h = active partition. */ - unsigned char Starting_Head; - unsigned char Starting_Sector; /* Bits 0-5 are the sector. Bits 6 and 7 are the high order bits of the starting cylinder. */ - unsigned char Starting_Cylinder; /* The cylinder number is a 10 bit value. The high order bits of the 10 bit value come from bits 6 & 7 of the Starting_Sector field. */ - unsigned char Format_Indicator; /* An indicator of the format/operation system on this partition. */ - unsigned char Ending_Head; - unsigned char Ending_Sector; - unsigned char Ending_Cylinder; - u32 Sector_Offset; /* The number of sectors on the disk which are prior to the start of this partition. */ - u32 Sector_Count; /* The number of sectors in this partition. */ -} Partition_Record; - -typedef struct _Master_Boot_Record { /* MBR */ - unsigned char Reserved[446]; - Partition_Record Partition_Table[4]; - u16 Signature; /* AA55h in this field indicates that this is a valid partition table/MBR. */ -} Master_Boot_Record; - -typedef Master_Boot_Record Extended_Boot_Record; - -/* The following definition covers the Boot Manager Alias Table in the EBR. - - The Alias Table in the EBR has 2 entries in it, although only the first one is actually used. */ -#define ALIAS_NAME_SIZE 8 -typedef struct _AliasTableEntry { /* ATE */ - unsigned char On_Boot_Manager_Menu; - char Name[ALIAS_NAME_SIZE]; -} AliasTableEntry; - -#define ALIAS_TABLE_OFFSET 0x18A - -/* XLATOFF */ -/* The following text is used for the Boot Manager Alias for items that were placed on the Boot Manager Menu by FDISK and - which have since been migrated to the new LVM format. This text is put into the Name field of an AliasTableEntry so - that, if FDISK ( or another program which understands the old Boot Manager Menu format) is run, it will display - something for those partitions/volumes which are on the Boot Manager Menu. - - NOTE: This text must be exactly ALIAS_NAME_SIZE characters in length! */ -#define ALIAS_TABLE_ENTRY_MIGRATION_TEXT "--> LVM " -#define ALIAS_TABLE_ENTRY_MIGRATION_TEXT2 "--> LVM*" - -/* XLATON */ - -/* The following is the signature used for an Master Boot Record, an Extended Boot Record, and a Boot Sector. */ -#define MBR_EBR_SIGNATURE 0xAA55 - -/* The following list of definitions defines the values of interest for the Format_Indicator in a Partition_Record. */ -#define EBR_INDICATOR 0x5 -#define WINDOZE_EBR_INDICATOR 0xF -#define UNUSED_INDICATOR 0x0 -#define IFS_INDICATOR 0x7 -#define FAT12_INDICATOR 0x1 -#define FAT16_SMALL_PARTITION_INDICATOR 0x4 -#define FAT16_LARGE_PARTITION_INDICATOR 0x6 -#define BOOT_MANAGER_HIDDEN_PARTITION_FLAG 0x10 -#define LVM_PARTITION_INDICATOR 0x35 -#define BOOT_MANAGER_INDICATOR 0x0A - -/* The following is the signature used in the Boot Sector for Boot Manager. */ -#define OS2LVM_BOOT_MANAGER_SIGNATURE "APJ&WN" - -/* The following is used for determining the synthetic geometry reported for Volumes employing drive linking. */ -#define OS2LVM_SYNTHETIC_SECTORS_PER_TRACK 63 - -/*-------------------------------------------------- - * Declares for Drive Linking feature: - *--------------------------------------------------*/ - -/* The following defines uniquely identify Drive Linking. */ -#define DRIVE_LINKING_FEATURE_ID 100 -#define DRIVE_LINKING_MAJOR_VERSION 1 -#define DRIVE_LINKING_MINOR_VERSION 0 - -/* The following definitions are used for the disk structures supporting drive linking. */ - -#define LINK_TABLE_MASTER_SIGNATURE 0x434E4157L -#define LINK_TABLE_SIGNATURE 0X4D4D5652L - -#define MAXIMUM_LINKS 246 - -#define DRIVE_LINKING_RESERVED_SECTOR_COUNT 4 - -#define LINKS_IN_FIRST_SECTOR 60 - -#define LINKS_IN_NEXT_SECTOR 62 - -struct drive_link { - u32 drive_serial; - u32 partition_serial; -}; - -struct link_table_first_sector { - u32 Link_Table_Signature; /* Use the LINK_TABLE_MASTER_SIGNATURE here. */ - u32 Link_Table_CRC; - u32 Sequence_Number; /* Used to resolve conflicts when the primary and secondary tables do not match. */ - u32 Links_In_Use; - struct drive_link Link_Table[LINKS_IN_FIRST_SECTOR]; -}; - -struct link_table_sector { - u32 Link_Table_Signature; /* Use LINK_TABLE_SIGNATURE here. */ - u32 Link_Table_CRC; - u32 Sequence_Number; /* Used to resolve conflicts when the primary and secondary tables do not match. */ - struct drive_link Link_Table[LINKS_IN_NEXT_SECTOR]; -}; - -/*-------------------------------------------------- - * Declares for Bad Block Relocation feature: - *--------------------------------------------------*/ - -/* The following definition is the numeric ID for Bad Block Relocation. */ -#define BBR_FEATURE_ID 101 - -#define BBR_FEATURE_MAJOR_VERSION 0x0001 -#define BBR_FEATURE_MINOR_VERSION 0x0000 - -/* The following definitions are used for the disk structures supporting bad block relocation. */ - -/* NOTE: BBR stands for Bad Block Relocation. */ - -#define BBR_TABLE_MASTER_SIGNATURE 0x00726D62 -#define BBR_TABLE_SIGNATURE 0x01726276 - -struct bbr_table_entry { - u32 BadSector; - u32 ReplacementSector; -}; - -typedef struct _LVM_BBR_Table_First_Sector { - u32 Signature; /* Signature for the first sector of the BBR Table. Use BBR_TABLE_MASTER_SIGNATURE here. */ - u32 CRC; /* CRC for this sector. */ - u32 Sequence_Number; /* Used to resolve conflicts when the primary and secondary tables do not match. */ - u32 Table_Size; /* The number of BBR_Table_Entries in the BBR Table. */ - u32 Table_Entries_In_Use; /* The number of BBR Table entries which are in use. */ - u32 Sectors_Per_Table; /* The number of LVM_BBR_Table_Sectors used to hold the BBR Table. */ - u32 First_Replacement_Sector; /* The location of the first replacement sector. */ - u32 Last_Replacement_Sector; /* The location of the last replacement sector. */ - u32 Replacement_Sector_Count; /* The number of replacement sectors. */ - u32 Flags; /* Flags global to the Bad Block Relocation Feature. */ -} LVM_BBR_Table_First_Sector; - -/* Flags for LVM_BBR_Table_First_Sector */ -#define BBR_Flag_Write_Verify 0x00000001 /* Indicate convert Write I/O to Write/Verify */ - -#define BBR_TABLE_ENTRIES_PER_SECTOR 62 - -typedef struct _LVM_BBR_Table_Sector { - u32 Signature; /* Signature for a sector of the BBR_Table which is not the first sector of the BBR Table. Use BBR_TABLE_SIGNATURE here. */ - u32 CRC; /* CRC for this sector of the BBR Table. */ - u32 Sequence_Number; /* Used to resolve conflicts when the primary and secondary tables do not match. */ - struct bbr_table_entry BBR_Table[BBR_TABLE_ENTRIES_PER_SECTOR]; - u32 reserved1; /* for block alignment */ -} LVM_BBR_Table_Sector; - -// -// Combined structure to hold entire BBR feature data as it exists on disk. -typedef struct _LVM_BBR_Feature { - LVM_BBR_Table_First_Sector control; - char reserved1[OS2_BYTES_PER_SECTOR - - sizeof (LVM_BBR_Table_First_Sector)]; - LVM_BBR_Table_Sector remap[1]; -} -LVM_BBR_Feature; - -/* The following defines establish the minimum and maximum number of replacement sectors which can be allocated for - Bad Block Relocation. Otherwise, 1 replacement sector per MB of disk space is allocated. */ -#define BBR_FLOOR 62 -#define BBR_LIMIT 4096 - -// In-memory Meta Data for Bad Block Relocation -// In-memory Meta Data for Drive Linking -struct os2_dl_entry { - u64 start_sector; - u64 sector_count; - u64 dl_lsn1; /* LSN of first on-disk copy of drive linking data. */ - u64 dl_lsn2; /* LSN of the second on-disk copy of drive linking data. */ - char *link_data; - u32 partition_serial; - u64 bbr_lsn1; /* LSN of the first on-disk copy of the BBR data. */ - u64 bbr_lsn2; /* LSN of the second on-disk copy of the BBR data. */ - u32 bbr_feature_size; /* # of sectors of BBR data. */ - u32 bbr_is_active; - struct semaphore bbr_table_lock; /* Used to serialize writers */ - unsigned int guard1; /* Lamport's Theorem for mutual exclusion */ - char *bbr_data; - unsigned int guard2; /* Lamport's Theorem for mutual exclusion */ - struct evms_logical_node *link_partition; - struct os2_dl_entry *next; -}; - -// In-memory Meta Data for each OS/2 LVM Volume: -typedef struct os2_volume_runtime_entry_s { - int complete; - u32 Export_Needed; - u64 size_in_sectors; - u32 Volume_Serial_Number; - u32 drive_link_count; - struct os2_dl_entry *drive_link; - struct evms_logical_node *next_os2lvm_node; -} os2_volume_runtime_entry_t; - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_raid0.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_raid0.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_raid0.h 2003-05-03 03:22:36.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_raid0.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,33 +0,0 @@ -#ifndef _EVMS_RAID0_INCL_ -#define _EVMS_RAID0_INCL_ - -#include - -struct strip_zone -{ - unsigned long zone_offset; /* Zone offset (in sectors) in md_dev */ - unsigned long dev_offset; /* Zone offset (in sectors) in real dev */ - unsigned long size_in_sects; /* Zone size in sectors */ - int nb_dev; /* # of devices attached to the zone */ - struct evms_logical_node *node[MD_SB_DISKS]; /* EVMS nodes attached to the zone */ -}; - -struct raid0_hash -{ - struct strip_zone *zone0, *zone1; -}; - -struct raid0_private_data -{ - struct raid0_hash *hash_table; /* Dynamically allocated */ - struct strip_zone *strip_zone; /* This one too */ - int nr_strip_zones; - struct strip_zone *smallest; - int nr_zones; -}; - -typedef struct raid0_private_data raid0_conf_t; - -#define mddev_to_conf(mddev) ((raid0_conf_t *) mddev->private) - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_raid1.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_raid1.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_raid1.h 2003-05-03 03:22:38.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_raid1.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,103 +0,0 @@ -#ifndef _EVMS_RAID1_H -#define _EVMS_RAID1_H - -#include - -struct mirror_info { - int number; - int raid_disk; - struct evms_logical_node *node; - kdev_t dev; - int sect_limit; - int head_position; - - /* - * State bits: - */ - int operational; - int write_only; - int spare; - - int used_slot; -}; - -struct raid1_private_data { - mddev_t *mddev; - struct mirror_info mirrors[MD_SB_DISKS]; - int nr_disks; - int raid_disks; - int working_disks; - int last_used; - unsigned long next_sect; - int sect_count; - struct evms_thread *thread, *resync_thread; - int resync_mirrors; - struct mirror_info *spare; - md_spinlock_t device_lock; - - /* buffer pool */ - /* buffer_heads that we have pre-allocated have b_pprev -> &freebh - * and are linked into a stack using b_next - * raid1_bh that are pre-allocated have R1BH_PreAlloc set. - * All these variable are protected by device_lock - */ - struct buffer_head *freebh; - int freebh_cnt; /* how many are on the list */ - int freebh_blocked; - struct raid1_bh *freer1; - int freer1_blocked; - int freer1_cnt; - struct raid1_bh *freebuf; /* each bh_req has a page allocated */ - md_wait_queue_head_t wait_buffer; - - /* for use when syncing mirrors: */ - unsigned long start_active, start_ready, - start_pending, start_future; - int cnt_done, cnt_active, cnt_ready, - cnt_pending, cnt_future; - int phase; - int window; - md_wait_queue_head_t wait_done; - md_wait_queue_head_t wait_ready; - md_spinlock_t segment_lock; -}; - -typedef struct raid1_private_data raid1_conf_t; - -/* - * this is the only point in the RAID code where we violate - * C type safety. mddev->private is an 'opaque' pointer. - */ -#define mddev_to_conf(mddev) ((raid1_conf_t *) mddev->private) - -/* - * this is our 'private' 'collective' RAID1 buffer head. - * it contains information about what kind of IO operations were started - * for this RAID1 operation, and about their status: - */ - -struct raid1_bh { - atomic_t remaining; /* 'have we finished' count, - * used from IRQ handlers - */ - int cmd; - unsigned long state; - mddev_t *mddev; - struct buffer_head *master_bh; - struct buffer_head *mirror_bh_list; - struct buffer_head bh_req; - struct evms_logical_node *node; /* map to evms node (READ only) */ - struct raid1_bh *next_r1; /* next for retry or in free list */ -}; - -typedef struct raid1_sync_cb_s { - int rc; - atomic_t io_count; - md_wait_queue_head_t wait; -} raid1_sync_cb_t; - -/* bits for raid1_bh.state */ -#define R1BH_Uptodate 1 -#define R1BH_SyncPhase 2 -#define R1BH_PreAlloc 3 /* this was pre-allocated, add to free list */ -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_raid5.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_raid5.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_raid5.h 2003-05-03 03:22:41.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_raid5.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,251 +0,0 @@ -#ifndef _RAID5_H -#define _RAID5_H - -#include -#include - -/* - * - * Each stripe contains one buffer per disc. Each buffer can be in - * one of a number of states determined by bh_state. Changes between - * these states happen *almost* exclusively under a per-stripe - * spinlock. Some very specific changes can happen in b_end_io, and - * these are not protected by the spin lock. - * - * The bh_state bits that are used to represent these states are: - * BH_Uptodate, BH_Lock - * - * State Empty == !Uptodate, !Lock - * We have no data, and there is no active request - * State Want == !Uptodate, Lock - * A read request is being submitted for this block - * State Dirty == Uptodate, Lock - * Some new data is in this buffer, and it is being written out - * State Clean == Uptodate, !Lock - * We have valid data which is the same as on disc - * - * The possible state transitions are: - * - * Empty -> Want - on read or write to get old data for parity calc - * Empty -> Dirty - on compute_parity to satisfy write/sync request.(RECONSTRUCT_WRITE) - * Empty -> Clean - on compute_block when computing a block for failed drive - * Want -> Empty - on failed read - * Want -> Clean - on successful completion of read request - * Dirty -> Clean - on successful completion of write request - * Dirty -> Clean - on failed write - * Clean -> Dirty - on compute_parity to satisfy write/sync (RECONSTRUCT or RMW) - * - * The Want->Empty, Want->Clean, Dirty->Clean, transitions - * all happen in b_end_io at interrupt time. - * Each sets the Uptodate bit before releasing the Lock bit. - * This leaves one multi-stage transition: - * Want->Dirty->Clean - * This is safe because thinking that a Clean buffer is actually dirty - * will at worst delay some action, and the stripe will be scheduled - * for attention after the transition is complete. - * - * There is one possibility that is not covered by these states. That - * is if one drive has failed and there is a spare being rebuilt. We - * can't distinguish between a clean block that has been generated - * from parity calculations, and a clean block that has been - * successfully written to the spare ( or to parity when resyncing). - * To distingush these states we have a stripe bit STRIPE_INSYNC that - * is set whenever a write is scheduled to the spare, or to the parity - * disc if there is no spare. A sync request clears this bit, and - * when we find it set with no buffers locked, we know the sync is - * complete. - * - * Buffers for the md device that arrive via make_request are attached - * to the appropriate stripe in one of two lists linked on b_reqnext. - * One list (bh_read) for read requests, one (bh_write) for write. - * There should never be more than one buffer on the two lists - * together, but we are not guaranteed of that so we allow for more. - * - * If a buffer is on the read list when the associated cache buffer is - * Uptodate, the data is copied into the read buffer and it's b_end_io - * routine is called. This may happen in the end_request routine only - * if the buffer has just successfully been read. end_request should - * remove the buffers from the list and then set the Uptodate bit on - * the buffer. Other threads may do this only if they first check - * that the Uptodate bit is set. Once they have checked that they may - * take buffers off the read queue. - * - * When a buffer on the write list is committed for write is it copied - * into the cache buffer, which is then marked dirty, and moved onto a - * third list, the written list (bh_written). Once both the parity - * block and the cached buffer are successfully written, any buffer on - * a written list can be returned with b_end_io. - * - * The write list and read list both act as fifos. The read list is - * protected by the device_lock. The write and written lists are - * protected by the stripe lock. The device_lock, which can be - * claimed while the stipe lock is held, is only for list - * manipulations and will only be held for a very short time. It can - * be claimed from interrupts. - * - * - * Stripes in the stripe cache can be on one of two lists (or on - * neither). The "inactive_list" contains stripes which are not - * currently being used for any request. They can freely be reused - * for another stripe. The "handle_list" contains stripes that need - * to be handled in some way. Both of these are fifo queues. Each - * stripe is also (potentially) linked to a hash bucket in the hash - * table so that it can be found by sector number. Stripes that are - * not hashed must be on the inactive_list, and will normally be at - * the front. All stripes start life this way. - * - * The inactive_list, handle_list and hash bucket lists are all protected by the - * device_lock. - * - stripes on the inactive_list never have their stripe_lock held. - * - stripes have a reference counter. If count==0, they are on a list. - * - If a stripe might need handling, STRIPE_HANDLE is set. - * - When refcount reaches zero, then if STRIPE_HANDLE it is put on - * handle_list else inactive_list - * - * This, combined with the fact that STRIPE_HANDLE is only ever - * cleared while a stripe has a non-zero count means that if the - * refcount is 0 and STRIPE_HANDLE is set, then it is on the - * handle_list and if recount is 0 and STRIPE_HANDLE is not set, then - * the stripe is on inactive_list. - * - * The possible transitions are: - * activate an unhashed/inactive stripe (get_active_stripe()) - * lockdev check-hash unlink-stripe cnt++ clean-stripe hash-stripe unlockdev - * activate a hashed, possibly active stripe (get_active_stripe()) - * lockdev check-hash if(!cnt++)unlink-stripe unlockdev - * attach a request to an active stripe (add_stripe_bh()) - * lockdev attach-buffer unlockdev - * handle a stripe (handle_stripe()) - * lockstripe clrSTRIPE_HANDLE ... (lockdev check-buffers unlockdev) .. change-state .. record io needed unlockstripe schedule io - * release an active stripe (release_stripe()) - * lockdev if (!--cnt) { if STRIPE_HANDLE, add to handle_list else add to inactive-list } unlockdev - * - * The refcount counts each thread that have activated the stripe, - * plus raid5d if it is handling it, plus one for each active request - * on a cached buffer. - */ -struct stripe_head { - struct stripe_head *hash_next, **hash_pprev; /* hash pointers */ - struct list_head lru; /* inactive_list or handle_list */ - struct raid5_private_data *raid_conf; - struct buffer_head *bh_cache[MD_SB_DISKS]; /* buffered copy */ - struct buffer_head *bh_read[MD_SB_DISKS]; /* read request buffers of the MD device */ - struct buffer_head *bh_write[MD_SB_DISKS]; /* write request buffers of the MD device */ - struct buffer_head *bh_written[MD_SB_DISKS]; /* write request buffers of the MD device that have been scheduled for write */ - struct page *bh_page[MD_SB_DISKS]; /* saved bh_cache[n]->b_page when reading around the cache */ - struct evms_logical_node *node[MD_SB_DISKS]; /* the target device node */ - unsigned long sector; /* sector of this row */ - int size; /* buffers size */ - int pd_idx; /* parity disk index */ - unsigned long state; /* state flags */ - atomic_t count; /* nr of active thread/requests */ - spinlock_t lock; - int sync_redone; -}; - - -/* - * Write method - */ -#define RECONSTRUCT_WRITE 1 -#define READ_MODIFY_WRITE 2 -/* not a write method, but a compute_parity mode */ -#define CHECK_PARITY 3 - -/* - * Stripe state - */ -#define STRIPE_ERROR 1 -#define STRIPE_HANDLE 2 -#define STRIPE_SYNCING 3 -#define STRIPE_INSYNC 4 -#define STRIPE_PREREAD_ACTIVE 5 -#define STRIPE_DELAYED 6 - -/* - * Plugging: - * - * To improve write throughput, we need to delay the handling of some - * stripes until there has been a chance that several write requests - * for the one stripe have all been collected. - * In particular, any write request that would require pre-reading - * is put on a "delayed" queue until there are no stripes currently - * in a pre-read phase. Further, if the "delayed" queue is empty when - * a stripe is put on it then we "plug" the queue and do not process it - * until an unplg call is made. (the tq_disk list is run). - * - * When preread is initiated on a stripe, we set PREREAD_ACTIVE and add - * it to the count of prereading stripes. - * When write is initiated, or the stripe refcnt == 0 (just in case) we - * clear the PREREAD_ACTIVE flag and decrement the count - * Whenever the delayed queue is empty and the device is not plugged, we - * move any strips from delayed to handle and clear the DELAYED flag and set PREREAD_ACTIVE. - * In stripe_handle, if we find pre-reading is necessary, we do it if - * PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue. - * HANDLE gets cleared if stripe_handle leave nothing locked. - */ - - -struct disk_info { - kdev_t dev; - struct evms_logical_node *node; - int operational; - int number; - int raid_disk; - int write_only; - int spare; - int used_slot; -}; - -struct raid5_private_data { - struct stripe_head **stripe_hashtbl; - mddev_t *mddev; - struct evms_thread *thread, *resync_thread; - struct disk_info disks[MD_SB_DISKS]; - struct disk_info *spare; - int buffer_size; - int chunk_size, level, algorithm; - int raid_disks, working_disks, failed_disks; - int resync_parity; - int max_nr_stripes; - - struct list_head handle_list; /* stripes needing handling */ - struct list_head delayed_list; /* stripes that have plugged requests */ - atomic_t preread_active_stripes; /* stripes with scheduled io */ - /* - * Free stripes pool - */ - atomic_t active_stripes; - struct list_head inactive_list; - md_wait_queue_head_t wait_for_stripe; - int inactive_blocked; /* release of inactive stripes blocked, - * waiting for 25% to be free - */ - md_spinlock_t device_lock; - - int plugged; - struct tq_struct plug_tq; -}; - -typedef struct raid5_private_data raid5_conf_t; - -#define mddev_to_conf(mddev) ((raid5_conf_t *) mddev->private) - -/* - * Our supported algorithms - */ -#define ALGORITHM_LEFT_ASYMMETRIC 0 -#define ALGORITHM_RIGHT_ASYMMETRIC 1 -#define ALGORITHM_LEFT_SYMMETRIC 2 -#define ALGORITHM_RIGHT_SYMMETRIC 3 - - -#define EVMS_MD_RAID5_INIT_IO 1 - -struct r5_sync_io { - int rw; - u64 lsn; - u64 nr_sects; - void *data; -}; -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_snapshot.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_snapshot.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_snapshot.h 2003-05-03 02:00:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_snapshot.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,361 +0,0 @@ -/* -*- linux-c -*- */ -/* - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ -/* - * linux/include/linux/evms_snapshot.h - * - * EVMS Snapshot Feature kernel header file - */ - -#ifndef __EVMS_SNAPSHOT_INCLUDED__ -#define __EVMS_SNAPSHOT_INCLUDED__ - -#define EVMS_SNAPSHOT_VERSION_MAJOR 2 -#define EVMS_SNAPSHOT_VERSION_MINOR 1 -#define EVMS_SNAPSHOT_VERSION_PATCHLEVEL 2 - -#define EVMS_SNAPSHOT_FEATURE_ID 104 - -#define EVMS_SNAPSHOT_SIGNATURE 0x536e4170 /* SnAp */ -#define EVMS_ORIGINAL_SIGNATURE 0x4f724967 /* OrIg */ -#define MAX_HASH_CHAIN_ENTRIES 10 - -/* Status flags */ -#define EVMS_SNAPSHOT 0x001 -#define EVMS_SNAPSHOT_ORG 0x002 -#define EVMS_SNAPSHOT_DISABLED 0x004 -#define EVMS_SNAPSHOT_FULL 0x008 -#define EVMS_SNAPSHOT_QUIESCED 0x010 -#define EVMS_SNAPSHOT_WRITEABLE 0x020 -#define EVMS_SNAPSHOT_ASYNC 0x040 -#define EVMS_SNAPSHOT_ROLLBACK 0x080 -#define EVMS_SNAPSHOT_ROLLBACK_COMP 0x100 -#define EVMS_SNAPSHOT_DISABLED_PENDING 0x200 - -/* Private ioctl commands */ -#define SNAPSHOT_QUERY_PERCENT_FULL 1 -#define SNAPSHOT_START_ROLLBACK 2 -#define SNAPSHOT_CHECK_STATE 3 - -/* Chunk states - for async mode */ -#define SNAP_CHUNK_COPYING 1 /* Chunk is being copied from org to snap. */ -#define SNAP_CHUNK_COPIED 0 /* Chunk has been copied from org to snap. */ - -#define SNAPSHOT_DEFAULT_CHUNK_SIZE 128 /* sectors == 64k */ -#define SNAPSHOT_MIN_CHUNK_SIZE 16 /* 8kB */ -#define SNAPSHOT_MAX_CHUNK_SIZE 2048 /* 1MB */ -#define SNAPSHOT_CHUNK_BUFFER_SIZE 128 /* copy buffer */ - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,9) -#define min(a,b) (((a)<(b))?(a):(b)) -#endif - -/** - * struct snapshot_metadata - * - * @signature: 0 : EVMS_SNAPSHOT_SIGNATURE - * @CRC: 4 : - * @version: 8 : Major, minor, patchlevel - * @flags: 20 : EVMS_SNAPSHOT_* - * @original_volume: 24 : Name of volume being snapshotted. - * @original_size: 152: In sectors. - * @lba_of_COW_table: 160: - * @lba_of_first_chunk: 168: - * @chunk_size: 176: In sectors - * @total_chunks: 180: - * - * On-disk metadata sector for EVMS Snapshot feature. - */ -struct snapshot_metadata { - u32 signature; - u32 CRC; - struct evms_version version; - u32 flags; - u8 original_volume[128]; - u64 original_size; - u64 lba_of_COW_table; - u64 lba_of_first_chunk; - u32 chunk_size; - u32 total_chunks; -}; - -/** - * struct snapshot_hash_entry - * - * @org_chunk: Chunk number, not LBA. - * @snap_chunk: Chunk_number, not LBA. - * @chunk_state: SNAP_CHUNK_* - * @chunk_state_lock: Protects access to chunk_state - * @snap_io: In async mode, the control-block for copying this chunk. - * @next - * @prev - * - * Entries in the snapshot remapping hash-table. - */ -struct snapshot_hash_entry { - u64 org_chunk; - u64 snap_chunk; - u32 chunk_state; - spinlock_t chunk_state_lock; - struct async_snap_io * snap_io; - struct snapshot_hash_entry * next; - struct snapshot_hash_entry * prev; -}; - -/** - * struct snapshot_volume - * - * @logical_node: Node below us. - * @exported_node: Node above us. - * @snapshot_org: The volume being snapshotted. - * @snapshot_next: List of volumes snapshotting this original. - * @snap_semaphore: On snapshots: protects access to the snapshot - * volume structure. - * On originals: protects the list of snapshots. - * @snapshot_map: Hash table of remapped chunks. - * @free_hash_list: List of pre-allocated hash entries. - * @chunk_size: In sectors. - * @chunk_shift: Shift value for chunk_size. - * @num_chunks: In this volume. - * @next_cow_entry: Index into current COW table sector. - * @current_cow_sector: Logical sector of current COW table. - * @next_free_chunk: Index of next free chunk (not LBA!). - * @hash_table_size: Size of the hash table for the remap. - * @flags: Status flags. EVMS_SNAPSHOT_* - * @cow_table: One sector's worth of COW tables. - * @async_io_thread: Thread for async copy-on-writes. Only on originals. - * @chunk_write_list: Lists and locks attached to the original. - * @chunk_write_list_lock: - * @org_pending_io_list: - * @org_pending_io_list_lock: - * @snap_pending_io_list: - * @snap_pending_io_list_lock: - * @cow_table_write_list: List and lock attached to the snapshot. - * @cow_table_write_list_lock: - * @rollback_thread: Thread for rollbacks. Only on snapshots. - * @chunk_data_buffer: Buffer for copying data during rollbacks. - * - * Private data for one snapshot volume or one original volume. - */ -struct snapshot_volume { - struct evms_logical_node * logical_node; - struct evms_logical_node * exported_node; - struct snapshot_volume * snapshot_org; - struct snapshot_volume * snapshot_next; - struct rw_semaphore snap_semaphore; - struct snapshot_hash_entry ** snapshot_map; - struct snapshot_hash_entry * free_hash_list; - u32 chunk_size; - u32 chunk_shift; - u32 num_chunks; - u32 next_cow_entry; - u64 current_cow_sector; - u32 next_free_chunk; - u32 hash_table_size; - u32 flags; - u64 cow_table[64]; - struct evms_thread * async_io_thread; - struct list_head chunk_write_list; - spinlock_t chunk_write_list_lock; - struct list_head org_pending_io_list; - spinlock_t org_pending_io_list_lock; - struct list_head snap_pending_io_list; - spinlock_t snap_pending_io_list_lock; - struct list_head cow_table_write_list; - spinlock_t cow_table_write_list_lock; -#ifdef SNAPSHOT_DEBUG - atomic_t cow_table_writes; - atomic_t cow_table_overlaps; -#endif - struct evms_thread * rollback_thread; - u8 * chunk_data_buffer; -}; - -/** - * struct snap_io_buffer - * - * @bh: A pointer to the embedded buffer_head at the end. - * @buffer_private: Private data associated with this buffer. - * @buffer_next: List of snap_io_buffer's for one async_[org|snap]_io. - * @copy_next: List of buffers that will write the data that this - * buffer just read. - * @chunk_write_list: List for the thread to use to drive writes to the - * snapshot as part of a copy. - * @_bh: An embedded buffer_head. The b_private field will - * always point back at the snap_io_buffer. - * - * A wrapper around a buffer_head, to allow for the buffer to exist on the - * variety of lists used by snapshotting. - */ -struct snap_io_buffer { - struct buffer_head * bh; - void * buffer_private; - struct snap_io_buffer * buffer_next; - struct snap_io_buffer * copy_next; - struct list_head chunk_write_list; - struct buffer_head _bh; -}; - -#define CHUNK_WRITE_ENTRY(lh) list_entry((lh), \ - struct snap_io_buffer, \ - chunk_write_list) - -/** - * struct async_snap_io - * - * @snap_volume: Snapshot volume that this chunk belongs to. - * @hash_table_entry: Hash table entry that this chunk belongs to. - * @org_io: Parent async I/O structure that contains list - * of read buffers. - * @pending_reads: List of pending read requests to the snapshot. - * @pending_writes: List of pending write requests to the snapshot. - * @copy_buffers: List of buffers to use to write this chunk to the - * snapshot. - * @cow_table_buffer: Buffer for writing the cow table to disk. - * @snap_io_list_next: List of async_snap_io's for the parent async_org_io. - * @snap_pending_io_list: List of async_snap_io's to be processed by the thread. - * For each of these, the thread will process the contents - * of the pending_[reads|writes] lists. - * @cow_write_list: List of cow table writes to be processed by the thread. - * For each of these, the thread will process the - * cow_table_buffer. - * @write_count: Number of buffers remaining to write for this chunk - * (equal to the length of the copy_buffers list). - * @dev: Copy of the b_rdev field for this volume. Needed in - * order to tell EVMS about pending I/Os. - * - * Control structure that handles writing a single chunk to the snapshot during - * a copy-on-write. - */ -struct async_snap_io { - struct snapshot_volume * snap_volume; - struct snapshot_hash_entry * hash_table_entry; - struct async_org_io * org_io; - struct buffer_head * pending_reads; - struct buffer_head * pending_writes; - struct snap_io_buffer * copy_buffers; - struct snap_io_buffer * cow_table_buffer; - struct async_snap_io * snap_io_list_next; - struct list_head snap_pending_io_list; - struct list_head cow_write_list; - atomic_t write_count; - kdev_t dev; -}; - -#define SNAP_PENDING_IO_ENTRY(lh) list_entry((lh), \ - struct async_snap_io, \ - snap_pending_io_list) -#define COW_WRITE_ENTRY(lh) list_entry((lh), \ - struct async_snap_io, \ - cow_write_list) - -/** - * struct async_org_io - * - * @org_volume: Original volume that this chunk belongs to. - * @pending_writes: List of pending write requests to the original. - * @pending_writes_lock:Protect the pending_writes list. - * @copy_buffers: List ob buffers to use to read this chunk from the - * original. - * @snap_io_list: List of async_snap_io's that will write this chunk to - * the snapshots. - * @org_pending_io_list:List of async_org_io's to be processed by the thread. - * For each of these, the thread will process the contents - * of the pending_writes list. - * @copy_count: Number of snapshots remaining to write this chunk. - * @ref_count: = copy_count + 1. Needed to determine when the entire - * async I/O structure can be deallocated. - * @dev: Copy of the b_rdev field for this volume. Needed in - * order to tell EVMS about pending I/Os. - */ -struct async_org_io { - struct snapshot_volume * org_volume; - struct buffer_head * pending_writes; - spinlock_t pending_writes_lock; - struct snap_io_buffer * copy_buffers; - struct async_snap_io * snap_io_list; - struct list_head org_pending_io_list; - atomic_t copy_count; - atomic_t ref_count; -#ifdef SNAPSHOT_DEBUG - struct async_org_io * debug_next_org_io; -#endif - kdev_t dev; -}; - -#define ORG_PENDING_IO_ENTRY(lh) list_entry((lh), \ - struct async_org_io, \ - org_pending_io_list) - -/* Debugging code */ -#ifdef SNAPSHOT_DEBUG - -#define DEBUG_CHECK_SNAP_IO(async_snap_io) \ - do { \ - if ( (async_snap_io)->pending_reads || \ - (async_snap_io)->pending_writes ) { \ - BUG(); \ - } \ - } while (0); - -#define DEBUG_REMOVE_ORG_IO_FROM_LIST(async_org_io) \ - do { \ - struct async_org_io ** p_org_io; \ - unsigned long flags; \ - if ((async_org_io)->pending_writes) { \ - BUG(); \ - } \ - spin_lock_irqsave(&debug_async_org_io_list_lock, flags); \ - for ( p_org_io = &debug_async_org_io_list; *p_org_io; \ - p_org_io = &(*p_org_io)->debug_next_org_io ) { \ - if ( *p_org_io == (async_org_io) ) { \ - *p_org_io = (async_org_io)->debug_next_org_io; \ - break; \ - } \ - } \ - (async_org_io)->debug_next_org_io = NULL; \ - spin_unlock_irqrestore(&debug_async_org_io_list_lock, flags); \ - } while (0); - -#define DEBUG_ADD_ORG_IO_TO_LIST(async_org_io) \ - do { \ - unsigned long flags; \ - spin_lock_irqsave(&debug_async_org_io_list_lock, flags); \ - (async_org_io)->debug_next_org_io = debug_async_org_io_list; \ - debug_async_org_io_list = (async_org_io); \ - spin_unlock_irqrestore(&debug_async_org_io_list_lock, flags); \ - } while (0); - -#define DEBUG_INC_COW_TABLE_OVERLAPS(snap_volume) \ - atomic_inc(&(snap_volume)->cow_table_overlaps) - -#define DEBUG_INC_COW_TABLE_WRITES(snap_volume) \ - atomic_inc(&(snap_volume)->cow_table_writes) - -#else /* SNAPSHOT_DEBUG */ - -#define DEBUG_CHECK_SNAP_IO(async_snap_io) -#define DEBUG_REMOVE_ORG_IO_FROM_LIST(async_org_io) -#define DEBUG_ADD_ORG_IO_TO_LIST(async_org_io) -#define DEBUG_INC_COW_TABLE_OVERLAPS(snap_volume) -#define DEBUG_INC_COW_TABLE_WRITES(snap_volume) - -#endif /* SNAPSHOT_DEBUG */ - -#endif /* __EVMS_SNAPSHOT_INCLUDED__ */ - diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_xor.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_xor.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/evms_xor.h 2003-05-03 03:22:41.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/evms_xor.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ -#ifndef _XOR_H -#define _XOR_H - -#include - -#define MAX_XOR_BLOCKS 5 - -extern void evms_md_xor_block(unsigned int count, struct buffer_head **bh_ptr); - -struct xor_block_template { - struct xor_block_template *next; - const char *name; - int speed; - void (*do_2)(unsigned long, unsigned long *, unsigned long *); - void (*do_3)(unsigned long, unsigned long *, unsigned long *, - unsigned long *); - void (*do_4)(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); - void (*do_5)(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); -}; - -#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/ldev_mgr.h linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/ldev_mgr.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/evms/ldev_mgr.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/evms/ldev_mgr.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,46 +0,0 @@ - -/* -*- linux-c -*- */ -/* - * - * Copyright (c) International Business Machines Corp., 2000 - * - * 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 - */ - -/* linux/driver/evms/ldev_mgr.h - * - * EVMS - Local Device (Hard Drive) Manager - * - */ - -/* plugin feature ID */ -#define EVMS_LOCAL_DEVICE_MANAGER_ID 1 - -/* plugin ioctl feature command defines */ -#define LDEV_MGR_BROADCAST_IOCTL_CMD 1 - -/** - * struct ldev_plugin_ioctl - ldev mgr direct ioctl packet definition - * @disk_handle: handle identifying target disk - * @cmd: ioctl cmd - * @arg: ioctl argument - * - * local device manager direct ioctl packet definition - **/ -struct ldev_plugin_ioctl { - u64 disk_handle; - u32 cmd; - ulong arg; -}; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/fs.h linux-2.4.20-wolk4.7-fullkernel/include/linux/fs.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/fs.h 2003-08-04 23:06:40.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/fs.h 2003-08-17 21:31:36.000000000 +0200 @@ -797,7 +797,7 @@ extern time_t lease_get_mtime(struct ino extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); extern void send_sigio(struct fown_struct *fown, int fd, int band); -extern void steal_locks(fl_owner_t from, fl_owner_t to); +extern void steal_locks(fl_owner_t from); struct fasync_struct { int magic; @@ -1549,6 +1549,7 @@ extern struct dentry * lookup_hash(struc #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd) extern void inode_init_once(struct inode *); +extern void _inode_init_once(struct inode *); extern void iput(struct inode *); extern void refile_inode(struct inode *inode); @@ -1731,7 +1732,6 @@ unsigned long generate_cluster(kdev_t, i unsigned long generate_cluster_swab32(kdev_t, int b[], int); extern kdev_t ROOT_DEV; extern char root_device_name[]; -extern void get_root_device_name( char * root_name ); #ifdef CONFIG_BADFS_FS /* fs/badfs/inode.c - used by forced umount */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/grmsg.h linux-2.4.20-wolk4.7-fullkernel/include/linux/grmsg.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/grmsg.h 2003-05-03 02:11:53.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/grmsg.h 2003-08-17 21:28:32.000000000 +0200 @@ -152,15 +152,15 @@ #define GR_MMAP_ACL_FLD "denied mmap execs" #define GR_MPROTECT_ACL_MSG "%s executable mprotect of %.950s by " DEFAULTSECMSG #define GR_MPROTECT_ACL_FLD "denied mprotect execs" -#define GR_SOCK_MSG "attempted socket(%d,%d,%d) by " DEFAULTSECMSG +#define GR_SOCK_MSG "attempted socket(%.16s,%.16s,%.16s) by " DEFAULTSECMSG #define GR_SOCK_FLD "attempted sockets" #define GR_BIND_MSG "attempted bind() by " DEFAULTSECMSG #define GR_BIND_FLD "attempted binds" #define GR_CONNECT_MSG "attempted connect by " DEFAULTSECMSG #define GR_CONNECT_FLD "attempted connects" -#define GR_BIND_ACL_MSG "attempted bind to %u.%u.%u.%u port %u sock type %u protocol %u by " DEFAULTSECMSG +#define GR_BIND_ACL_MSG "attempted bind to %u.%u.%u.%u port %u sock type %.16s protocol %.16s by " DEFAULTSECMSG #define GR_BIND_ACL_FLD "attempted binds" -#define GR_CONNECT_ACL_MSG "attempted connect to %u.%u.%u.%u port %u sock type %u protocol %u by " DEFAULTSECMSG +#define GR_CONNECT_ACL_MSG "attempted connect to %u.%u.%u.%u port %u sock type %.16s protocol %.16s by " DEFAULTSECMSG #define GR_CONNECT_ACL_FLD "attempted connects" #define GR_IP_LEARN_MSG "LEARN:%d:%lu:%u.%u.%u.%u:%u:%u:%u:%u" #define GR_EXEC_CHROOT_MSG "exec of %.980s within chroot by process " DEFAULTSECMSG diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-8xx.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-8xx.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-8xx.h 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-8xx.h 2003-08-17 21:26:58.000000000 +0200 @@ -16,12 +16,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-algo-8xx.h,v 1.3 2002/06/12 02:29:54 mds Exp $ */ +/* $Id: i2c-algo-8xx.h,v 1.3.2.2 2003/01/21 10:00:19 kmalkki Exp $ */ -#ifndef I2C_ALGO_8XX_H -#define I2C_ALGO_8XX_H 1 - -#include +#ifndef _LINUX_I2C_ALGO_8XX_H +#define _LINUX_I2C_ALGO_8XX_H struct i2c_algo_8xx_data { uint dp_addr; @@ -40,4 +38,4 @@ struct i2c_algo_8xx_data { int i2c_8xx_add_bus(struct i2c_adapter *); int i2c_8xx_del_bus(struct i2c_adapter *); -#endif /* I2C_ALGO_8XX_H */ +#endif /* _LINUX_I2C_ALGO_8XX_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-bit.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-bit.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-bit.h 2003-05-13 12:27:27.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-bit.h 2003-08-17 21:26:58.000000000 +0200 @@ -21,12 +21,10 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-algo-bit.h,v 1.9 2002/11/26 00:10:52 mds Exp $ */ +/* $Id: i2c-algo-bit.h,v 1.9.2.1 2003/01/21 10:00:19 kmalkki Exp $ */ -#ifndef I2C_ALGO_BIT_H -#define I2C_ALGO_BIT_H 1 - -#include +#ifndef _LINUX_I2C_ALGO_BIT_H +#define _LINUX_I2C_ALGO_BIT_H /* --- Defines for bit-adapters --------------------------------------- */ /* @@ -53,4 +51,4 @@ struct i2c_algo_bit_data { int i2c_bit_add_bus(struct i2c_adapter *); int i2c_bit_del_bus(struct i2c_adapter *); -#endif /* I2C_ALGO_BIT_H */ +#endif /* _LINUX_I2C_ALGO_BIT_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-ibm_ocp.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-ibm_ocp.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-ibm_ocp.h 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-ibm_ocp.h 2003-08-17 21:26:58.000000000 +0200 @@ -25,11 +25,8 @@ /* Modifications by MontaVista Software, August 2000 Changes made to support the IIC peripheral on the IBM PPC 405 */ -#ifndef I2C_ALGO_IIC_H -#define I2C_ALGO_IIC_H 1 - -/* --- Defines for pcf-adapters --------------------------------------- */ -#include +#ifndef _LINUX_I2C_ALGO_IBM_OCP_H +#define _LINUX_I2C_ALGO_IBM_OCP_H struct i2c_algo_iic_data { struct iic_regs *data; /* private data for lolevel routines */ @@ -52,4 +49,4 @@ struct i2c_algo_iic_data { int i2c_ocp_add_bus(struct i2c_adapter *); int i2c_ocp_del_bus(struct i2c_adapter *); -#endif /* I2C_ALGO_IIC_H */ +#endif /* _LINUX_I2C_ALGO_IBM_OCP_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-pcf.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-pcf.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-algo-pcf.h 2003-05-13 12:27:30.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-algo-pcf.h 2003-08-17 21:26:58.000000000 +0200 @@ -22,13 +22,12 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-algo-pcf.h,v 1.7 2000/02/27 23:02:45 frodo Exp $ */ +/* $Id: i2c-algo-pcf.h,v 1.7.2.1 2003/01/21 10:00:19 kmalkki Exp $ */ -#ifndef I2C_ALGO_PCF_H -#define I2C_ALGO_PCF_H 1 +#ifndef _LINUX_I2C_ALGO_PCF_H +#define _LINUX_I2C_ALGO_PCF_H -/* --- Defines for pcf-adapters --------------------------------------- */ -#include +#include struct i2c_algo_pcf_data { void *data; /* private data for lolevel routines */ @@ -49,4 +48,4 @@ struct i2c_algo_pcf_data { int i2c_pcf_add_bus(struct i2c_adapter *); int i2c_pcf_del_bus(struct i2c_adapter *); -#endif /* I2C_ALGO_PCF_H */ +#endif /* _LINUX_I2C_ALGO_PCF_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-dev.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-dev.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-dev.h 2003-05-13 12:27:26.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-dev.h 2003-08-17 21:26:58.000000000 +0200 @@ -19,200 +19,32 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: i2c-dev.h,v 1.11 2002/07/07 15:42:47 mds Exp $ */ - -#ifndef I2C_DEV_H -#define I2C_DEV_H +/* $Id: i2c-dev.h,v 1.11.2.3 2003/06/13 01:20:31 mds Exp $ */ +#ifndef _LINUX_I2C_DEV_H +#define _LINUX_I2C_DEV_H #include -#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) +#define minor(d) MINOR(d) +#endif /* Some IOCTL commands are defined in */ /* Note: 10-bit addresses are NOT supported! */ /* This is the structure as used in the I2C_SMBUS ioctl call */ struct i2c_smbus_ioctl_data { - char read_write; + __u8 read_write; __u8 command; - int size; + __u32 size; union i2c_smbus_data *data; }; /* This is the structure as used in the I2C_RDWR ioctl call */ struct i2c_rdwr_ioctl_data { struct i2c_msg *msgs; /* pointers to i2c_msgs */ - int nmsgs; /* number of i2c_msgs */ + __u32 nmsgs; /* number of i2c_msgs */ }; -#ifndef __KERNEL__ - -#include - -static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, - int size, union i2c_smbus_data *data) -{ - struct i2c_smbus_ioctl_data args; - - args.read_write = read_write; - args.command = command; - args.size = size; - args.data = data; - return ioctl(file,I2C_SMBUS,&args); -} - - -static inline __s32 i2c_smbus_write_quick(int file, __u8 value) -{ - return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); -} - -static inline __s32 i2c_smbus_read_byte(int file) -{ - union i2c_smbus_data data; - if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -static inline __s32 i2c_smbus_write_byte(int file, __u8 value) -{ - return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, - I2C_SMBUS_BYTE,NULL); -} - -static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) -{ - union i2c_smbus_data data; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_BYTE_DATA,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, - __u8 value) -{ - union i2c_smbus_data data; - data.byte = value; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_BYTE_DATA, &data); -} - -static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) -{ - union i2c_smbus_data data; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_WORD_DATA,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - -static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, - __u16 value) -{ - union i2c_smbus_data data; - data.word = value; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_WORD_DATA, &data); -} - -static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) -{ - union i2c_smbus_data data; - data.word = value; - if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_PROC_CALL,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - - -/* Returns the number of read bytes */ -static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, - __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_BLOCK_DATA, &data); -} - -/* Returns the number of read bytes */ -static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, - __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_I2C_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); -} - -/* Returns the number of read bytes */ -static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_BLOCK_PROC_CALL,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -#endif /* ndef __KERNEL__ */ - -#endif +#endif /* _LINUX_I2C_DEV_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-elektor.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-elektor.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-elektor.h 2001-10-11 17:05:47.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-elektor.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,47 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-97 Simon G. Vogl - 1998-99 Hans Berglund - - 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. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Kyösti Mälkki and even - Frodo Looijaard */ - -/* $Id: i2c-elektor.h,v 1.5 2001/06/05 01:46:33 mds Exp $ */ - -#ifndef I2C_PCF_ELEKTOR_H -#define I2C_PCF_ELEKTOR_H 1 - -/* - * This struct contains the hw-dependent functions of PCF8584 adapters to - * manipulate the registers, and to init any hw-specific features. - * vdovikin: removed: this module in real supports only one device, - * due to missing arguments in some functions, called from the algo-pcf module. - * Sometimes it's need to be rewriten - - * but for now just remove this for simpler reading */ - -/* -struct i2c_pcf_isa { - int pi_base; - int pi_irq; - int pi_clock; - int pi_own; -}; -*/ - -#endif /* PCF_ELEKTOR_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-id.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-id.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-id.h 2003-05-03 01:58:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-id.h 2003-08-17 21:26:58.000000000 +0200 @@ -20,10 +20,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-id.h,v 1.61 2002/12/16 01:27:40 mds Exp $ */ +/* $Id: i2c-id.h,v 1.62.2.5 2003/07/14 11:41:25 khali Exp $ */ + +#ifndef LINUX_I2C_ID_H +#define LINUX_I2C_ID_H -#ifndef I2C_ID_H -#define I2C_ID_H /* * This file is part of the i2c-bus package and contains the identifier * values for drivers, adapters and other folk populating these serial @@ -95,7 +96,9 @@ #define I2C_DRIVERID_ADV717x 48 /* ADV 7175/7176 video encoder */ #define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */ #define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ -#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ +#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ +#define I2C_DRIVERID_STM41T00 52 /* real time clock */ +#define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */ @@ -148,6 +151,9 @@ #define I2C_DRIVERID_BMCSENSORS 1036 #define I2C_DRIVERID_FS451 1037 #define I2C_DRIVERID_W83627HF 1038 +#define I2C_DRIVERID_LM85 1039 +#define I2C_DRIVERID_LM83 1040 +#define I2C_DRIVERID_SAA1064 1041 /* * ---- Adapter types ---------------------------------------------------- @@ -169,11 +175,13 @@ #define I2C_ALGO_MPC824X 0x0a0000 /* Motorola 8240 / 8245 */ #define I2C_ALGO_IPMI 0x0b0000 /* IPMI dummy adapter */ #define I2C_ALGO_IPMB 0x0c0000 /* IPMB adapter */ +#define I2C_ALGO_MPC107 0x0d0000 #define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */ #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ +#define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -207,6 +215,11 @@ #define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */ #define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */ #define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ +#define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface (ARM) */ +#define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */ +#define I2C_HW_B_IXP2000 0x16 /* GPIO on IXP2000 systems */ +#define I2C_HW_B_IXP425 0x17 /* GPIO on IXP425 systems */ +#define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x00 /* Parallel port interface */ @@ -228,6 +241,8 @@ /* --- PowerPC on-chip adapters */ #define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ +/* --- XSCALE on-chip adapters */ +#define I2C_HW_IOP321 0x00 /* --- SMBus only adapters */ #define I2C_HW_SMBUS_PIIX4 0x00 @@ -242,6 +257,7 @@ #define I2C_HW_SMBUS_SIS645 0x09 #define I2C_HW_SMBUS_AMD8111 0x0a #define I2C_HW_SMBUS_SCX200 0x0b +#define I2C_HW_SMBUS_NFORCE2 0x0c /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x00 @@ -252,4 +268,7 @@ /* --- IPMB adapter */ #define I2C_HW_IPMB 0x00 -#endif /* I2C_ID_H */ +/* --- MCP107 adapter */ +#define I2C_HW_MPC107 0x00 + +#endif /* LINUX_I2C_ID_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-pcf8584.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-pcf8584.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-pcf8584.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-pcf8584.h 2003-08-17 21:26:58.000000000 +0200 @@ -0,0 +1,78 @@ +/* -------------------------------------------------------------------- */ +/* i2c-pcf8584.h: PCF 8584 global defines */ +/* -------------------------------------------------------------------- */ +/* Copyright (C) 1996 Simon G. Vogl + 1999 Hans Berglund + + 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. */ +/* -------------------------------------------------------------------- */ + +/* With some changes from Frodo Looijaard */ + +/* $Id: i2c-pcf8584.h,v 1.4.2.1 2003/01/21 10:00:19 kmalkki Exp $ */ + +#ifndef _LINUX_I2C_PCF8584_H +#define _LINUX_I2C_PCF8584_H + +/* ----- Control register bits ---------------------------------------- */ +#define I2C_PCF_PIN 0x80 +#define I2C_PCF_ESO 0x40 +#define I2C_PCF_ES1 0x20 +#define I2C_PCF_ES2 0x10 +#define I2C_PCF_ENI 0x08 +#define I2C_PCF_STA 0x04 +#define I2C_PCF_STO 0x02 +#define I2C_PCF_ACK 0x01 + +#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) +#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) + +/* ----- Status register bits ----------------------------------------- */ +/*#define I2C_PCF_PIN 0x80 as above*/ + +#define I2C_PCF_INI 0x40 /* 1 if not initialized */ +#define I2C_PCF_STS 0x20 +#define I2C_PCF_BER 0x10 +#define I2C_PCF_AD0 0x08 +#define I2C_PCF_LRB 0x08 +#define I2C_PCF_AAS 0x04 +#define I2C_PCF_LAB 0x02 +#define I2C_PCF_BB 0x01 + +/* ----- Chip clock frequencies --------------------------------------- */ +#define I2C_PCF_CLK3 0x00 +#define I2C_PCF_CLK443 0x10 +#define I2C_PCF_CLK6 0x14 +#define I2C_PCF_CLK 0x18 +#define I2C_PCF_CLK12 0x1c + +/* ----- transmission frequencies ------------------------------------- */ +#define I2C_PCF_TRNS90 0x00 /* 90 kHz */ +#define I2C_PCF_TRNS45 0x01 /* 45 kHz */ +#define I2C_PCF_TRNS11 0x02 /* 11 kHz */ +#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */ + + +/* ----- Access to internal registers according to ES1,ES2 ------------ */ +/* they are mapped to the data port ( a0 = 0 ) */ +/* available when ESO == 0 : */ + +#define I2C_PCF_OWNADR 0 +#define I2C_PCF_INTREG I2C_PCF_ES2 +#define I2C_PCF_CLKREG I2C_PCF_ES1 + +#endif /* _LINUX_I2C_PCF8584_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-proc.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-proc.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c-proc.h 2003-05-13 12:27:33.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c-proc.h 2003-08-17 21:26:58.000000000 +0200 @@ -19,14 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef SENSORS_SENSORS_H -#define SENSORS_SENSORS_H +#ifndef _LINUX_I2C_PROC_H +#define _LINUX_I2C_PROC_H -#ifdef __KERNEL__ - -/* Next two must be included before sysctl.h can be included, in 2.0 kernels */ -#include -#include #include /* The type of callback functions used in sensors_{proc,sysctl}_real */ @@ -56,18 +51,10 @@ typedef void (*i2c_real_callback) (struc found. In all cases, client points to the client we wish to interact with, and ctl_name is the SYSCTL id of the file we are accessing. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) -extern int i2c_sysctl_real(ctl_table * table, int *name, unsigned nlen, - void *oldval, size_t * oldlenp, - void *newval, size_t newlen, - void **context); -#else extern int i2c_sysctl_real(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context); -#endif /* 2.2.19+ */ extern int i2c_proc_real(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp); @@ -82,8 +69,7 @@ extern int i2c_proc_real(ctl_table * ctl these functions must be updated! */ extern int i2c_register_entry(struct i2c_client *client, const char *prefix, - ctl_table * ctl_template, - struct module *controlling_mod); + ctl_table * ctl_template); extern void i2c_deregister_entry(int id); @@ -396,7 +382,7 @@ extern int i2c_detect(struct i2c_adapter /* This macro is used to scale user-input to sensible values in almost all chip drivers. */ -extern inline int SENSORS_LIMIT(long value, long low, long high) +static inline int SENSORS_LIMIT(long value, long low, long high) { if (value < low) return low; @@ -406,8 +392,6 @@ extern inline int SENSORS_LIMIT(long val return value; } -#endif /* def __KERNEL__ */ - /* The maximum length of the prefix */ #define SENSORS_PREFIX_MAX 20 @@ -426,5 +410,5 @@ struct i2c_chips_data { char name[SENSORS_PREFIX_MAX + 13]; }; -#endif /* def SENSORS_SENSORS_H */ +#endif /* def _LINUX_I2C_PROC_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c.h linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/i2c.h 2003-05-13 12:27:25.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/i2c.h 2003-08-17 21:26:58.000000000 +0200 @@ -23,38 +23,25 @@ /* With some changes from Kyösti Mälkki and Frodo Looijaard */ -/* $Id: i2c.h,v 1.65 2002/12/15 22:25:34 kmalkki Exp $ */ +/* $Id: i2c.h,v 1.66.2.7 2003/07/15 00:15:09 phil Exp $ */ -#ifndef I2C_H -#define I2C_H +#ifndef _LINUX_I2C_H +#define _LINUX_I2C_H -#define I2C_DATE "20021208" -#define I2C_VERSION "2.7.0" +#define I2C_DATE "20030714" +#define I2C_VERSION "2.8.0" -#include /* id values of adapters et. al. */ +#include #include - - -struct i2c_msg; - - -#ifdef __KERNEL__ - -/* --- Includes and compatibility declarations ------------------------ */ +#include +#include +#include #include -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +#define MODULE_LICENSE(x) #endif -#include /* for 2.2.xx */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,25) -#include -#else -#include -#endif -#include - /* --- General options ------------------------------------------------ */ #define I2C_ALGO_MAX 4 /* control memory consumption */ @@ -63,6 +50,7 @@ struct i2c_msg; #define I2C_CLIENT_MAX 32 #define I2C_DUMMY_MAX 4 +struct i2c_msg; struct i2c_algorithm; struct i2c_adapter; struct i2c_client; @@ -70,12 +58,6 @@ struct i2c_driver; struct i2c_client_address_data; union i2c_smbus_data; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,1) -#ifndef __exit -#define __exit -#endif -#endif - /* * The master routines are the ones normally used to transmit data to devices * on a bus (or read from them). Apart from two basic transfer functions to @@ -142,6 +124,7 @@ extern s32 i2c_smbus_write_i2c_block_dat */ struct i2c_driver { + struct module *owner; char name[32]; int id; unsigned int flags; /* div., see below */ @@ -165,18 +148,6 @@ struct i2c_driver { * with the device. */ int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); - - /* These two are mainly used for bookkeeping & dynamic unloading of - * kernel modules. inc_use tells the driver that a client is being - * used by another module & that it should increase its ref. counter. - * dec_use is the inverse operation. - * NB: Make sure you have no circular dependencies, or else you get a - * deadlock when trying to unload the modules. - * You should use the i2c_{inc,dec}_use_client functions instead of - * calling this function directly. - */ - void (*inc_use)(struct i2c_client *client); - void (*dec_use)(struct i2c_client *client); }; /* @@ -209,6 +180,7 @@ struct i2c_client { * to name two of the most common. */ struct i2c_algorithm { + struct module *owner; /* future use --km */ char name[32]; /* textual description */ unsigned int id; @@ -233,25 +205,18 @@ struct i2c_algorithm { u32 (*functionality) (struct i2c_adapter *); }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29) -struct proc_dir_entry; -#endif - /* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. */ struct i2c_adapter { + struct module *owner; char name[32]; /* some useful name to identify the adapter */ unsigned int id;/* == is algo->id | hwdep.struct->id, */ /* for registered values see below */ struct i2c_algorithm *algo;/* the algorithm to access the bus */ void *algo_data; - /* --- These may be NULL, but should increase the module use count */ - void (*inc_use)(struct i2c_adapter *); - void (*dec_use)(struct i2c_adapter *); - /* --- administration stuff. */ int (*client_register)(struct i2c_client *); int (*client_unregister)(struct i2c_client *); @@ -262,11 +227,11 @@ struct i2c_adapter { /* and can be set via the i2c_ioctl call */ /* data fields that are valid for all devices */ - struct semaphore lock; + struct semaphore bus; + struct semaphore list; unsigned int flags;/* flags specifying div. data */ struct i2c_client *clients[I2C_CLIENT_MAX]; - int client_count; int timeout; int retries; @@ -274,9 +239,6 @@ struct i2c_adapter { #ifdef CONFIG_PROC_FS /* No need to set this when you initialize the adapter */ int inode; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29) - struct proc_dir_entry *proc_entry; -#endif #endif /* def CONFIG_PROC_FS */ }; @@ -329,12 +291,6 @@ extern int i2c_del_driver(struct i2c_dri extern int i2c_attach_client(struct i2c_client *); extern int i2c_detach_client(struct i2c_client *); -/* Only call these if you grab a resource that makes unloading the - client and the adapter it is on completely impossible. Like when a - /proc directory is entered. */ -extern void i2c_inc_use_client(struct i2c_client *); -extern void i2c_dec_use_client(struct i2c_client *); - /* New function: This is to get an i2c_client-struct for controlling the client either by using i2c_control-function or having the client-module export functions that can be used with the i2c_client @@ -368,6 +324,15 @@ extern int i2c_probe(struct i2c_adapter struct i2c_client_address_data *address_data, i2c_client_found_addr_proc *found_proc); +static inline int i2c_client_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + if (client->driver && client->driver->command) + return client->driver->command(client, cmd, arg); + else + return -EINVAL; +} + /* An ioctl like call to set div. parameters of the adapter. */ extern int i2c_control(struct i2c_client *,unsigned int, unsigned long); @@ -385,22 +350,20 @@ extern u32 i2c_get_functionality (struct /* Return 1 if adapter supports everything we need, 0 if not. */ extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func); -#endif /* __KERNEL__ */ - /* * I2C Message - used for pure i2c transaction, also from /dev interface */ struct i2c_msg { __u16 addr; /* slave address */ - unsigned short flags; + __u16 flags; #define I2C_M_TEN 0x10 /* we have a ten bit chip address */ #define I2C_M_RD 0x01 #define I2C_M_NOSTART 0x4000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800 - short len; /* msg length */ - char *buf; /* pointer to msg data */ + __u16 len; /* msg length */ + __u8 *buf; /* pointer to msg data */ int err; short done; }; @@ -538,16 +501,6 @@ union i2c_smbus_data { #define I2C_MAJOR 89 /* Device major number */ -#ifdef __KERNEL__ - -# ifndef NULL -# define NULL ( (void *) 0 ) -# endif - -# ifndef ENODEV -# include -# endif - /* These defines are used for probing i2c client addresses */ /* Default fill of many variables */ #define I2C_CLIENT_DEFAULTS {I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \ @@ -609,5 +562,4 @@ union i2c_smbus_data { #define i2c_is_isa_adapter(adapptr) \ ((adapptr)->algo->id == I2C_ALGO_ISA) -#endif /* def __KERNEL__ */ -#endif /* I2C_H */ +#endif /* _LINUX_I2C_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/if_arp.h linux-2.4.20-wolk4.7-fullkernel/include/linux/if_arp.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/if_arp.h 2003-05-13 12:20:38.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/if_arp.h 2003-08-17 21:31:40.000000000 +0200 @@ -40,6 +40,7 @@ #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ #define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ #define ARPHRD_EUI64 27 /* EUI-64 */ +#define ARPHRD_INFINIBAND 32 /* InfiniBand */ /* Dummy types for non ARP hardware */ #define ARPHRD_SLIP 256 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/kdb.h linux-2.4.20-wolk4.7-fullkernel/include/linux/kdb.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/kdb.h 2003-05-13 12:18:56.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/kdb.h 2003-08-17 21:26:24.000000000 +0200 @@ -38,10 +38,11 @@ #include #include +#include #include #define KDB_MAJOR_VERSION 4 -#define KDB_MINOR_VERSION 2 +#define KDB_MINOR_VERSION 3 #define KDB_TEST_VERSION "" /* @@ -91,14 +92,11 @@ extern struct kdb_serial { */ extern const char *kdb_diemsg; - /* - * 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 -#define KDB_FLAG_CATASTROPHIC 0x00000002 /* A catastrophic event has occurred */ -#define KDB_FLAG_CMD_INTERRUPT 0x00000004 /* Previous command was interrupted */ +#define KDB_FLAG_EARLYKDB (1 << 0) /* set from boot parameter kdb=early */ +#define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */ +#define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */ +#define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */ +#define KDB_FLAG_ONLY_DO_DUMP (1 << 4) /* Only do a dump, used when kdb is off */ /* * Internal debug flags diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/kernel.h linux-2.4.20-wolk4.7-fullkernel/include/linux/kernel.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/kernel.h 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/kernel.h 2003-08-17 21:31:38.000000000 +0200 @@ -5,6 +5,8 @@ * 'kernel.h' contains some often-used function prototypes etc */ +#define O1_SCHEDULER + #ifdef __KERNEL__ #include diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/major.h linux-2.4.20-wolk4.7-fullkernel/include/linux/major.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/major.h 2003-05-03 02:00:20.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/major.h 2003-08-17 21:27:39.000000000 +0200 @@ -146,8 +146,6 @@ #define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ -#define EVMS_MAJOR 117 /* Enterprise Volume Management System */ - #define RTF_MAJOR 150 #define RAW_MAJOR 162 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/miscdevice.h linux-2.4.20-wolk4.7-fullkernel/include/linux/miscdevice.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/miscdevice.h 2003-05-13 12:19:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/miscdevice.h 2003-08-17 21:28:14.000000000 +0200 @@ -3,39 +3,40 @@ #include -#define BUSMOUSE_MINOR 0 -#define PSMOUSE_MINOR 1 -#define MS_BUSMOUSE_MINOR 2 -#define ATIXL_BUSMOUSE_MINOR 3 -#define AMIGAMOUSE_MINOR 4 -#define ATARIMOUSE_MINOR 5 -#define SUN_MOUSE_MINOR 6 -#define APOLLO_MOUSE_MINOR 7 -#define PC110PAD_MINOR 9 -#define ADB_MOUSE_MINOR 10 -#define MK712_MINOR 15 /* MK712 touch screen */ +#define BUSMOUSE_MINOR 0 +#define PSMOUSE_MINOR 1 +#define MS_BUSMOUSE_MINOR 2 +#define ATIXL_BUSMOUSE_MINOR 3 +#define AMIGAMOUSE_MINOR 4 +#define ATARIMOUSE_MINOR 5 +#define SUN_MOUSE_MINOR 6 +#define APOLLO_MOUSE_MINOR 7 +#define PC110PAD_MINOR 9 +#define ADB_MOUSE_MINOR 10 +#define MK712_MINOR 15 /* MK712 touch screen */ #define WATCHDOG_MINOR 130 /* Watchdog timer */ #define TEMP_MINOR 131 /* Temperature Sensor */ -#define RTC_MINOR 135 +#define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ -#define SUN_OPENPROM_MINOR 139 -#define NVRAM_MINOR 144 -#define I2O_MINOR 166 +#define SUN_OPENPROM_MINOR 139 +#define DMAPI_MINOR 140 /* DMAPI */ +#define NVRAM_MINOR 144 +#define I2O_MINOR 166 #define MICROCODE_MINOR 184 -#define DEADMAN_MINOR 185 -#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ -#define MPT_MINOR 220 -#define MISC_DYNAMIC_MINOR 255 - -#define SGI_GRAPHICS_MINOR 146 -#define SGI_OPENGL_MINOR 147 -#define SGI_GFX_MINOR 148 -#define SGI_STREAMS_MOUSE 149 -#define SGI_STREAMS_KEYBOARD 150 +#define DEADMAN_MINOR 185 +#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ +#define MPT_MINOR 220 +#define MISC_DYNAMIC_MINOR 255 + +#define SGI_GRAPHICS_MINOR 146 +#define SGI_OPENGL_MINOR 147 +#define SGI_GFX_MINOR 148 +#define SGI_STREAMS_MOUSE 149 +#define SGI_STREAMS_KEYBOARD 150 /* drivers/sgi/char/usema.c */ -#define SGI_USEMACLONE 151 +#define SGI_USEMACLONE 151 -#define TUN_MINOR 200 +#define TUN_MINOR 200 extern int misc_init(void); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/mm.h linux-2.4.20-wolk4.7-fullkernel/include/linux/mm.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/mm.h 2003-08-04 23:06:27.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/mm.h 2003-08-17 21:31:30.000000000 +0200 @@ -135,10 +135,23 @@ struct vm_area_struct { #define VM_MAYNOTWRITE 0x00200000 /* vma cannot be granted VM_WRITE any more */ #endif +#ifdef ARCH_STACK_GROWSUP +#define __VM_STACK_FLAGS 0x00000233 +#else +#define __VM_STACK_FLAGS 0x00000133 +#endif + #if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) -#define VM_STACK_FLAGS (0x00000133 | ((current->flags & (PF_PAX_PAGEEXEC|PF_PAX_SEGMEXEC))?0:VM_EXEC|VM_MAYEXEC)) +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT +#define VM_STACK_FLAGS (__VM_STACK_FLAGS | \ + ((current->flags & PF_PAX_MPROTECT)?0:VM_MAYEXEC) | \ + ((current->flags & (PF_PAX_PAGEEXEC|PF_PAX_SEGMEXEC))?0:VM_EXEC)) +#else +#define VM_STACK_FLAGS (__VM_STACK_FLAGS | VM_MAYEXEC | \ + ((current->flags & (PF_PAX_PAGEEXEC|PF_PAX_SEGMEXEC))?0:VM_EXEC)) +#endif #else -#define VM_STACK_FLAGS 0x00000177 +#define VM_STACK_FLAGS (__VM_STACK_FLAGS | VM_EXEC | VM_MAYEXEC) #endif #define VM_READHINTMASK (VM_SEQ_READ | VM_RAND_READ) @@ -737,8 +750,7 @@ static inline unsigned long do_mmap(stru ) { unsigned long ret_m; - ret_m = do_mmap_pgoff(NULL, ret + SEGMEXEC_TASK_SIZE, -0UL, prot, flag | MAP_MIRROR | MAP_FIXED, ret); + ret_m = do_mmap_pgoff(NULL, ret + SEGMEXEC_TASK_SIZE, 0UL, prot, flag | MAP_MIRROR | MAP_FIXED, ret); if (BAD_ADDR(ret_m)) { do_munmap(current->mm, ret, len); ret = ret_m; @@ -775,7 +787,6 @@ static inline int __can_vma_merge(struct #ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC if ((vma->vm_flags | vm_flags) & VM_MIRROR) return 0; - else #endif if (vma->vm_file == file && vma->vm_flags == vm_flags && diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/mm_inline.h linux-2.4.20-wolk4.7-fullkernel/include/linux/mm_inline.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/mm_inline.h 2003-05-13 12:21:04.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/mm_inline.h 2003-08-17 21:28:11.000000000 +0200 @@ -69,6 +69,7 @@ static inline int page_dirty(struct page * Returns 1 if the page is backed by ram/swap, 0 if the page is * backed by a file in a filesystem on permanent storage. */ +extern int shmem_writepage(struct page *); static inline int page_anon(struct page * page) { /* Pages of an mmap()d file won't trigger this unless they get @@ -83,7 +84,16 @@ static inline int page_anon(struct page if (PageSwapCache(page)) return 1; - /* TODO: ramfs, tmpfs shm segments and ramdisk */ + /* + * Files on tmpfs that are are shared writable mmapped are often + * database shared memory segments, which should receive the same + * priority as anonymous memory. Yes this is ugly. + */ + if (page->mapping && page->mapping->i_mmap_shared && + page->mapping->a_ops->writepage == shmem_writepage) + return 1; + + /* TODO: ramfs and ramdisk */ return 0; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/netdevice.h linux-2.4.20-wolk4.7-fullkernel/include/linux/netdevice.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/netdevice.h 2003-08-04 23:06:40.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/netdevice.h 2003-08-17 21:31:40.000000000 +0200 @@ -65,7 +65,7 @@ struct vlan_group; #endif -#define MAX_ADDR_LEN 8 /* Largest hardware address length */ +#define MAX_ADDR_LEN 32 /* Largest hardware address length */ /* * Compute the worst case header length according to the protocols @@ -479,6 +479,7 @@ extern int register_netdevice(struct ne extern int unregister_netdevice(struct net_device *dev); extern int register_netdevice_notifier(struct notifier_block *nb); extern int unregister_netdevice_notifier(struct notifier_block *nb); +extern int call_netdevice_notifiers(unsigned long val, void *v); extern int dev_new_index(void); extern struct net_device *dev_get_by_index(int ifindex); extern struct net_device *__dev_get_by_index(int ifindex); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/pkt_sched.h linux-2.4.20-wolk4.7-fullkernel/include/linux/pkt_sched.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/pkt_sched.h 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/pkt_sched.h 2003-08-17 21:29:57.000000000 +0200 @@ -374,6 +374,118 @@ enum #define TCA_CBQ_MAX TCA_CBQ_POLICE +/* WRR section */ + +/* Other includes */ +#include + +// A sub weight and of a class +// All numbers are represented as parts of (2^64-1). +struct tc_wrr_class_weight { + __u64 val; // Current value (0 is not valid) + __u64 decr; // Value pr bytes (2^64-1 is not valid) + __u64 incr; // Value pr seconds (2^64-1 is not valid) + __u64 min; // Minimal value (0 is not valid) + __u64 max; // Minimal value (0 is not valid) + + // The time where the above information was correct: + time_t tim; +}; + +// Pakcet send when modifying a class: +struct tc_wrr_class_modf { + // Not-valid values are ignored. + struct tc_wrr_class_weight weight1; + struct tc_wrr_class_weight weight2; +}; + +// Packet returned when quering a class: +struct tc_wrr_class_stats { + char used; // If this is false the information below is invalid + + struct tc_wrr_class_modf class_modf; + + unsigned char addr[ETH_ALEN]; + char usemac; // True if addr is a MAC address, else it is an IP address + // (this value is only for convience, it is always the same + // value as in the qdisc) + int heappos; // Current heap position or 0 if not in heap + __u64 penal_ls; // Penalty value in heap (ls) + __u64 penal_ms; // Penalty value in heap (ms) +}; + +// Qdisc-wide penalty information (boolean values - 2 not valid) +struct tc_wrr_qdisc_weight { + char weight_mode; // 0=No automatic change to weight + // 1=Decrease normally + // 2=Also multiply with number of machines + // 3=Instead multiply with priority divided + // with priority of the other. + // -1=no change +}; + +// Packet send when modifing a qdisc: +struct tc_wrr_qdisc_modf { + // Not-valid values are ignored: + struct tc_wrr_qdisc_weight weight1; + struct tc_wrr_qdisc_weight weight2; +}; + +// Packet send when creating a qdisc: +struct tc_wrr_qdisc_crt { + struct tc_wrr_qdisc_modf qdisc_modf; + + char srcaddr; // 1=lookup source, 0=lookup destination + char usemac; // 1=Classify on MAC addresses, 0=classify on IP + char usemasq; // 1=Classify based on masqgrading - only valid + // if usemac is zero + int bands_max; // Maximal number of bands (i.e.: classes) + int proxy_maxconn; // If differnt from 0 then we support proxy remapping + // of packets. And this is the number of maximal + // concurrent proxy connections. +}; + +// Packet returned when quering a qdisc: +struct tc_wrr_qdisc_stats { + struct tc_wrr_qdisc_crt qdisc_crt; + int proxy_curconn; + int nodes_in_heap; // Current number of bands wanting to send something + int bands_cur; // Current number of bands used (i.e.: MAC/IP addresses seen) + int bands_reused; // Number of times this band has been reused. + int packets_requed; // Number of times packets have been requeued. + __u64 priosum; // Sum of priorities in heap where 1 is 2^32 +}; + +struct tc_wrr_qdisc_modf_std { + // This indicates which of the tc_wrr_qdisc_modf structers this is: + char proxy; // 0=This struct + + // Should we also change a class? + char change_class; + + // Only valid if change_class is false + struct tc_wrr_qdisc_modf qdisc_modf; + + // Only valid if change_class is true: + unsigned char addr[ETH_ALEN]; // Class to change (non-used bytes should be 0) + struct tc_wrr_class_modf class_modf; // The change +}; + +// Used for proxyrempping: +struct tc_wrr_qdisc_modf_proxy { + // This indicates which of the tc_wrr_qdisc_modf structers this is: + char proxy; // 1=This struct + + // This is 1 if the proxyremap information should be reset + char reset; + + // changec is the number of elements in changes. + int changec; + + // This is an array of type ProxyRemapBlock: + long changes[0]; +}; + /* dsmark section */ enum { diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/posix_acl_xattr.h linux-2.4.20-wolk4.7-fullkernel/include/linux/posix_acl_xattr.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/posix_acl_xattr.h 2003-05-03 01:54:00.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/posix_acl_xattr.h 2003-08-17 21:26:20.000000000 +0200 @@ -4,7 +4,6 @@ Extended attribute system call representation of Access Control Lists. Copyright (C) 2000 by Andreas Gruenbacher - Copyright (C) 2002 SGI - Silicon Graphics, Inc */ #ifndef _POSIX_ACL_XATTR_H #define _POSIX_ACL_XATTR_H diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/posix_cap_xattr.h linux-2.4.20-wolk4.7-fullkernel/include/linux/posix_cap_xattr.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/posix_cap_xattr.h 2003-05-03 01:54:00.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/posix_cap_xattr.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,27 +0,0 @@ -/* - File: linux/posix_cap_xattr.h - - Extended attribute representation of capabilities -*/ -#ifndef _POSIX_CAP_XATTR_H -#define _POSIX_CAP_XATTR_H - -#define POSIX_CAP_XATTR "system.posix_capabilities" -#define POSIX_CAP_XATTR_VERSION 0x0001 - -typedef __u64 posix_cap_xattr_value; - -typedef struct { - __u32 c_version; - __u32 c_abiversion; - posix_cap_xattr_value c_effective; - posix_cap_xattr_value c_permitted; - posix_cap_xattr_value c_inheritable; -} posix_cap_xattr; - -static inline size_t posix_cap_xattr_size(void) -{ - return (sizeof(posix_cap_xattr)); -} - -#endif /* _POSIX_CAP_XATTR_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/proc_fs.h linux-2.4.20-wolk4.7-fullkernel/include/linux/proc_fs.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/proc_fs.h 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/proc_fs.h 2003-08-17 21:31:45.000000000 +0200 @@ -24,8 +24,8 @@ enum { /* Finally, the dynamically allocatable proc entries are reserved: */ -#define PROC_DYNAMIC_FIRST 4096 -#define PROC_NDYNAMIC 4096 +#define PROC_DYNAMIC_FIRST 4096 +#define PROC_NDYNAMIC 8192 #define PROC_SUPER_MAGIC 0x9fa0 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/raid/multipath.h linux-2.4.20-wolk4.7-fullkernel/include/linux/raid/multipath.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/raid/multipath.h 2003-05-13 12:29:03.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/raid/multipath.h 2003-08-17 21:30:59.000000000 +0200 @@ -15,6 +15,7 @@ struct multipath_info { int spare; int used_slot; + atomic_t nr_pending; /* number of pending requests */ }; struct multipath_private_data { @@ -63,6 +64,7 @@ struct multipath_bh { struct buffer_head *master_bh; struct buffer_head bh_req; struct multipath_bh *next_mp; /* next for retry or in free list */ + struct multipath_info *multipath; /* allows end_request to easilly dec pending buffer count*/ }; /* bits for multipath_bh.state */ #define MPBH_Uptodate 1 diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/reiserfs_fs.h linux-2.4.20-wolk4.7-fullkernel/include/linux/reiserfs_fs.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/reiserfs_fs.h 2003-05-13 12:34:25.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/reiserfs_fs.h 2003-08-17 21:31:43.000000000 +0200 @@ -873,6 +873,7 @@ struct stat_data_v1 #else #define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL #endif /* CONFIG_SCONTEXTS */ +#define REISERFS_APPEND_FL EXT2_APPEND_FL #define REISERFS_SYNC_FL EXT2_SYNC_FL #define REISERFS_NOATIME_FL EXT2_NOATIME_FL #define REISERFS_NODUMP_FL EXT2_NODUMP_FL @@ -883,7 +884,7 @@ struct stat_data_v1 Note, that is inheritable: mark directory with this and all new files inside will not have tails. - Teodore Tso allocated EXT2_NODUMP_FL (0x00008000) for this. Change + Teodore Tso allocated EXT2_NOTAIL_FL (0x00008000) for this. Change numeric constant to ext2 macro when available. */ #define REISERFS_NOTAIL_FL (0x00008000) /* EXT2_NOTAIL_FL */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/rtnetlink.h linux-2.4.20-wolk4.7-fullkernel/include/linux/rtnetlink.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/rtnetlink.h 2003-05-03 02:00:11.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/rtnetlink.h 2003-08-17 21:31:40.000000000 +0200 @@ -17,6 +17,7 @@ #define RTM_NEWLINK (RTM_BASE+0) #define RTM_DELLINK (RTM_BASE+1) #define RTM_GETLINK (RTM_BASE+2) +#define RTM_SETLINK (RTM_BASE+3) #define RTM_NEWADDR (RTM_BASE+4) #define RTM_DELADDR (RTM_BASE+5) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/sensors.h linux-2.4.20-wolk4.7-fullkernel/include/linux/sensors.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/sensors.h 2003-05-13 12:31:37.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/sensors.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,693 +0,0 @@ -/* - sensors.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - 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. -*/ - -#ifndef SENSORS_NSENSORS_H -#define SENSORS_NSENSORS_H - -#include - -#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM78_SYSCTL_IN1 1001 -#define LM78_SYSCTL_IN2 1002 -#define LM78_SYSCTL_IN3 1003 -#define LM78_SYSCTL_IN4 1004 -#define LM78_SYSCTL_IN5 1005 -#define LM78_SYSCTL_IN6 1006 -#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM78_SYSCTL_FAN2 1102 -#define LM78_SYSCTL_FAN3 1103 -#define LM78_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ -#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ -#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ - -#define LM78_ALARM_IN0 0x0001 -#define LM78_ALARM_IN1 0x0002 -#define LM78_ALARM_IN2 0x0004 -#define LM78_ALARM_IN3 0x0008 -#define LM78_ALARM_IN4 0x0100 -#define LM78_ALARM_IN5 0x0200 -#define LM78_ALARM_IN6 0x0400 -#define LM78_ALARM_FAN1 0x0040 -#define LM78_ALARM_FAN2 0x0080 -#define LM78_ALARM_FAN3 0x0800 -#define LM78_ALARM_TEMP 0x0010 -#define LM78_ALARM_BTI 0x0020 -#define LM78_ALARM_CHAS 0x1000 -#define LM78_ALARM_FIFO 0x2000 -#define LM78_ALARM_SMI_IN 0x4000 - -#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ -#define W83781D_SYSCTL_IN1 1001 -#define W83781D_SYSCTL_IN2 1002 -#define W83781D_SYSCTL_IN3 1003 -#define W83781D_SYSCTL_IN4 1004 -#define W83781D_SYSCTL_IN5 1005 -#define W83781D_SYSCTL_IN6 1006 -#define W83781D_SYSCTL_IN7 1007 -#define W83781D_SYSCTL_IN8 1008 -#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83781D_SYSCTL_FAN2 1102 -#define W83781D_SYSCTL_FAN3 1103 -#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ -#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ -#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ -#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ -#define W83781D_SYSCTL_VRM 1301 -#define W83781D_SYSCTL_PWM1 1401 -#define W83781D_SYSCTL_PWM2 1402 -#define W83781D_SYSCTL_PWM3 1403 -#define W83781D_SYSCTL_PWM4 1404 -#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define W83781D_SYSCTL_SENS2 1502 -#define W83781D_SYSCTL_SENS3 1503 -#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ -#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ -#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ -#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ -#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ - -#define W83781D_ALARM_IN0 0x0001 -#define W83781D_ALARM_IN1 0x0002 -#define W83781D_ALARM_IN2 0x0004 -#define W83781D_ALARM_IN3 0x0008 -#define W83781D_ALARM_IN4 0x0100 -#define W83781D_ALARM_IN5 0x0200 -#define W83781D_ALARM_IN6 0x0400 -#define W83782D_ALARM_IN7 0x10000 -#define W83782D_ALARM_IN8 0x20000 -#define W83781D_ALARM_FAN1 0x0040 -#define W83781D_ALARM_FAN2 0x0080 -#define W83781D_ALARM_FAN3 0x0800 -#define W83781D_ALARM_TEMP1 0x0010 -#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ -#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ -#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ -#define W83781D_ALARM_CHAS 0x1000 - -#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ - -#define ADM1021_SYSCTL_TEMP 1200 -#define ADM1021_SYSCTL_REMOTE_TEMP 1201 -#define ADM1021_SYSCTL_DIE_CODE 1202 -#define ADM1021_SYSCTL_ALARMS 1203 - -#define ADM1021_ALARM_TEMP_HIGH 0x40 -#define ADM1021_ALARM_TEMP_LOW 0x20 -#define ADM1021_ALARM_RTEMP_HIGH 0x10 -#define ADM1021_ALARM_RTEMP_LOW 0x08 -#define ADM1021_ALARM_RTEMP_NA 0x04 - -#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL518_SYSCTL_VIN1 1001 -#define GL518_SYSCTL_VIN2 1002 -#define GL518_SYSCTL_VIN3 1003 -#define GL518_SYSCTL_FAN1 1101 /* RPM */ -#define GL518_SYSCTL_FAN2 1102 -#define GL518_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ -#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL518_SYSCTL_BEEP 2002 /* bitvector */ -#define GL518_SYSCTL_FAN1OFF 2003 -#define GL518_SYSCTL_ITERATE 2004 - -#define GL518_ALARM_VDD 0x01 -#define GL518_ALARM_VIN1 0x02 -#define GL518_ALARM_VIN2 0x04 -#define GL518_ALARM_VIN3 0x08 -#define GL518_ALARM_TEMP 0x10 -#define GL518_ALARM_FAN1 0x20 -#define GL518_ALARM_FAN2 0x40 - -#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL520_SYSCTL_VIN1 1001 -#define GL520_SYSCTL_VIN2 1002 -#define GL520_SYSCTL_VIN3 1003 -#define GL520_SYSCTL_VIN4 1004 -#define GL520_SYSCTL_FAN1 1101 /* RPM */ -#define GL520_SYSCTL_FAN2 1102 -#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ -#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ -#define GL520_SYSCTL_VID 1300 -#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL520_SYSCTL_BEEP 2002 /* bitvector */ -#define GL520_SYSCTL_FAN1OFF 2003 -#define GL520_SYSCTL_CONFIG 2004 - -#define GL520_ALARM_VDD 0x01 -#define GL520_ALARM_VIN1 0x02 -#define GL520_ALARM_VIN2 0x04 -#define GL520_ALARM_VIN3 0x08 -#define GL520_ALARM_TEMP1 0x10 -#define GL520_ALARM_FAN1 0x20 -#define GL520_ALARM_FAN2 0x40 -#define GL520_ALARM_TEMP2 0x80 -#define GL520_ALARM_VIN4 0x80 - -#define EEPROM_SYSCTL1 1000 -#define EEPROM_SYSCTL2 1001 -#define EEPROM_SYSCTL3 1002 -#define EEPROM_SYSCTL4 1003 -#define EEPROM_SYSCTL5 1004 -#define EEPROM_SYSCTL6 1005 -#define EEPROM_SYSCTL7 1006 -#define EEPROM_SYSCTL8 1007 -#define EEPROM_SYSCTL9 1008 -#define EEPROM_SYSCTL10 1009 -#define EEPROM_SYSCTL11 1010 -#define EEPROM_SYSCTL12 1011 -#define EEPROM_SYSCTL13 1012 -#define EEPROM_SYSCTL14 1013 -#define EEPROM_SYSCTL15 1014 -#define EEPROM_SYSCTL16 1015 - -#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM80_SYSCTL_IN1 1001 -#define LM80_SYSCTL_IN2 1002 -#define LM80_SYSCTL_IN3 1003 -#define LM80_SYSCTL_IN4 1004 -#define LM80_SYSCTL_IN5 1005 -#define LM80_SYSCTL_IN6 1006 -#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM80_SYSCTL_FAN2 1102 -#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ -#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ - -#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM9240_SYSCTL_IN1 1001 -#define ADM9240_SYSCTL_IN2 1002 -#define ADM9240_SYSCTL_IN3 1003 -#define ADM9240_SYSCTL_IN4 1004 -#define ADM9240_SYSCTL_IN5 1005 -#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM9240_SYSCTL_FAN2 1102 -#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ -#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM9240_SYSCTL_ANALOG_OUT 2002 -#define ADM9240_SYSCTL_VID 2003 - -#define ADM9240_ALARM_IN0 0x0001 -#define ADM9240_ALARM_IN1 0x0002 -#define ADM9240_ALARM_IN2 0x0004 -#define ADM9240_ALARM_IN3 0x0008 -#define ADM9240_ALARM_IN4 0x0100 -#define ADM9240_ALARM_IN5 0x0200 -#define ADM9240_ALARM_FAN1 0x0040 -#define ADM9240_ALARM_FAN2 0x0080 -#define ADM9240_ALARM_TEMP 0x0010 -#define ADM9240_ALARM_CHAS 0x1000 - -#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM1024_SYSCTL_IN1 1001 -#define ADM1024_SYSCTL_IN2 1002 -#define ADM1024_SYSCTL_IN3 1003 -#define ADM1024_SYSCTL_IN4 1004 -#define ADM1024_SYSCTL_IN5 1005 -#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM1024_SYSCTL_FAN2 1102 -#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ -#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celcius */ -#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celcius */ -#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM1024_SYSCTL_ANALOG_OUT 2002 -#define ADM1024_SYSCTL_VID 2003 - -#define ADM1024_ALARM_IN0 0x0001 -#define ADM1024_ALARM_IN1 0x0002 -#define ADM1024_ALARM_IN2 0x0004 -#define ADM1024_ALARM_IN3 0x0008 -#define ADM1024_ALARM_IN4 0x0100 -#define ADM1024_ALARM_IN5 0x0200 -#define ADM1024_ALARM_FAN1 0x0040 -#define ADM1024_ALARM_FAN2 0x0080 -#define ADM1024_ALARM_TEMP 0x0010 -#define ADM1024_ALARM_TEMP1 0x0020 -#define ADM1024_ALARM_TEMP2 0x0001 -#define ADM1024_ALARM_CHAS 0x1000 - -#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM1025_SYSCTL_IN1 1001 -#define ADM1025_SYSCTL_IN2 1002 -#define ADM1025_SYSCTL_IN3 1003 -#define ADM1025_SYSCTL_IN4 1004 -#define ADM1025_SYSCTL_IN5 1005 -#define ADM1025_SYSCTL_RTEMP 1251 -#define ADM1025_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ -#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM1025_SYSCTL_ANALOG_OUT 2002 -#define ADM1025_SYSCTL_VID 2003 -#define ADM1025_SYSCTL_VRM 2004 - -#define ADM1025_ALARM_IN0 0x0001 -#define ADM1025_ALARM_IN1 0x0002 -#define ADM1025_ALARM_IN2 0x0004 -#define ADM1025_ALARM_IN3 0x0008 -#define ADM1025_ALARM_IN4 0x0100 -#define ADM1025_ALARM_IN5 0x0200 -#define ADM1025_ALARM_RTEMP 0x0020 -#define ADM1025_ALARM_TEMP 0x0010 - -#define LTC1710_SYSCTL_SWITCH_1 1000 -#define LTC1710_SYSCTL_SWITCH_2 1001 - -#define LM80_ALARM_IN0 0x0001 -#define LM80_ALARM_IN1 0x0002 -#define LM80_ALARM_IN2 0x0004 -#define LM80_ALARM_IN3 0x0008 -#define LM80_ALARM_IN4 0x0010 -#define LM80_ALARM_IN5 0x0020 -#define LM80_ALARM_IN6 0x0040 -#define LM80_ALARM_FAN1 0x0400 -#define LM80_ALARM_FAN2 0x0800 -#define LM80_ALARM_TEMP_HOT 0x0100 -#define LM80_ALARM_TEMP_OS 0x2000 -#define LM80_ALARM_CHAS 0x1000 -#define LM80_ALARM_BTI 0x0200 -#define LM80_ALARM_INT_IN 0x0080 - -#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ -#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ -#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ -#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ -#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celcius */ -#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celcius */ -#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celcius */ -#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celcius */ -#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celcius */ -#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celcius */ -#define MAXI_SYSCTL_PLL 1301 /* MHz */ -#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ -#define MAXI_SYSCTL_VID2 1402 /* Volts */ -#define MAXI_SYSCTL_VID3 1403 /* Volts */ -#define MAXI_SYSCTL_VID4 1404 /* Volts */ -#define MAXI_SYSCTL_VID5 1405 /* Volts */ -#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ -#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ -#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ -#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ -#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ - -#define MAXI_ALARM_VID4 0x0001 -#define MAXI_ALARM_TEMP2 0x0002 -#define MAXI_ALARM_VID1 0x0004 -#define MAXI_ALARM_VID2 0x0008 -#define MAXI_ALARM_VID3 0x0010 -#define MAXI_ALARM_PLL 0x0080 -#define MAXI_ALARM_TEMP4 0x0100 -#define MAXI_ALARM_TEMP5 0x0200 -#define MAXI_ALARM_FAN1 0x1000 -#define MAXI_ALARM_FAN2 0x2000 -#define MAXI_ALARM_FAN3 0x4000 - -#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ -#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ -#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ -#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ - -#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ -#define SIS5595_SYSCTL_IN1 1001 -#define SIS5595_SYSCTL_IN2 1002 -#define SIS5595_SYSCTL_IN3 1003 -#define SIS5595_SYSCTL_IN4 1004 -#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ -#define SIS5595_SYSCTL_FAN2 1102 -#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ -#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ - -#define SIS5595_ALARM_IN0 0x01 -#define SIS5595_ALARM_IN1 0x02 -#define SIS5595_ALARM_IN2 0x04 -#define SIS5595_ALARM_IN3 0x08 -#define SIS5595_ALARM_BTI 0x20 -#define SIS5595_ALARM_FAN1 0x40 -#define SIS5595_ALARM_FAN2 0x80 -#define SIS5595_ALARM_IN4 0x8000 -#define SIS5595_ALARM_TEMP 0x8000 - -#define VIA686A_SYSCTL_IN0 1000 -#define VIA686A_SYSCTL_IN1 1001 -#define VIA686A_SYSCTL_IN2 1002 -#define VIA686A_SYSCTL_IN3 1003 -#define VIA686A_SYSCTL_IN4 1004 -#define VIA686A_SYSCTL_FAN1 1101 -#define VIA686A_SYSCTL_FAN2 1102 -#define VIA686A_SYSCTL_TEMP 1200 -#define VIA686A_SYSCTL_TEMP2 1201 -#define VIA686A_SYSCTL_TEMP3 1202 -#define VIA686A_SYSCTL_FAN_DIV 2000 -#define VIA686A_SYSCTL_ALARMS 2001 - -#define VIA686A_ALARM_IN0 0x01 -#define VIA686A_ALARM_IN1 0x02 -#define VIA686A_ALARM_IN2 0x04 -#define VIA686A_ALARM_IN3 0x08 -#define VIA686A_ALARM_TEMP 0x10 -#define VIA686A_ALARM_FAN1 0x40 -#define VIA686A_ALARM_FAN2 0x80 -#define VIA686A_ALARM_IN4 0x100 -#define VIA686A_ALARM_TEMP2 0x800 -#define VIA686A_ALARM_CHAS 0x1000 -#define VIA686A_ALARM_TEMP3 0x8000 - -#define ICSPLL_SYSCTL1 1000 - -#define BT869_SYSCTL_STATUS 1000 -#define BT869_SYSCTL_NTSC 1001 -#define BT869_SYSCTL_HALF 1002 -#define BT869_SYSCTL_RES 1003 -#define BT869_SYSCTL_COLORBARS 1004 -#define BT869_SYSCTL_DEPTH 1005 -#define BT869_SYSCTL_SVIDEO 1006 - -#define MATORB_SYSCTL_DISP 1000 - -#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celcius */ -#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celcius */ -#define THMC50_SYSCTL_INTER 1202 -#define THMC50_SYSCTL_INTER_MASK 1203 -#define THMC50_SYSCTL_DIE_CODE 1204 -#define THMC50_SYSCTL_ANALOG_OUT 1205 - -#define DDCMON_SYSCTL_ID 1010 -#define DDCMON_SYSCTL_SIZE 1011 -#define DDCMON_SYSCTL_SYNC 1012 -#define DDCMON_SYSCTL_TIMINGS 1013 -#define DDCMON_SYSCTL_SERIAL 1014 - -#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM87_SYSCTL_IN1 1001 -#define LM87_SYSCTL_IN2 1002 -#define LM87_SYSCTL_IN3 1003 -#define LM87_SYSCTL_IN4 1004 -#define LM87_SYSCTL_IN5 1005 -#define LM87_SYSCTL_AIN1 1006 -#define LM87_SYSCTL_AIN2 1007 -#define LM87_SYSCTL_FAN1 1102 -#define LM87_SYSCTL_FAN2 1103 -#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celcius * 100 */ -#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celcius * 100 */ -#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celcius * 100 */ -#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ -#define LM87_SYSCTL_ANALOG_OUT 2002 -#define LM87_SYSCTL_VID 2003 -#define LM87_SYSCTL_VRM 2004 - -#define LM87_ALARM_IN0 0x0001 -#define LM87_ALARM_IN1 0x0002 -#define LM87_ALARM_IN2 0x0004 -#define LM87_ALARM_IN3 0x0008 -#define LM87_ALARM_TEMP1 0x0010 -#define LM87_ALARM_TEMP2 0x0020 -#define LM87_ALARM_TEMP3 0x0020 /* same?? */ -#define LM87_ALARM_FAN1 0x0040 -#define LM87_ALARM_FAN2 0x0080 -#define LM87_ALARM_IN4 0x0100 -#define LM87_ALARM_IN5 0x0200 -#define LM87_ALARM_RESERVED1 0x0400 -#define LM87_ALARM_RESERVED2 0x0800 -#define LM87_ALARM_CHAS 0x1000 -#define LM87_ALARM_THERM_SIG 0x2000 -#define LM87_ALARM_TEMP2_FAULT 0x4000 -#define LM87_ALARM_TEMP3_FAULT 0x08000 - -#define PCF8574_SYSCTL_READ 1000 -#define PCF8574_SYSCTL_WRITE 1001 - -#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ -#define MTP008_SYSCTL_IN1 1001 -#define MTP008_SYSCTL_IN2 1002 -#define MTP008_SYSCTL_IN3 1003 -#define MTP008_SYSCTL_IN4 1004 -#define MTP008_SYSCTL_IN5 1005 -#define MTP008_SYSCTL_IN6 1006 -#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ -#define MTP008_SYSCTL_FAN2 1102 -#define MTP008_SYSCTL_FAN3 1103 -#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ -#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ -#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ -#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ -#define MTP008_SYSCTL_PWM1 1401 -#define MTP008_SYSCTL_PWM2 1402 -#define MTP008_SYSCTL_PWM3 1403 -#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define MTP008_SYSCTL_SENS2 1502 -#define MTP008_SYSCTL_SENS3 1503 -#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ -#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ - -#define MTP008_ALARM_IN0 0x0001 -#define MTP008_ALARM_IN1 0x0002 -#define MTP008_ALARM_IN2 0x0004 -#define MTP008_ALARM_IN3 0x0008 -#define MTP008_ALARM_IN4 0x0100 -#define MTP008_ALARM_IN5 0x0200 -#define MTP008_ALARM_IN6 0x0400 -#define MTP008_ALARM_FAN1 0x0040 -#define MTP008_ALARM_FAN2 0x0080 -#define MTP008_ALARM_FAN3 0x0800 -#define MTP008_ALARM_TEMP1 0x0010 -#define MTP008_ALARM_TEMP2 0x0100 -#define MTP008_ALARM_TEMP3 0x0200 - -#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ -#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ -#define DS1621_ALARM_TEMP_HIGH 0x40 -#define DS1621_ALARM_TEMP_LOW 0x20 -#define DS1621_SYSCTL_ENABLE 2002 -#define DS1621_SYSCTL_CONTINUOUS 2003 -#define DS1621_SYSCTL_POLARITY 2004 - -#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ -#define IT87_SYSCTL_IN1 1001 -#define IT87_SYSCTL_IN2 1002 -#define IT87_SYSCTL_IN3 1003 -#define IT87_SYSCTL_IN4 1004 -#define IT87_SYSCTL_IN5 1005 -#define IT87_SYSCTL_IN6 1006 -#define IT87_SYSCTL_IN7 1007 -#define IT87_SYSCTL_IN8 1008 -#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ -#define IT87_SYSCTL_FAN2 1102 -#define IT87_SYSCTL_FAN3 1103 -#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ -#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ -#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ -#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ -#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ - -#define IT87_ALARM_IN0 0x000100 -#define IT87_ALARM_IN1 0x000200 -#define IT87_ALARM_IN2 0x000400 -#define IT87_ALARM_IN3 0x000800 -#define IT87_ALARM_IN4 0x001000 -#define IT87_ALARM_IN5 0x002000 -#define IT87_ALARM_IN6 0x004000 -#define IT87_ALARM_IN7 0x008000 -#define IT87_ALARM_FAN1 0x0001 -#define IT87_ALARM_FAN2 0x0002 -#define IT87_ALARM_FAN3 0x0004 -#define IT87_ALARM_TEMP1 0x00010000 -#define IT87_ALARM_TEMP2 0x00020000 -#define IT87_ALARM_TEMP3 0x00040000 - -#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ -#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ -#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ -#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ -#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ -#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ -#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ -#define FSCPOS_SYSCTL_REV 2000 /* Revision */ -#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ -#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ - -#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ -#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ -#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ -#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ -#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ -#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ -#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ -#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ -#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ -#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ -#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ -#define FSCSCY_SYSCTL_REV 2000 /* Revision */ -#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ -#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ -#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ -#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ - -#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ -#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ -#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ -#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ -#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ -#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ -#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ - -#define ARP_SYSCTL1 1000 -#define ARP_SYSCTL2 1001 -#define ARP_SYSCTL3 1002 -#define ARP_SYSCTL4 1003 -#define ARP_SYSCTL5 1004 -#define ARP_SYSCTL6 1005 -#define ARP_SYSCTL7 1006 -#define ARP_SYSCTL8 1007 - -#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ -#define SMSC47M1_SYSCTL_FAN2 1102 -#define SMSC47M1_SYSCTL_PWM1 1401 -#define SMSC47M1_SYSCTL_PWM2 1402 -#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ - -#define SMSC47M1_ALARM_FAN1 0x0001 -#define SMSC47M1_ALARM_FAN2 0x0002 - -#define VT1211_SYSCTL_IN0 1000 -#define VT1211_SYSCTL_IN1 1001 -#define VT1211_SYSCTL_IN2 1002 -#define VT1211_SYSCTL_IN3 1003 -#define VT1211_SYSCTL_IN4 1004 -#define VT1211_SYSCTL_IN5 1005 -#define VT1211_SYSCTL_IN6 1006 -#define VT1211_SYSCTL_FAN1 1101 -#define VT1211_SYSCTL_FAN2 1102 -#define VT1211_SYSCTL_TEMP 1200 -#define VT1211_SYSCTL_TEMP2 1201 -#define VT1211_SYSCTL_TEMP3 1202 -#define VT1211_SYSCTL_TEMP4 1203 -#define VT1211_SYSCTL_TEMP5 1204 -#define VT1211_SYSCTL_TEMP6 1205 -#define VT1211_SYSCTL_TEMP7 1206 -#define VT1211_SYSCTL_VID 1300 -#define VT1211_SYSCTL_PWM1 1401 -#define VT1211_SYSCTL_PWM2 1402 -#define VT1211_SYSCTL_VRM 1600 -#define VT1211_SYSCTL_UCH 1700 -#define VT1211_SYSCTL_FAN_DIV 2000 -#define VT1211_SYSCTL_ALARMS 2001 - -#define VT1211_ALARM_IN1 0x01 -#define VT1211_ALARM_IN2 0x02 -#define VT1211_ALARM_IN5 0x04 -#define VT1211_ALARM_IN3 0x08 -#define VT1211_ALARM_TEMP 0x10 -#define VT1211_ALARM_FAN1 0x40 -#define VT1211_ALARM_FAN2 0x80 -#define VT1211_ALARM_IN4 0x100 -#define VT1211_ALARM_IN6 0x200 -#define VT1211_ALARM_TEMP2 0x800 -#define VT1211_ALARM_CHAS 0x1000 -#define VT1211_ALARM_TEMP3 0x8000 -/* duplicates */ -#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP -#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 -#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 -#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 -#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 - -#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ -#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysterisis, input */ - -#define LM92_ALARM_TEMP_HIGH 0x01 -#define LM92_ALARM_TEMP_LOW 0x02 -#define LM92_ALARM_TEMP_CRIT 0x04 -#define LM92_TEMP_HIGH 0x08 -#define LM92_TEMP_LOW 0x10 -#define LM92_TEMP_CRIT 0x20 -#define LM92_TEMP_HYST 0x40 -#define LM92_TEMP_INPUT 0x80 - -#define VT8231_SYSCTL_IN0 1000 -#define VT8231_SYSCTL_IN1 1001 -#define VT8231_SYSCTL_IN2 1002 -#define VT8231_SYSCTL_IN3 1003 -#define VT8231_SYSCTL_IN4 1004 -#define VT8231_SYSCTL_IN5 1005 -#define VT8231_SYSCTL_IN6 1006 -#define VT8231_SYSCTL_FAN1 1101 -#define VT8231_SYSCTL_FAN2 1102 -#define VT8231_SYSCTL_TEMP 1200 -#define VT8231_SYSCTL_TEMP2 1201 -#define VT8231_SYSCTL_TEMP3 1202 -#define VT8231_SYSCTL_TEMP4 1203 -#define VT8231_SYSCTL_TEMP5 1204 -#define VT8231_SYSCTL_TEMP6 1205 -#define VT8231_SYSCTL_TEMP7 1206 -#define VT8231_SYSCTL_VID 1300 -#define VT8231_SYSCTL_PWM1 1401 -#define VT8231_SYSCTL_PWM2 1402 -#define VT8231_SYSCTL_VRM 1600 -#define VT8231_SYSCTL_UCH 1700 -#define VT8231_SYSCTL_FAN_DIV 2000 -#define VT8231_SYSCTL_ALARMS 2001 - -#define VT8231_ALARM_IN1 0x01 -#define VT8231_ALARM_IN2 0x02 -#define VT8231_ALARM_IN5 0x04 -#define VT8231_ALARM_IN3 0x08 -#define VT8231_ALARM_TEMP 0x10 -#define VT8231_ALARM_FAN1 0x40 -#define VT8231_ALARM_FAN2 0x80 -#define VT8231_ALARM_IN4 0x100 -#define VT8231_ALARM_IN6 0x200 -#define VT8231_ALARM_TEMP2 0x800 -#define VT8231_ALARM_CHAS 0x1000 -#define VT8231_ALARM_TEMP3 0x8000 -/* duplicates */ -#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP -#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN1 -#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN2 -#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN3 -#define VT8231_ALARM_TEMP7 VT8231_ALARM_IN4 - -#define SMARTBATT_SYSCTL_I 1001 -#define SMARTBATT_SYSCTL_V 1002 -#define SMARTBATT_SYSCTL_TEMP 1003 -#define SMARTBATT_SYSCTL_TIME 1004 -#define SMARTBATT_SYSCTL_ALARMS 1005 -#define SMARTBATT_SYSCTL_CHARGE 1006 - -#define BMC_SYSCTL_IN1 1000 -#define BMC_SYSCTL_TEMP1 1100 -#define BMC_SYSCTL_CURR1 1200 -#define BMC_SYSCTL_FAN1 1300 -#define BMC_SYSCTL_ALARMS 5000 - - -#endif /* def SENSORS_SENSORS_H */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/sensors_compat.h linux-2.4.20-wolk4.7-fullkernel/include/linux/sensors_compat.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/sensors_compat.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/sensors_compat.h 2003-08-17 21:26:58.000000000 +0200 @@ -0,0 +1,31 @@ +/* + * Stolen from kernel 2.5.69 + * device.h - generic, centralized driver model + * To make it easier to backport from 2.5 + * + * Copyright (c) 2001-2003 Patrick Mochel + * + */ + +#ifndef _SENSORS_COMPAT_H_ +#define _SENSORS_COMPAT_H_ + +/* debugging and troubleshooting/diagnostic helpers. */ +#define dev_printk(level, dev, format, arg...) \ + printk(level "%s: " format , (dev)->name , ## arg) + +#ifdef DEBUG +#define dev_dbg(dev, format, arg...) \ + dev_printk(KERN_DEBUG , dev , format , ## arg) +#else +#define dev_dbg(dev, format, arg...) do {} while (0) +#endif + +#define dev_err(dev, format, arg...) \ + dev_printk(KERN_ERR , dev , format , ## arg) +#define dev_info(dev, format, arg...) \ + dev_printk(KERN_INFO , dev , format , ## arg) +#define dev_warn(dev, format, arg...) \ + dev_printk(KERN_WARNING , dev , format , ## arg) + +#endif /* _SENSORS_COMPAT_H_ */ diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/sensors_vid.h linux-2.4.20-wolk4.7-fullkernel/include/linux/sensors_vid.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/sensors_vid.h 2003-05-03 01:58:35.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/sensors_vid.h 2003-08-17 21:26:58.000000000 +0200 @@ -29,6 +29,21 @@ */ /* + AMD Opteron processors don't follow the Intel VRM spec. + I'm going to "make up" 2.4 as the VRM spec for the Opterons. + No good reason just a mnemonic for the 24x Opteron processor + series + + Opteron VID encoding is: + + 00000 = 1.550 V + 00001 = 1.525 V + . . . . + 11110 = 0.800 V + 11111 = 0.000 V (off) + */ + +/* Legal val values 00 - 1F. vrm is the Intel VRM document version. Note: vrm version is scaled by 10 and the return value is scaled by 1000 @@ -37,12 +52,13 @@ #define DEFAULT_VRM 82 -static int vid_from_reg(int val, int vrm); - -static int vid_from_reg(int val, int vrm) +static inline int vid_from_reg(int val, int vrm) { switch(vrm) { + case 24: /* Opteron processor */ + return(val == 0x1f ? 0 : 1550 - val * 25); + case 91: /* VRM 9.1 */ case 90: /* VRM 9.0 */ return(val == 0x1f ? 0 : diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/swap.h linux-2.4.20-wolk4.7-fullkernel/include/linux/swap.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/swap.h 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/swap.h 2003-08-17 21:29:58.000000000 +0200 @@ -3,7 +3,6 @@ #include #include -#include #define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ #define SWAP_FLAG_PRIO_MASK 0x7fff @@ -96,32 +95,8 @@ extern unsigned int freeable_lowmem(void extern atomic_t page_cache_size; extern atomic_t buffermem_pages; -#if 1 - -static inline void - lock_pagecache(void) { br_write_lock(BR_PAGECACHE_LOCK); } -static inline void - unlock_pagecache(void) { br_write_unlock(BR_PAGECACHE_LOCK); } -static inline void - lock_pagecache_readonly(void) { br_read_lock(BR_PAGECACHE_LOCK); } -static inline void - unlock_pagecache_readonly(void) { br_read_unlock(BR_PAGECACHE_LOCK); } - -#else - extern spinlock_cacheline_t pagecache_lock_cacheline; -#define __pagecache_lock (pagecache_lock_cacheline.lock) - -static inline void - lock_pagecache(void) { spin_lock(&__pagecache_lock); } -static inline void - unlock_pagecache(void) { spin_unlock(&__pagecache_lock); } -static inline void - lock_pagecache_readonly(void) { spin_lock(&__pagecache_lock); } -static inline void - unlock_pagecache_readonly(void) { spin_unlock(&__pagecache_lock); } - -#endif +#define pagecache_lock (pagecache_lock_cacheline.lock) extern void __remove_inode_page(struct page *); @@ -135,7 +110,6 @@ struct zone_t; /* linux/mm/rmap.c */ struct pte_chain; extern int FASTCALL(page_referenced(struct page *, int *)); -extern int FASTCALL(page_referenced_lock(struct page *, int *)); extern struct pte_chain * FASTCALL(page_add_rmap(struct page *, pte_t *, struct pte_chain *)); extern void FASTCALL(page_remove_rmap(struct page *, pte_t *)); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/linux/sysctl.h linux-2.4.20-wolk4.7-fullkernel/include/linux/sysctl.h --- linux-2.4.20-wolk4.6-fullkernel/include/linux/sysctl.h 2003-08-04 23:06:34.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/linux/sysctl.h 2003-08-17 21:31:32.000000000 +0200 @@ -652,14 +652,14 @@ enum { /* CTL_FS names: */ enum { FS_NRINODE=1, /* int:current number of allocated inodes */ - FS_STATINODE=2, + FS_STATINODE=2, /* */ FS_MAXINODE=3, /* int:maximum number of inodes that can be allocated */ FS_NRDQUOT=4, /* int:current number of allocated dquots */ /* was FS_MAXDQUOT */ FS_NRFILE=6, /* int:current number of allocated filedescriptors */ FS_MAXSOFT=7, /* int: Soft limit number of filedescriptors that can be allocated */ FS_MAXHARD=8, /* int: Hard limit is max, Soft limit starts complaining */ - FS_DENTRY=9, + FS_DENTRY=9, /* */ FS_NRSUPER=10, /* int:current number of allocated super_blocks */ FS_MAXSUPER=11, /* int:maximum number of super_blocks that can be allocated */ FS_OVERFLOWUID=12, /* int: overflow UID */ @@ -673,6 +673,7 @@ enum { FS_AIO_MAX_NR=20, /* int: max system wide aio requests */ FS_AIO_MAX_SIZE=21, /* int: max size of read/write chunks */ FS_AIO_MAX_PINNED=22, /* long: max memory pinned (in pages) */ + }; /* /proc/sys/fs/quota/ */ @@ -695,8 +696,7 @@ enum { DEV_HWMON=2, DEV_PARPORT=3, DEV_RAID=4, - DEV_MAC_HID=5, - DEV_EVMS=6 + DEV_MAC_HID=5 }; /* /proc/sys/dev/cdrom */ @@ -714,18 +714,6 @@ enum { DEV_PARPORT_DEFAULT=-3 }; -/* /proc/sys/dev/evms */ -enum { - DEV_EVMS_INFO_LEVEL=1, - DEV_EVMS_MD=2 -}; - -/* /proc/sys/dev/evms/raid */ -enum { - DEV_EVMS_MD_SPEED_LIMIT_MIN=1, - DEV_EVMS_MD_SPEED_LIMIT_MAX=2 -}; - /* /proc/sys/dev/raid */ enum { DEV_RAID_SPEED_LIMIT_MIN=1, diff -Naurp linux-2.4.20-wolk4.6-fullkernel/include/net/ip_vs.h linux-2.4.20-wolk4.7-fullkernel/include/net/ip_vs.h --- linux-2.4.20-wolk4.6-fullkernel/include/net/ip_vs.h 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/include/net/ip_vs.h 2003-08-17 21:27:31.000000000 +0200 @@ -8,7 +8,7 @@ #include /* For __uXX types */ -#define IP_VS_VERSION_CODE 0x010009 +#define IP_VS_VERSION_CODE 0x01000A #define NVERSION(version) \ (version >> 16) & 0xFF, \ (version >> 8) & 0xFF, \ @@ -702,7 +702,6 @@ extern int sysctl_ip_vs_cache_bypass; extern int sysctl_ip_vs_expire_nodest_conn; extern int sysctl_ip_vs_sync_threshold; extern int sysctl_ip_vs_nat_icmp_send; -extern atomic_t ip_vs_dropentry; extern struct ip_vs_stats ip_vs_stats; extern struct ip_vs_service *ip_vs_service_get(__u32 fwmark, @@ -715,7 +714,6 @@ static inline void ip_vs_service_put(str extern struct ip_vs_dest * ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport); -extern void update_defense_level(void); extern void ip_vs_random_dropentry(void); extern int ip_vs_control_init(void); extern void ip_vs_control_cleanup(void); @@ -914,7 +912,8 @@ static inline void ip_vs_fast_check_upda else checkp = &h->uh->check; *checkp = ip_vs_check_diff(~oldip, newip, - ip_vs_check_diff(oldport ^ 0xFFFF, newport, *checkp)); + ip_vs_check_diff(oldport ^ 0xFFFF, + newport, *checkp)); if (!*checkp && protocol == IPPROTO_UDP) *checkp = 0xFFFF; } @@ -928,7 +927,7 @@ ip_vs_skb_cow(struct sk_buff *skb, unsig if (delta < 0) delta = 0; - if (delta ||skb_cloned(skb)) { + if (delta || skb_cloned(skb)) { if (pskb_expand_head(skb, (delta+15)&~15, 0, GFP_ATOMIC)) return -ENOMEM; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/init/do_mounts.c linux-2.4.20-wolk4.7-fullkernel/init/do_mounts.c --- linux-2.4.20-wolk4.6-fullkernel/init/do_mounts.c 2003-08-04 23:06:40.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/init/do_mounts.c 2003-08-17 21:31:31.000000000 +0200 @@ -270,7 +270,6 @@ static struct dev_name_struct { { "ftlc", 0x2c10 }, { "ftld", 0x2c18 }, { "mtdblock", 0x1f00 }, - { "evms", 0x7500 }, { "nb", 0x2b00 }, { NULL, 0 } }; @@ -806,11 +805,6 @@ static void __init mount_root(void) mount_block_root("/dev/root", root_mountflags); } -void get_root_device_name( char * root_name ) -{ - strncpy(root_name, root_device_name, 63); -} - #ifdef CONFIG_BLK_DEV_INITRD static int old_fd, root_fd; static int do_linuxrc(void * shell) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/init/main.c linux-2.4.20-wolk4.7-fullkernel/init/main.c --- linux-2.4.20-wolk4.6-fullkernel/init/main.c 2003-08-04 23:06:40.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/init/main.c 2003-08-17 21:31:29.000000000 +0200 @@ -327,31 +327,22 @@ static void __init parse_options(char *l if (!*line) continue; #ifdef 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, kdb=off, kdb=early */ + if (strncmp(line, "kdb=", 4) == 0) { + if (strcmp(line+4, "on") == 0) { 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); + 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 /* CONFIG_KDB */ if (!strncmp(line,"init=",5)) { @@ -612,16 +603,9 @@ asmlinkage void __init start_kernel(void printk("ELEVATOR: You are using the NOOP Elevator. WARNING!!\n"); #endif #ifdef CONFIG_BLK_DEV_ELEVATOR_LOWLAT - printk("ELEVATOR: You are using the Low Latency I/O Elevator.\n"); - #endif - #ifdef CONFIG_BLK_DEV_ELEVATOR_NORMAL - printk("ELEVATOR: You are using the Normal I/O Elevator.\n"); - #endif - #ifdef CONFIG_BLK_DEV_ELEVATOR_MAXSPEED - printk("ELEVATOR: You are using the Max Throughput I/O Elevator.\n"); + printk("ELEVATOR: You are using the Low Latency Elevator. Fasten your seat belt :)\n"); #endif - /* * We want to tell the user we are O(1) scheduling. */ @@ -777,6 +761,9 @@ static int init(void * unused) #ifdef CONFIG_RSBAC /* RSBAC: OK, most stuff initialized and root mounted: Init RSBAC. */ #ifdef CONFIG_BLK_DEV_INITRD +#ifdef CONFIG_RSBAC_INIT_DELAY + if(!rsbac_delay_init) +#endif rsbac_init(real_root_dev); { struct super_block * sb_p = get_super(MKDEV(RAMDISK_MAJOR,0)); @@ -790,6 +777,7 @@ static int init(void * unused) #else rsbac_init(ROOT_DEV); #endif + #endif /* diff -Naurp linux-2.4.20-wolk4.6-fullkernel/init/version.c linux-2.4.20-wolk4.7-fullkernel/init/version.c --- linux-2.4.20-wolk4.6-fullkernel/init/version.c 2003-08-17 21:04:11.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/init/version.c 2003-08-17 21:31:24.000000000 +0200 @@ -26,7 +26,7 @@ struct new_utsname system_utsname = { }; const char *wolk_banner = - "WOLK - Working Overloaded Linux Kernel - v4.6 - Server Edition""\n\n"; + "WOLK - Working Overloaded Linux Kernel - v4.7 - Server Edition""\n\n"; const char *linux_banner = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kdb/ChangeLog linux-2.4.20-wolk4.7-fullkernel/kdb/ChangeLog --- linux-2.4.20-wolk4.6-fullkernel/kdb/ChangeLog 2003-05-05 20:04:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kdb/ChangeLog 2003-08-17 21:26:24.000000000 +0200 @@ -1,3 +1,24 @@ +2003-06-20 Keith Owens + + * More details on vm command, add vmp and pte commands. + Dean Nelson, Dean Roe, SGI. + * YAO1SCF (Yet Another O(1) Scheduler Coexistence Fix). + * Changes to common code to build on sparc. Tom Duffy. + * Move Tom Duffy's changes to drivers/sbus from the sparc64 + patch to the common patch to keep all the serial changes + together. + * Changes to common code to build on Xscale. Eddie Dong, Intel. + * Remove CROSS_COMPILE_INC. + * Remove obsolete boot parameter 'kdb', long since replaced by + 'kdb=on'. + * Remove obsolete kdb_eframe_t casts. + * Add CONFIG_KDB_CONTINUE_CATASTROPHIC. + * Wait a short interval for cpus to join kdb before proceeding. + * Automatically enable sysrq for sr command. + * Correct double free of kdb_printf lock, spotted by Richard Sanders. + * Add optional cpu parameter to btc command. + * kdb v4.3-2.4.20-common-1. + 2003-05-02 Keith Owens * Some architectures have problems with the initial empty kallsyms diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kdb/kdb_bt.c linux-2.4.20-wolk4.7-fullkernel/kdb/kdb_bt.c --- linux-2.4.20-wolk4.6-fullkernel/kdb/kdb_bt.c 2003-05-05 20:04:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kdb/kdb_bt.c 2003-08-17 21:26:24.000000000 +0200 @@ -52,7 +52,7 @@ * btp Kernel stack for * btt Kernel stack for task structure at * bta [DRSTZU] All processes, optionally filtered by state - * btc The current process on each cpu + * btc [] The current process on one cpu, default is all cpus * * address expression refers to a return address on the stack. It * is expected to be preceeded by a frame pointer. @@ -153,12 +153,24 @@ kdb_bt(int argc, const char **argv, cons return diag; return kdb_bt1((struct task_struct *)addr, ~0, argcount, 0); } else if (strcmp(argv[0], "btc") == 0) { - unsigned long cpu; + unsigned long cpu = ~0; struct kdb_running_process *krp; char buf[80]; - if (argc != 0) + if (argc > 1) return KDB_ARGCOUNT; - kdb_printf("btc: cpu\n"); + if (argc == 1 && (diag = kdbgetularg((char *)argv[1], &cpu))) + return diag; + if (cpu != ~0) { + krp = kdb_running_process + cpu; + if (cpu >= smp_num_cpus || !krp->seqno) { + kdb_printf("no process for cpu %ld\n", cpu); + return 0; + } + sprintf(buf, "btt 0x%p\n", krp->p); + kdb_parse(buf, regs); + return 0; + } + kdb_printf("btc: cpu status: "); kdb_parse("cpu\n", regs); for (cpu = 0, krp = kdb_running_process; cpu < smp_num_cpus; ++cpu, ++krp) { if (!krp->seqno) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kdb/kdb_io.c linux-2.4.20-wolk4.7-fullkernel/kdb/kdb_io.c --- linux-2.4.20-wolk4.6-fullkernel/kdb/kdb_io.c 2003-05-05 20:04:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kdb/kdb_io.c 2003-08-17 21:26:24.000000000 +0200 @@ -486,6 +486,7 @@ kdb_printf(const char *fmt, ...) int linecount; int logging, saved_loglevel = 0; int do_longjmp = 0; + int got_printf_lock = 0; struct console *c = console_drivers; static spinlock_t kdb_printf_lock = SPIN_LOCK_UNLOCKED; @@ -496,6 +497,7 @@ kdb_printf(const char *fmt, ...) if (!KDB_STATE(PRINTF_LOCK)) { KDB_STATE_SET(PRINTF_LOCK); spin_lock(&kdb_printf_lock); + got_printf_lock = 1; } diag = kdbgetintenv("LINES", &linecount); @@ -591,7 +593,8 @@ kdb_printf(const char *fmt, ...) if (logging) { console_loglevel = saved_loglevel; } - if (KDB_STATE(PRINTF_LOCK)) { + if (KDB_STATE(PRINTF_LOCK) && got_printf_lock) { + got_printf_lock = 0; spin_unlock(&kdb_printf_lock); KDB_STATE_CLEAR(PRINTF_LOCK); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kdb/kdbmain.c linux-2.4.20-wolk4.7-fullkernel/kdb/kdbmain.c --- linux-2.4.20-wolk4.6-fullkernel/kdb/kdbmain.c 2003-05-05 20:04:55.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kdb/kdbmain.c 2003-08-17 21:26:24.000000000 +0200 @@ -3,6 +3,7 @@ * * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 2000 Stephane Eranian + * Xscale (R) modifications copyright (C) 2003 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -33,6 +34,11 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ +/* + * Updated for Xscale (R) architecture support + * Eddie Dong 8 Jan 03 + */ + #include #include #include @@ -50,6 +56,9 @@ #include #include #include +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#include +#endif #include @@ -87,6 +96,12 @@ int kdb_on = 1; /* Default is on */ const char *kdb_diemsg; struct notifier_block *kdb_notifier_list; /* racy for modules, see comments in kdb.h */ +static int kdb_go_count; +#ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC +static unsigned int kdb_continue_catastrophic = CONFIG_KDB_CONTINUE_CATASTROPHIC; +#else +static unsigned int kdb_continue_catastrophic = 0; +#endif #ifdef KDB_HAVE_LONGJMP /* @@ -123,7 +138,11 @@ static kdbmsg_t kdbmsgs[] = { KDBMSG(ENVFULL, "Environment full"), KDBMSG(ENVBUFFULL, "Environment buffer full"), KDBMSG(TOOMANYBPT, "Too many breakpoints defined"), +#ifdef CONFIG_CPU_XSCALE + KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"), +#else KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"), +#endif KDBMSG(DUPBPT, "Duplicate breakpoint address"), KDBMSG(BPTNOTFOUND, "Breakpoint not found"), KDBMSG(BADMODE, "Invalid IDMODE"), @@ -368,6 +387,103 @@ kdbgetularg(const char *arg, unsigned lo } /* + * 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; +} + +/* * kdbgetaddrarg * * This function is responsible for parsing an @@ -931,6 +1047,61 @@ handle_ctrl_cmd(char *cmd) return 0; } +/* + * kdb_do_dump + * + * Call the dump() function if the kernel is configured for LKCD. + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. dump() may or may not return. + * Locking: + * none. + * Remarks: + */ + +static void +kdb_do_dump(struct pt_regs *regs) +{ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + kdb_printf("Forcing dump (if configured)\n"); + console_loglevel = 8; /* to see the dump messages */ + dump("kdb_do_dump", regs); +#endif +} + +/* + * 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); + kdb_printf("Hmm, kdb_reboot did not reboot, spinning here\n"); + while (1) {}; + /* NOTREACHED */ + return 0; +} /* * kdb_local @@ -969,6 +1140,7 @@ kdb_local(kdb_reason_t reason, int error char *cmdbuf; int diag; + kdb_go_count = 0; if (reason != KDB_REASON_DEBUG && reason != KDB_REASON_SILENT) { kdb_printf("\nEntering kdb (current=0x%p, pid %d) ", (void *)current, current->pid); @@ -1096,6 +1268,19 @@ kdb_local(kdb_reason_t reason, int error *cmdbuf = '\0'; *(cmd_hist[cmd_head])='\0'; + if (KDB_FLAG(ONLY_DO_DUMP)) { + /* kdb is off but a catastrophic error requires a dump. + * Take the dump and reboot. + * Turn on logging so the kdb output appears in the log + * buffer in the dump. + */ + const char *setargs[] = { "set", "LOGGING", "1" }; + kdb_set(2, setargs, NULL, regs); + kdb_do_dump(regs); + kdb_reboot(0, NULL, NULL, regs); + /*NOTREACHED*/ + } + do_full_getstr: #if defined(CONFIG_SMP) snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"), smp_processor_id()); @@ -1200,6 +1385,61 @@ kdb_previous_event(void) } /* + * kdb_wait_for_cpus + * + * Invoked once at the start of a kdb event, from the controlling cpu. Wait a + * short period for the other cpus to enter kdb state. + * + * Inputs: + * none + * Returns: + * none + * Locking: + * none + * Remarks: + * none + */ + +int kdb_wait_for_cpus_secs = 10; /* may be modified by ia64 MCA timeout */ + +static void +kdb_wait_for_cpus(void) +{ +#ifdef CONFIG_SMP + int online = 0, kdb_data = 0, prev_kdb_data = 0, i, time; + mdelay(100); + for (time = 0; time < kdb_wait_for_cpus_secs; ++time) { + online = 0; + kdb_data = 0; + for (i = 0; i < NR_CPUS; ++i) { + if (cpu_online(i)) { + ++online; + if (kdb_running_process[i].seqno >= kdb_seqno - 1) + ++kdb_data; + } + } + if (online == kdb_data) + break; + if (prev_kdb_data != kdb_data) { + kdb_nextline = 0; /* no prompt yet */ + kdb_printf("%d out of %d cpus in kdb, waiting for the rest\n", + kdb_data, online); + prev_kdb_data = kdb_data; + } + touch_nmi_watchdog(); + mdelay(1000); + } + if (time) { + if (online == kdb_data) + kdb_printf("All cpus are now in kdb\n"); + else + kdb_printf("%d cpu%s are not in kdb, their state is unknown\n", + online - kdb_data, online - kdb_data == 1 ? "" : "s"); + } +#endif /* CONFIG_SMP */ +} + +/* * kdb_main_loop * * The main kdb loop. After initial setup and assignment of the controlling @@ -1235,6 +1475,7 @@ kdb_main_loop(kdb_reason_t reason, kdb_r kdb_dbtrap_t db_result, struct pt_regs *regs) { int result = 1; + int wait_for_cpus = reason != KDB_REASON_SILENT; /* Stay in kdb() until 'go', 'ss[b]' or an error */ while (1) { /* @@ -1256,6 +1497,10 @@ kdb_main_loop(kdb_reason_t reason, kdb_r if (KDB_STATE(LEAVING)) break; /* Another cpu said 'go' */ + if (wait_for_cpus) { + wait_for_cpus = 0; + kdb_wait_for_cpus(); + } /* Still using kdb, this processor is in control */ result = kdb_local(reason2, error, regs, db_result); KDB_DEBUG_STATE("kdb_main_loop 3", result); @@ -1421,7 +1666,23 @@ kdb(kdb_reason_t reason, int error, stru int ss_event; kdb_dbtrap_t db_result=KDB_DB_NOBPT; - if (!kdb_on) + switch(reason) { + case KDB_REASON_OOPS: + case KDB_REASON_NMI: + case KDB_REASON_WATCHDOG: + KDB_FLAG_SET(CATASTROPHIC); /* kernel state is dubious now */ + break; + default: + break; + } + if (kdb_continue_catastrophic > 2) { + kdb_printf("kdb_continue_catastrophic is out of range, setting to 2\n"); + kdb_continue_catastrophic = 2; + } + if (!kdb_on && KDB_FLAG(CATASTROPHIC) && kdb_continue_catastrophic == 2) { + KDB_FLAG_SET(ONLY_DO_DUMP); + } + if (!kdb_on && !KDB_FLAG(ONLY_DO_DUMP)) return 0; KDB_DEBUG_STATE("kdb 1", reason); @@ -1433,6 +1694,16 @@ kdb(kdb_reason_t reason, int error, stru * kdba_b[dp]_trap sets SSBPT if required. */ ss_event = KDB_STATE(DOING_SS) || KDB_STATE(SSBPT); +#ifdef CONFIG_CPU_XSCALE + if ( KDB_STATE(A_XSC_ICH) ) { + /* restore changed I_BIT */ + KDB_STATE_CLEAR(A_XSC_ICH); + kdba_restore_retirq(regs, KDB_STATE(A_XSC_IRQ)); + if ( !ss_event ) { + kdb_printf("Stranger!!! Why IRQ bit is changed====\n"); + } + } +#endif if (reason == KDB_REASON_BREAK) { db_result = kdba_bp_trap(regs, error); /* Only call this once */ } @@ -1593,11 +1864,10 @@ kdb(kdb_reason_t reason, int error, stru /* * If SMP, stop other processors. The other processors * will enter kdb() with KDB_REASON_SWITCH and spin in - * kdb_main_loop(). Skip this for catastrophic events, - * IPI is not reliable and can cause kdb to hang. + * kdb_main_loop(). */ KDB_DEBUG_STATE("kdb 6", reason); - if (smp_num_cpus > 1 && !KDB_FLAG(CATASTROPHIC)) { + if (smp_num_cpus > 1) { int i; for (i = 0; i < NR_CPUS; ++i) { if (!cpu_online(i)) @@ -1664,6 +1934,21 @@ kdb(kdb_reason_t reason, int error, stru KDB_DEBUG_STATE("kdb 14", result); kdba_restoreint(&int_state); +#ifdef CONFIG_CPU_XSCALE + if ( smp_processor_id() == kdb_initial_cpu && + ( KDB_STATE(SSBPT) | KDB_STATE(DOING_SS) ) + ) { + kdba_setsinglestep(regs); + // disable IRQ in stack frame + KDB_STATE_SET(A_XSC_ICH); + if ( kdba_disable_retirq(regs) ) { + KDB_STATE_SET(A_XSC_IRQ); + } + else { + KDB_STATE_CLEAR(A_XSC_IRQ); + } + } +#endif /* Only do this work if we are really leaving kdb */ if (!(KDB_STATE(DOING_SS) || KDB_STATE(SSBPT) || KDB_STATE(RECURSE))) { @@ -1675,6 +1960,7 @@ kdb(kdb_reason_t reason, int error, stru } KDB_DEBUG_STATE("kdb 16", result); + KDB_FLAG_CLEAR(CATASTROPHIC); KDB_STATE_CLEAR(IP_ADJUSTED); /* Re-adjust ip next time in */ KDB_STATE_CLEAR(KDB); /* Main kdb state has been cleared */ KDB_STATE_CLEAR(RECURSE); @@ -2050,6 +2336,21 @@ kdb_go(int argc, const char **argv, cons return KDB_ARGCOUNT; diag = KDB_CMD_GO; + if (KDB_FLAG(CATASTROPHIC)) { + kdb_printf("Catastrophic error detected\n"); + kdb_printf("kdb_continue_catastrophic=%d, ", + kdb_continue_catastrophic); + if (kdb_continue_catastrophic == 0 && kdb_go_count++ == 0) { + kdb_printf("type go a second time if you really want to continue\n"); + return 0; + } + if (kdb_continue_catastrophic == 2) { + kdb_do_dump(regs); + kdb_printf("forcing reboot\n"); + kdb_reboot(0, NULL, NULL, regs); + } + kdb_printf("attempting to continue\n"); + } if (smp_processor_id() != kdb_initial_cpu) { char buf[80]; kdb_printf("go was not issued from initial cpu, switching back to cpu %d\n", kdb_initial_cpu); @@ -2098,7 +2399,7 @@ kdb_rd(int argc, const char **argv, cons return KDB_ARGCOUNT; } - return kdba_dumpregs(regs, argv[1], argv[2]); + return kdba_dumpregs(regs, argv[1], argc==2 ? argv[2]: NULL); } /* @@ -2180,9 +2481,14 @@ kdb_rm(int argc, const char **argv, cons int kdb_sr(int argc, const char **argv, const char **envp, struct pt_regs *regs) { + extern int sysrq_enabled; if (argc != 1) { return KDB_ARGCOUNT; } + if (!sysrq_enabled) { + kdb_printf("Auto activating sysrq\n"); + sysrq_enabled = 1; + } handle_sysrq(*argv[1], regs, 0, 0); @@ -2234,35 +2540,6 @@ kdb_ef(int argc, const char **argv, cons 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); @@ -2422,103 +2699,6 @@ kdb_env(int argc, const char **argv, con } /* - * 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_dmesg * * This function implements the 'dmesg' command to display the contents @@ -2570,17 +2750,17 @@ kdb_dmesg(int argc, const char **argv, c logsize = syslog_data[1] - syslog_data[0]; start = syslog_data[0] + (syslog_data[2] - syslog_data[0]) % logsize; end = syslog_data[0] + (syslog_data[3] - syslog_data[0]) % logsize; -#define WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; else if (p >= syslog_data[1]) p = syslog_data[0] +#define KDB_WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; else if (p >= syslog_data[1]) p = syslog_data[0] if (lines) { char *p = end; ++lines; do { --p; - WRAP(p); + KDB_WRAP(p); if (*p == '\n') { if (--lines == 0) { ++p; - WRAP(p); + KDB_WRAP(p); break; } } @@ -2595,7 +2775,7 @@ kdb_dmesg(int argc, const char **argv, c if (!*start) { while (!*start) { ++start; - WRAP(start); + KDB_WRAP(start); if (start == end) break; } @@ -2607,7 +2787,7 @@ kdb_dmesg(int argc, const char **argv, c c = *start; ++chars; ++start; - WRAP(start); + KDB_WRAP(start); if (start == end || c == '\n') break; } @@ -3387,6 +3567,7 @@ kdb_cmd_init(void) static int kdb_panic(struct notifier_block *self, unsigned long command, void *ptr) { + KDB_FLAG_SET(CATASTROPHIC); /* kernel state is dubious now */ KDB_ENTER(); return(0); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kdb/modules/kdbm_vm.c linux-2.4.20-wolk4.7-fullkernel/kdb/modules/kdbm_vm.c --- linux-2.4.20-wolk4.6-fullkernel/kdb/modules/kdbm_vm.c 2003-05-03 01:54:07.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kdb/modules/kdbm_vm.c 2003-08-17 21:26:24.000000000 +0200 @@ -68,34 +68,248 @@ struct __vmflags { }; static int +kdbm_print_vm(struct vm_area_struct *vp, unsigned long addr, int verbose_flg) +{ + struct __vmflags *tp; + + kdb_printf("struct vm_area_struct at 0x%lx for %d bytes\n", + addr, (int) sizeof (struct vm_area_struct)); + + kdb_printf("vm_start = 0x%p vm_end = 0x%p\n", (void *) vp->vm_start, + (void *) vp->vm_end); + kdb_printf("vm_page_prot = 0x%lx\n", pgprot_val(vp->vm_page_prot)); + + kdb_printf("vm_flags: "); + for (tp = vmflags; tp->mask; tp++) { + if (vp->vm_flags & tp->mask) { + kdb_printf(" %s", tp->name); + } + } + kdb_printf("\n"); + + if (!verbose_flg) + return 0; + + kdb_printf("vm_mm = 0x%p\n", (void *) vp->vm_mm); + kdb_printf("vm_next = 0x%p\n", (void *) vp->vm_next); + kdb_printf("vm_next_share = 0x%p\n", (void *) vp->vm_next_share); + kdb_printf("vm_pprev_share = 0x%p\n", (void *) vp->vm_pprev_share); + kdb_printf("vm_ops = 0x%p\n", (void *) vp->vm_ops); + if (vp->vm_ops != NULL) { + kdb_printf("vm_ops->open = 0x%p\n", vp->vm_ops->open); + kdb_printf("vm_ops->close = 0x%p\n", vp->vm_ops->close); + kdb_printf("vm_ops->nopage = 0x%p\n", vp->vm_ops->nopage); +#ifdef HAVE_VMOP_MPROTECT + kdb_printf("vm_ops->mprotect = 0x%p\n", vp->vm_ops->mprotect); +#endif + } + kdb_printf("vm_pgoff = 0x%lx\n", vp->vm_pgoff); + kdb_printf("vm_file = 0x%p\n", (void *) vp->vm_file); + kdb_printf("vm_private_data = 0x%p\n", vp->vm_private_data); + + return 0; +} + +static int +kdbm_print_vmp(struct vm_area_struct *vp, int verbose_flg) +{ + struct __vmflags *tp; + + if (verbose_flg) { + kdb_printf("0x%lx: ", (unsigned long) vp); + } + + kdb_printf("0x%p 0x%p ", (void *) vp->vm_start, (void *) vp->vm_end); + + for (tp = vmflags; tp->mask; tp++) { + if (vp->vm_flags & tp->mask) { + kdb_printf(" %s", tp->name); + } + } + kdb_printf("\n"); + + return 0; +} + +/* + * kdbm_vm + * + * This function implements the 'vm' command. Print a vm_area_struct. + * + * vm [-v]
Print vm_area_struct at
+ * vmp [-v] Print all vm_area_structs for + */ + +static int kdbm_vm(int argc, const char **argv, const char **envp, struct pt_regs *regs) { - struct vm_area_struct vp; unsigned long addr; - long offset=0; + long offset = 0; int nextarg; int diag; - struct __vmflags *tp; - - if (argc != 1) + int verbose_flg = 0; + + if (argc == 2) { + if (strcmp(argv[1], "-v") != 0) { + return KDB_ARGCOUNT; + } + verbose_flg = 1; + } else if (argc != 1) { return KDB_ARGCOUNT; + } - nextarg = 1; - if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || - (diag = kdb_getarea(vp, addr))) - return(diag); + if (strcmp(argv[0], "vmp") == 0) { + struct task_struct *tp; + struct vm_area_struct *vp; + pid_t pid; - kdb_printf("struct vm_area_struct at 0x%lx for %d bytes\n", - addr, (int)sizeof(struct vm_area_struct)); - kdb_printf("vm_start = 0x%lx vm_end = 0x%lx\n", vp.vm_start, vp.vm_end); - kdb_printf("page_prot = 0x%lx\n", pgprot_val(vp.vm_page_prot)); - kdb_printf("flags: "); - for(tp=vmflags; tp->mask; tp++) { - if (vp.vm_flags & tp->mask) { - kdb_printf("%s ", tp->name); + if ((diag = kdbgetularg(argv[argc], (unsigned long *) &pid))) + return diag; + + for_each_task(tp) { + if (tp->pid == pid) { + if (tp->mm != NULL) { + if (verbose_flg) + kdb_printf + ("vm_area_struct "); + kdb_printf + ("vm_start vm_end vm_flags\n"); + vp = tp->mm->mmap; + while (vp != NULL) { + kdbm_print_vmp(vp, verbose_flg); + vp = vp->vm_next; + } + } + return 0; + } } + + kdb_printf("No process with pid == %d found\n", pid); + + } else { + struct vm_area_struct v; + + nextarg = argc; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, + NULL, regs)) + || (diag = kdb_getarea(v, addr))) + return (diag); + + kdbm_print_vm(&v, addr, verbose_flg); + } + + return 0; +} + +static int +kdbm_print_pte(pte_t * pte) +{ + kdb_printf("0x%lx (", (unsigned long) pte_val(*pte)); + + if (pte_present(*pte)) { + if (pte_exec(*pte)) + kdb_printf("X"); + if (pte_write(*pte)) + kdb_printf("W"); + if (pte_read(*pte)) + kdb_printf("R"); + if (pte_young(*pte)) + kdb_printf("A"); + if (pte_dirty(*pte)) + kdb_printf("D"); + + } else { + kdb_printf("OFFSET=0x%lx ", SWP_OFFSET(pte_to_swp_entry(*pte))); + kdb_printf("TYPE=0x%lx", SWP_TYPE(pte_to_swp_entry(*pte))); + } + + kdb_printf(")"); + + /* final newline is output by caller of kdbm_print_pte() */ + + return 0; +} + +/* + * kdbm_pte + * + * This function implements the 'pte' command. Print all pte_t structures + * that map to the given virtual address range for the given process. + * + * pte
[] Print all pte_t structures for virtual + *
in address space of + */ + +static int +kdbm_pte(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + unsigned long nbytes = 1; + long npgs; + int diag; + int found; + pid_t pid; + struct task_struct *tp; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + if (argc < 2 || argc > 3) { + return KDB_ARGCOUNT; + } + + if ((diag = kdbgetularg(argv[1], (unsigned long *) &pid))) { + return diag; + } + + found = 0; + for_each_task(tp) { + if (tp->pid == pid) { + if (tp->mm != NULL) { + found = 1; + break; + } + kdb_printf("task structure's mm field is NULL\n"); + return 0; + } + } + + if (!found) { + kdb_printf("No process with pid == %d found\n", pid); + return 0; + } + + if ((diag = kdbgetularg(argv[2], &addr))) { + return diag; + } + + if (argc == 3) { + if ((diag = kdbgetularg(argv[3], &nbytes))) { + return diag; + } + } + + kdb_printf("vaddr pte\n"); + + npgs = ((((addr & ~PAGE_MASK) + nbytes) + ~PAGE_MASK) >> PAGE_SHIFT); + while (npgs-- > 0) { + + kdb_printf("0x%p ", (void *) (addr & PAGE_MASK)); + + pgd = pgd_offset(tp->mm, addr); + if (pgd_present(*pgd)) { + pmd = pmd_offset(pgd, addr); + if (pmd_present(*pmd)) { + pte = pte_offset(pmd, addr); + if (pte_present(*pte)) { + kdbm_print_pte(pte); + } + } + } + + kdb_printf("\n"); + addr += PAGE_SIZE; } - kdb_printf("\n"); return 0; } @@ -452,7 +666,9 @@ out: static int __init kdbm_vm_init(void) { - kdb_register("vm", kdbm_vm, "", "Display vm_area_struct", 0); + kdb_register("vm", kdbm_vm, "[-v] ", "Display vm_area_struct", 0); + kdb_register("vmp", kdbm_vm, "[-v] ", "Display all vm_area_struct for ", 0); + kdb_register("pte", kdbm_pte, " []", "Display pte_t", 0); kdb_register("dentry", kdbm_dentry, "", "Display interesting dentry stuff", 0); kdb_register("filp", kdbm_fp, "", "Display interesting filp stuff", 0); kdb_register("fl", kdbm_fl, "", "Display interesting file_lock stuff", 0); @@ -466,6 +682,8 @@ static int __init kdbm_vm_init(void) static void __exit kdbm_vm_exit(void) { kdb_unregister("vm"); + kdb_unregister("vmp"); + kdb_unregister("pte"); kdb_unregister("dentry"); kdb_unregister("filp"); kdb_unregister("fl"); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kernel/fork.c linux-2.4.20-wolk4.7-fullkernel/kernel/fork.c --- linux-2.4.20-wolk4.6-fullkernel/kernel/fork.c 2003-08-17 21:04:11.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kernel/fork.c 2003-08-17 21:31:39.000000000 +0200 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -576,6 +575,11 @@ static int copy_files(unsigned long clon goto out; } + /* + * Note: we may be using current for both targets (See exec.c) + * This works because we cache current->files (old) as oldf. Don't + * break this. + */ tsk->files = NULL; error = -ENOMEM; newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kernel/ksyms.c linux-2.4.20-wolk4.7-fullkernel/kernel/ksyms.c --- linux-2.4.20-wolk4.6-fullkernel/kernel/ksyms.c 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kernel/ksyms.c 2003-08-17 21:31:38.000000000 +0200 @@ -183,14 +183,15 @@ EXPORT_SYMBOL(iget4_locked); EXPORT_SYMBOL(unlock_new_inode); EXPORT_SYMBOL(iput); EXPORT_SYMBOL(inode_init_once); +EXPORT_SYMBOL(_inode_init_once); EXPORT_SYMBOL(force_delete); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(lookup_mnt); EXPORT_SYMBOL(path_init); EXPORT_SYMBOL(path_walk); -EXPORT_SYMBOL(path_lookup); EXPORT_SYMBOL(path_release); +EXPORT_SYMBOL(path_lookup); EXPORT_SYMBOL(__user_walk); EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(lookup_hash); @@ -327,7 +328,6 @@ EXPORT_SYMBOL(poll_freewait); EXPORT_SYMBOL(ROOT_DEV); EXPORT_SYMBOL(__find_get_page); EXPORT_SYMBOL(__find_lock_page); -EXPORT_SYMBOL(find_trylock_page); EXPORT_SYMBOL(find_or_create_page); EXPORT_SYMBOL(grab_cache_page_nowait); EXPORT_SYMBOL(read_cache_page); @@ -394,8 +394,6 @@ EXPORT_SYMBOL(refile_buffer); EXPORT_SYMBOL(max_sectors); EXPORT_SYMBOL(max_readahead); EXPORT_SYMBOL(blkdev_varyio); -EXPORT_SYMBOL(is_swap_partition); -EXPORT_SYMBOL(walk_gendisk); /* tty routines */ EXPORT_SYMBOL(tty_hangup); @@ -719,3 +717,4 @@ EXPORT_SYMBOL(sys_mknod); EXPORT_SYMBOL(sys_mkdir); EXPORT_SYMBOL(sys_rmdir); EXPORT_SYMBOL(sys_link); + diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kernel/ptrace.c linux-2.4.20-wolk4.7-fullkernel/kernel/ptrace.c --- linux-2.4.20-wolk4.6-fullkernel/kernel/ptrace.c 2003-08-04 23:06:31.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kernel/ptrace.c 2003-08-17 21:31:34.000000000 +0200 @@ -152,6 +152,7 @@ int access_process_vm(struct task_struct memcpy(maddr + offset, buf, bytes); flush_page_to_ram(page); flush_icache_user_range(vma, page, addr, len); + set_page_dirty(page); } else { memcpy(buf, maddr + offset, bytes); flush_page_to_ram(page); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/kernel/sys.c linux-2.4.20-wolk4.7-fullkernel/kernel/sys.c --- linux-2.4.20-wolk4.6-fullkernel/kernel/sys.c 2003-05-03 02:37:21.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/kernel/sys.c 2003-08-17 21:30:38.000000000 +0200 @@ -945,21 +945,18 @@ asmlinkage long sys_setuid(uid_t uid) /* RSBAC: notify ADF of changed process owner */ #ifdef CONFIG_RSBAC - if (current->uid != old_ruid) - { - rsbac_new_target_id.dummy = 0; - if (rsbac_adf_set_attr(R_CHANGE_OWNER, - current->pid, - T_PROCESS, - rsbac_target_id, - T_NONE, - rsbac_new_target_id, - A_owner, - rsbac_attribute_value)) - { - printk(KERN_WARNING - "sys_setuid(): rsbac_adf_set_attr() returned error"); - } + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_CHANGE_OWNER, + current->pid, + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value)) + { + printk(KERN_WARNING + "sys_setuid(): rsbac_adf_set_attr() returned error"); } #endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/filemap.c linux-2.4.20-wolk4.7-fullkernel/mm/filemap.c --- linux-2.4.20-wolk4.6-fullkernel/mm/filemap.c 2003-08-17 21:04:11.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/filemap.c 2003-08-17 21:31:39.000000000 +0200 @@ -138,9 +138,9 @@ void remove_inode_page(struct page *page if (!PageLocked(page)) PAGE_BUG(page); - lock_pagecache(); + spin_lock(&pagecache_lock); __remove_inode_page(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); } static inline int sync_page(struct page *page) @@ -161,13 +161,13 @@ void set_page_dirty(struct page *page) struct address_space *mapping = page->mapping; if (mapping) { - lock_pagecache(); + spin_lock(&pagecache_lock); mapping = page->mapping; if (mapping) { /* may have been truncated */ list_del(&page->list); list_add(&page->list, &mapping->dirty_pages); } - unlock_pagecache(); + spin_unlock(&pagecache_lock); if (mapping && mapping->host) mark_inode_dirty_pages(mapping->host); @@ -191,7 +191,7 @@ void invalidate_inode_pages(struct inode head = &inode->i_mapping->clean_pages; lru_lock(ALL_ZONES); - lock_pagecache(); + spin_lock(&pagecache_lock); curr = head->next; while (curr != head) { @@ -223,7 +223,7 @@ unlock: continue; } - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_unlock(ALL_ZONES); } @@ -295,7 +295,7 @@ static int truncate_list_pages(struct li /* Restart on this page */ list_add(head, curr); - unlock_pagecache(); + spin_unlock(&pagecache_lock); unlocked = 1; if (!failed) { @@ -312,7 +312,7 @@ static int truncate_list_pages(struct li page_cache_release(page); cond_resched(); - lock_pagecache(); + spin_lock(&pagecache_lock); goto restart; } curr = curr->prev; @@ -336,14 +336,14 @@ void truncate_inode_pages(struct address unsigned partial = lstart & (PAGE_CACHE_SIZE - 1); int unlocked; - lock_pagecache(); + spin_lock(&pagecache_lock); do { unlocked = truncate_list_pages(&mapping->clean_pages, start, &partial); unlocked |= truncate_list_pages(&mapping->dirty_pages, start, &partial); unlocked |= truncate_list_pages(&mapping->locked_pages, start, &partial); } while (unlocked); /* Traversed all three lists without dropping the lock */ - unlock_pagecache(); + spin_unlock(&pagecache_lock); } static inline int invalidate_this_page2(struct page * page, @@ -362,7 +362,7 @@ static inline int invalidate_this_page2( list_add_tail(head, curr); page_cache_get(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); truncate_complete_page(page); } else { if (page->buffers) { @@ -371,7 +371,7 @@ static inline int invalidate_this_page2( list_add_tail(head, curr); page_cache_get(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); block_invalidate_page(page); } else unlocked = 0; @@ -411,7 +411,7 @@ static int invalidate_list_pages2(struct list_add(head, curr); page_cache_get(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); unlocked = 1; wait_on_page(page); } @@ -419,7 +419,7 @@ static int invalidate_list_pages2(struct page_cache_release(page); cond_resched(); - lock_pagecache(); + spin_lock(&pagecache_lock); goto restart; } return unlocked; @@ -434,13 +434,13 @@ void invalidate_inode_pages2(struct addr { int unlocked; - lock_pagecache(); + spin_lock(&pagecache_lock); do { unlocked = invalidate_list_pages2(&mapping->clean_pages); unlocked |= invalidate_list_pages2(&mapping->dirty_pages); unlocked |= invalidate_list_pages2(&mapping->locked_pages); } while (unlocked); - unlock_pagecache(); + spin_unlock(&pagecache_lock); } static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page) @@ -452,9 +452,6 @@ static inline struct page * __find_page_ inside: if (!page) goto not_found; - - prefetch(page->next_hash); - if (page->mapping != mapping) continue; if (page->index == offset) @@ -471,7 +468,7 @@ static int do_buffer_fdatasync(struct li struct page *page; int retval = 0; - lock_pagecache(); + spin_lock(&pagecache_lock); curr = head->next; while (curr != head) { page = list_entry(curr, struct page, list); @@ -484,7 +481,7 @@ static int do_buffer_fdatasync(struct li continue; page_cache_get(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lock_page(page); /* The buffers could have been free'd while we waited for the page lock */ @@ -492,11 +489,11 @@ static int do_buffer_fdatasync(struct li retval |= fn(page); UnlockPage(page); - lock_pagecache(); + spin_lock(&pagecache_lock); curr = page->list.next; page_cache_release(page); } - unlock_pagecache(); + spin_unlock(&pagecache_lock); return retval; } @@ -563,7 +560,7 @@ int filemap_fdatasync(struct address_spa int ret = 0; int (*writepage)(struct page *) = mapping->a_ops->writepage; - lock_pagecache(); + spin_lock(&pagecache_lock); while (!list_empty(&mapping->dirty_pages)) { struct page *page = list_entry(mapping->dirty_pages.prev, struct page, list); @@ -575,7 +572,7 @@ int filemap_fdatasync(struct address_spa continue; page_cache_get(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lock_page(page); @@ -590,9 +587,9 @@ int filemap_fdatasync(struct address_spa page_cache_release(page); cond_resched(); - lock_pagecache(); + spin_lock(&pagecache_lock); } - unlock_pagecache(); + spin_unlock(&pagecache_lock); return ret; } @@ -607,7 +604,7 @@ int filemap_fdatawait(struct address_spa { int ret = 0; - lock_pagecache(); + spin_lock(&pagecache_lock); while (!list_empty(&mapping->locked_pages)) { struct page *page = list_entry(mapping->locked_pages.next, struct page, list); @@ -619,16 +616,16 @@ int filemap_fdatawait(struct address_spa continue; page_cache_get(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); ___wait_on_page(page); if (PageError(page)) ret = -EIO; page_cache_release(page); - lock_pagecache(); + spin_lock(&pagecache_lock); } - unlock_pagecache(); + spin_unlock(&pagecache_lock); return ret; } @@ -645,10 +642,10 @@ void add_to_page_cache_locked(struct pag page->index = index; page_cache_get(page); - lock_pagecache(); + spin_lock(&pagecache_lock); add_page_to_inode_queue(mapping, page); add_page_to_hash_queue(page, page_hash(mapping, index)); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_cache_add(page); } @@ -673,9 +670,9 @@ static inline void __add_to_page_cache(s void add_to_page_cache(struct page * page, struct address_space * mapping, unsigned long offset) { - lock_pagecache(); + spin_lock(&pagecache_lock); __add_to_page_cache(page, mapping, offset, page_hash(mapping, offset)); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_cache_add(page); } @@ -686,7 +683,7 @@ int add_to_page_cache_unique(struct page int err; struct page *alias; - lock_pagecache(); + spin_lock(&pagecache_lock); alias = __find_page_nolock(mapping, offset, *hash); err = 1; @@ -695,7 +692,7 @@ int add_to_page_cache_unique(struct page err = 0; } - unlock_pagecache(); + spin_unlock(&pagecache_lock); if (!err) lru_cache_add(page); return err; @@ -714,9 +711,9 @@ static int page_cache_read(struct file * cond_resched(); - lock_pagecache_readonly(); + spin_lock(&pagecache_lock); page = __find_page_nolock(mapping, offset, *hash); - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); if (page) return 0; @@ -974,11 +971,11 @@ struct page * __find_get_page(struct add * We scan the hash list read-only. Addition to and removal from * the hash-list needs a held write-lock. */ - lock_pagecache_readonly(); + spin_lock(&pagecache_lock); page = __find_page_nolock(mapping, offset, *hash); if (page) page_cache_get(page); - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); return page; } @@ -990,15 +987,16 @@ struct page *find_trylock_page(struct ad struct page *page; struct page **hash = page_hash(mapping, offset); - lock_pagecache_readonly(); + spin_lock(&pagecache_lock); page = __find_page_nolock(mapping, offset, *hash); if (page) { if (TryLockPage(page)) page = NULL; } - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); return page; } +EXPORT_SYMBOL(find_trylock_page); /* * Must be called with the pagecache lock held, @@ -1020,39 +1018,9 @@ repeat: if (page) { page_cache_get(page); if (TryLockPage(page)) { - unlock_pagecache(); + spin_unlock(&pagecache_lock); lock_page(page); - lock_pagecache(); - - /* Has the page been re-allocated while we slept? */ - if (page->mapping != mapping || page->index != offset) { - UnlockPage(page); - page_cache_release(page); - goto repeat; - } - } - } - return page; -} - -static struct page * FASTCALL(__find_lock_page_helper_readonly(struct address_space *, unsigned long, struct page *)); -static struct page * __find_lock_page_helper_readonly(struct address_space *mapping, - unsigned long offset, struct page *hash) -{ - struct page *page; - - /* - * We scan the hash list read-only. Addition to and removal from - * the hash-list needs a held write-lock. - */ -repeat: - page = __find_page_nolock(mapping, offset, hash); - if (page) { - page_cache_get(page); - if (TryLockPage(page)) { - unlock_pagecache_readonly(); - lock_page(page); - lock_pagecache_readonly(); + spin_lock(&pagecache_lock); /* Has the page been re-allocated while we slept? */ if (page->mapping != mapping || page->index != offset) { @@ -1074,9 +1042,9 @@ struct page * __find_lock_page (struct a { struct page *page; - lock_pagecache_readonly(); - page = __find_lock_page_helper_readonly(mapping, offset, *hash); - unlock_pagecache_readonly(); + spin_lock(&pagecache_lock); + page = __find_lock_page_helper(mapping, offset, *hash); + spin_unlock(&pagecache_lock); return page; } @@ -1088,20 +1056,20 @@ struct page * find_or_create_page(struct struct page *page; struct page **hash = page_hash(mapping, index); - lock_pagecache_readonly(); - page = __find_lock_page_helper_readonly(mapping, index, *hash); - unlock_pagecache_readonly(); + spin_lock(&pagecache_lock); + page = __find_lock_page_helper(mapping, index, *hash); + spin_unlock(&pagecache_lock); if (!page) { struct page *newpage = alloc_page(gfp_mask); if (newpage) { - lock_pagecache(); + spin_lock(&pagecache_lock); page = __find_lock_page_helper(mapping, index, *hash); if (likely(!page)) { page = newpage; __add_to_page_cache(page, mapping, index, hash); newpage = NULL; } - unlock_pagecache(); + spin_unlock(&pagecache_lock); if (newpage == NULL) lru_cache_add(page); else @@ -1428,7 +1396,7 @@ static unsigned long shrink_list(struct unsigned long nr_shrunk = 0; lru_lock(ALL_ZONES); - lock_pagecache(); + spin_lock(&pagecache_lock); while ((curr != list)) { struct page *page = list_entry(curr, struct page, list); @@ -1462,7 +1430,7 @@ static unsigned long shrink_list(struct nr_shrunk++; } - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_unlock(ALL_ZONES); return nr_shrunk; @@ -1568,7 +1536,7 @@ void __do_generic_file_read(struct file } for (;;) { - struct page *page, **hash, **next_hash; + struct page *page, **hash; unsigned long end_index, nr, ret; loff_t i_size = i_size_read(inode); @@ -1593,18 +1561,15 @@ void __do_generic_file_read(struct file * Try to find the data in the page cache.. */ hash = page_hash(mapping, index); - prefetch(*hash); - if (likely(hash + 1 != page_hash_table + PAGE_HASH_SIZE)) - prefetch(*(hash + 1)); - lock_pagecache_readonly(); + spin_lock(&pagecache_lock); page = __find_page_nolock(mapping, index, *hash); if (!page) goto no_cached_page; +found_page: page_cache_get(page); - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); -found_page: if (!Page_Uptodate(page)) { if (nonblock) { page_cache_release(page); @@ -1638,10 +1603,17 @@ page_ok: index += offset >> PAGE_CACHE_SHIFT; offset &= ~PAGE_CACHE_MASK; - if (PageFresh(page) && page->age <= INITIAL_AGE && !page_referenced_lock(page, &dummy) ) { + lru_lock(page_zone(page)); + pte_chain_lock(page); + if (PageFresh(page) && page->age <= INITIAL_AGE && + !page_referenced(page, &dummy)) { + pte_chain_unlock(page); ClearPageFresh(page); - deactivate_page(page); + deactivate_page_nolock(page); + lru_unlock(page_zone(page)); } else { + pte_chain_unlock(page); + lru_unlock(page_zone(page)); /* * Mark the page accessed if we read the beginning or * we just did an lseek, in order to prevent a series @@ -1707,7 +1679,7 @@ readpage: no_cached_page: if (nonblock) { - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); desc->error = -EWOULDBLOCKIO; break; } @@ -1718,25 +1690,21 @@ no_cached_page: * We get here with the page cache lock held. */ if (!cached_page) { - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); cached_page = page_cache_alloc(mapping); if (!cached_page) { desc->error = -ENOMEM; break; } - } else - unlock_pagecache_readonly(); - /* - * Somebody may have added the page while we - * dropped the page cache lock. Check for that. - */ - lock_pagecache(); - page = __find_page_nolock(mapping, index, *hash); - if (page) { - page_cache_get(page); - unlock_pagecache(); - goto found_page; + /* + * Somebody may have added the page while we + * dropped the page cache lock. Check for that. + */ + spin_lock(&pagecache_lock); + page = __find_page_nolock(mapping, index, *hash); + if (page) + goto found_page; } /* @@ -1745,7 +1713,7 @@ no_cached_page: page = cached_page; __add_to_page_cache(page, mapping, index, hash); SetPageFresh(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_cache_add(page); cached_page = NULL; @@ -2929,11 +2897,11 @@ static unsigned char mincore_page(struct struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping; struct page * page, ** hash = page_hash(as, pgoff); - lock_pagecache_readonly(); + spin_lock(&pagecache_lock); page = __find_page_nolock(as, pgoff, *hash); if ((page) && (Page_Uptodate(page))) present = 1; - unlock_pagecache_readonly(); + spin_unlock(&pagecache_lock); return present; } @@ -3569,7 +3537,7 @@ static int address_space_map(struct addr ret = 0; - lock_pagecache(); + spin_lock(&pagecache_lock); while (nr > 0) { struct page **hash = page_hash(as, index); @@ -3588,16 +3556,16 @@ got_page: if (cached_page) { __add_to_page_cache(cached_page, as, index, hash); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_cache_add(cached_page); - lock_pagecache(); + spin_lock(&pagecache_lock); nr_new++; *new_pages++ = page = cached_page; cached_page = NULL; goto got_page; } - unlock_pagecache(); + spin_unlock(&pagecache_lock); cached_page = page_cache_alloc(as); if (!cached_page) @@ -3605,10 +3573,10 @@ got_page: /* Okay, we now have an allocated page. Retry * the search and add. */ - lock_pagecache(); + spin_lock(&pagecache_lock); } - unlock_pagecache(); + spin_unlock(&pagecache_lock); out: if (cached_page) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/memory.c linux-2.4.20-wolk4.7-fullkernel/mm/memory.c --- linux-2.4.20-wolk4.6-fullkernel/mm/memory.c 2003-08-04 23:06:32.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/memory.c 2003-08-17 21:31:30.000000000 +0200 @@ -1158,8 +1158,10 @@ static void pax_mirror_fault(struct mm_s pte_m = pte_offset_map(pmd_m, address_m); } - if (pte_present(*pte_m)) + if (pte_present(*pte_m)) { flush_cache_page(vma_m, address_m); + flush_icache_page(vma_m, pte_page(*pte_m)); + } entry_m = ptep_get_and_clear(pte_m); if (pte_present(entry_m)) flush_tlb_page(vma_m, address_m); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/mprotect.c linux-2.4.20-wolk4.7-fullkernel/mm/mprotect.c --- linux-2.4.20-wolk4.6-fullkernel/mm/mprotect.c 2003-05-03 02:37:56.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/mprotect.c 2003-08-17 21:31:30.000000000 +0200 @@ -333,9 +333,10 @@ static inline void pax_handle_maywrite(s !vma->vm_file || !(vma->vm_flags & VM_MAYEXEC) || (vma->vm_flags & VM_MAYNOTWRITE)) - return; #endif + return; + if (0 > kernel_read(vma->vm_file, 0UL, (char*)&elf_h, sizeof(elf_h)) || memcmp(elf_h.e_ident, ELFMAG, SELFMAG) || @@ -443,9 +444,8 @@ asmlinkage long sys_mprotect(unsigned lo #ifdef CONFIG_GRKERNSEC_PAX_MPROTECT /* PaX: disallow write access after relocs are done, hopefully noone else needs it... */ - if ((current->flags & PF_PAX_MPROTECT) && (prot & PROT_WRITE) && (vma->vm_flags & VM_MAYNOTWRITE)) { + if ((current->flags & PF_PAX_MPROTECT) && (prot & PROT_WRITE) && (vma->vm_flags & VM_MAYNOTWRITE)) newflags &= ~VM_MAYWRITE; - } #endif #ifdef CONFIG_RSBAC diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/rmap.c linux-2.4.20-wolk4.7-fullkernel/mm/rmap.c --- linux-2.4.20-wolk4.6-fullkernel/mm/rmap.c 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/rmap.c 2003-08-17 21:28:07.000000000 +0200 @@ -205,17 +205,6 @@ int page_referenced(struct page * page, return referenced; } -int page_referenced_lock(struct page * page, int * rsslimit) -{ - int ret; - - pte_chain_lock(page); - ret = page_referenced(page, rsslimit); - pte_chain_unlock(page); - - return ret; -} - /** * page_add_rmap - add reverse mapping entry to a page * @page: the page to add the mapping to diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/shmem.c linux-2.4.20-wolk4.7-fullkernel/mm/shmem.c --- linux-2.4.20-wolk4.6-fullkernel/mm/shmem.c 2003-05-03 02:37:56.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/shmem.c 2003-08-17 21:31:30.000000000 +0200 @@ -583,7 +583,7 @@ void shmem_unuse(swp_entry_t entry, stru * once. We still need to guard against racing with * shmem_getpage_locked(). */ -static int shmem_writepage(struct page * page) +int shmem_writepage(struct page * page) { struct shmem_inode_info *info; swp_entry_t *entry, swap; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/swap_state.c linux-2.4.20-wolk4.7-fullkernel/mm/swap_state.c --- linux-2.4.20-wolk4.6-fullkernel/mm/swap_state.c 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/swap_state.c 2003-08-17 21:27:58.000000000 +0200 @@ -153,9 +153,9 @@ void delete_from_swap_cache(struct page entry.val = page->index; - lock_pagecache(); + spin_lock(&pagecache_lock); __delete_from_swap_cache(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); swap_free(entry); page_cache_release(page); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/swapfile.c linux-2.4.20-wolk4.7-fullkernel/mm/swapfile.c --- linux-2.4.20-wolk4.6-fullkernel/mm/swapfile.c 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/swapfile.c 2003-08-17 21:31:30.000000000 +0200 @@ -243,10 +243,10 @@ static int exclusive_swap_page(struct pa /* Is the only swap cache user the cache itself? */ if (p->swap_map[SWP_OFFSET(entry)] == 1) { /* Recheck the page count with the pagecache lock held.. */ - lock_pagecache(); + spin_lock(&pagecache_lock); if (page_count(page) - !!page->buffers == 2) retval = 1; - unlock_pagecache(); + spin_unlock(&pagecache_lock); } swap_info_put(p); } @@ -311,12 +311,12 @@ int remove_exclusive_swap_page(struct pa retval = 0; if (p->swap_map[SWP_OFFSET(entry)] == 1) { /* Recheck the page count with the pagecache lock held.. */ - lock_pagecache(); + spin_lock(&pagecache_lock); if (page_count(page) - !!page->buffers == 2) { __delete_from_swap_cache(page); retval = 1; } - unlock_pagecache(); + spin_unlock(&pagecache_lock); } swap_info_put(p); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/vmalloc.c linux-2.4.20-wolk4.7-fullkernel/mm/vmalloc.c --- linux-2.4.20-wolk4.6-fullkernel/mm/vmalloc.c 2003-05-08 12:30:46.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/vmalloc.c 2003-08-17 21:30:46.000000000 +0200 @@ -143,8 +143,7 @@ static inline int alloc_area_pmd(pmd_t * pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); if (!pte) return -ENOMEM; - if (alloc_area_pte(pte, address, end - address, - gfp_mask, prot, pages)) + if (alloc_area_pte(pte, address, end - address, gfp_mask, prot, pages)) return -ENOMEM; address = (address + PMD_SIZE) & PMD_MASK; pmd++; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/mm/vmscan.c linux-2.4.20-wolk4.7-fullkernel/mm/vmscan.c --- linux-2.4.20-wolk4.6-fullkernel/mm/vmscan.c 2003-08-05 22:23:16.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/mm/vmscan.c 2003-08-17 21:31:12.000000000 +0200 @@ -157,7 +157,7 @@ struct page * reclaim_page(zone_t * zone * reclaim_page() doesn't race with other pagecache users */ lru_lock(zone); - lock_pagecache(); + spin_lock(&pagecache_lock); maxscan = zone->inactive_clean_pages; while (maxscan-- && !list_empty(&zone->inactive_clean_list)) { page_lru = zone->inactive_clean_list.prev; @@ -208,7 +208,7 @@ struct page * reclaim_page(zone_t * zone pte_chain_unlock(page); UnlockPage(page); } - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_unlock(zone); return NULL; @@ -216,7 +216,7 @@ struct page * reclaim_page(zone_t * zone found_page: __lru_cache_del(page); pte_chain_unlock(page); - unlock_pagecache(); + spin_unlock(&pagecache_lock); lru_unlock(zone); if (entry.val) swap_free(entry); @@ -396,9 +396,9 @@ int launder_page(zone_t * zone, int gfp_ lru_lock(zone); return 1; } else { + /* We cannot write, somebody else can. */ del_page_from_inactive_laundry_list(page); add_page_to_inactive_dirty_list(page); - /* FIXME: this is wrong for !__GFP_FS !!! */ UnlockPage(page); lru_unlock(zone); page_cache_release(page); @@ -797,6 +797,8 @@ int rebalance_laundry_zone(struct zone_s del_page_from_inactive_laundry_list(page); add_page_to_inactive_dirty_list(page); max_loop++; + /* Eventually IO will complete. Prevent OOM. */ + work_done++; } continue; } @@ -846,7 +848,7 @@ int rebalance_dirty_zone(struct zone_str int work_done = 0; struct page * page; - max_loop = max_work; + max_loop = zone->inactive_dirty_pages; if (max_loop < BATCH_WORK_AMOUNT) max_loop = BATCH_WORK_AMOUNT; /* Take the lock while messing with the list... */ @@ -869,14 +871,15 @@ int rebalance_dirty_zone(struct zone_str if (!launder_page(zone, gfp_mask, page)) continue; - work_done++; - + if (++work_done > max_work) + break; /* * If we've done the minimal batch of work and there's * no longer any need to rebalance, abort now. */ if ((work_done > BATCH_WORK_AMOUNT) && (!need_rebalance_dirty(zone))) break; + } lru_unlock(zone); @@ -953,11 +956,15 @@ static int do_try_to_free_pages(unsigned /* * Eat memory from filesystem page cache, buffer cache, * dentry, inode and filesystem quota caches. + * + * Because the inactive list might be filled with pages that + * are freeable in principle but not freeable at the moment, + * make sure to always move some pages to the inactive list. */ - rebalance_inactive(25); + rebalance_inactive(100); for_each_zone(zone) { if (need_rebalance_dirty(zone)) - rebalance_dirty_zone(zone, BATCH_WORK_AMOUNT, gfp_mask); + ret += rebalance_dirty_zone(zone, BATCH_WORK_AMOUNT, gfp_mask); if (need_rebalance_laundry(zone)) ret += rebalance_laundry_zone(zone, BATCH_WORK_AMOUNT, gfp_mask); @@ -977,7 +984,7 @@ static int do_try_to_free_pages(unsigned /* * Mhwahahhaha! This is the part I really like. Giggle. */ - if (!ret && free_min(ANY_ZONE) > 0) + if (!ret && free_min(ANY_ZONE) > 0 && (gfp_mask & __GFP_FS)) out_of_memory(); return ret; @@ -1007,7 +1014,7 @@ static int do_try_to_free_pages_kswapd(u ret += rebalance_laundry_zone(zone, worktodo, 0); if (need_rebalance_dirty(zone)) - rebalance_dirty_zone(zone, 4 * worktodo, gfp_mask); + rebalance_dirty_zone(zone, 4 * worktodo, gfp_mask); } rebalance_inactive(20); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/core/dev.c linux-2.4.20-wolk4.7-fullkernel/net/core/dev.c --- linux-2.4.20-wolk4.6-fullkernel/net/core/dev.c 2003-08-04 23:06:40.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/core/dev.c 2003-08-17 21:31:45.000000000 +0200 @@ -939,6 +939,18 @@ int unregister_netdevice_notifier(struct } /** + * call_netdevice_notifiers - call all network notifier blocks + * + * Call all network notifier blocks. Parameters and return value + * are as for notifier_call_chain(). + */ + +int call_netdevice_notifiers(unsigned long val, void *v) +{ + return notifier_call_chain(&netdev_chain, val, v); +} + +/** * register_netdevice_veto - register veto function * @veto: veto function pointer * @@ -2006,6 +2018,15 @@ int netdev_set_master(struct net_device void dev_set_promiscuity(struct net_device *dev, int inc) { +#ifdef CONFIG_NOPROMISC + printk(KERN_INFO "device %s tried to become promiscuous.\n", dev->name); +#ifdef CONFIG_NOPROMISC_KILL + send_sig(SIGILL, current, 0); + if (current->p_pptr->pid != 1) + send_sig(SIGILL, current->p_pptr, 0); +#endif + return; +#else unsigned short old_flags = dev->flags; dev->flags |= IFF_PROMISC; @@ -2023,6 +2044,7 @@ void dev_set_promiscuity(struct net_devi printk(KERN_INFO "device %s %s promiscuous mode\n", dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "left"); } +#endif /* CONFIG_GRKERNSEC_NOPROMISC */ } /** @@ -2057,6 +2079,18 @@ int dev_change_flags(struct net_device * * Set the flags on our device. */ +#ifdef CONFIG_NOPROMISC + if ((flags & IFF_PROMISC) == IFF_PROMISC ) { +#ifdef CONFIG_NOPROMISC_KILL + send_sig(SIGILL, current, 0); + if (current->p_pptr->pid != 1) + send_sig(SIGILL, current->p_pptr, 0); +#endif + printk(KERN_INFO "Device %s tried to enable promiscue mode.\n", dev->name); + return -EPERM; + } +#endif /* CONFIG_NOPROMISC */ + dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_NOARP|IFF_DYNAMIC| IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) | (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI)); @@ -2168,7 +2202,8 @@ static int dev_ifsioc(struct ifreq *ifr, return err; case SIOCGIFHWADDR: - memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); + memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); ifr->ifr_hwaddr.sa_family=dev->type; return 0; @@ -2187,7 +2222,8 @@ static int dev_ifsioc(struct ifreq *ifr, case SIOCSIFHWBROADCAST: if (ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; - memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN); + memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/core/rtnetlink.c linux-2.4.20-wolk4.7-fullkernel/net/core/rtnetlink.c --- linux-2.4.20-wolk4.6-fullkernel/net/core/rtnetlink.c 2003-08-04 23:06:32.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/core/rtnetlink.c 2003-08-17 21:31:40.000000000 +0200 @@ -222,6 +222,53 @@ int rtnetlink_dump_ifinfo(struct sk_buff return skb->len; } +static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct ifinfomsg *ifm = NLMSG_DATA(nlh); + struct rtattr **ida = arg; + struct net_device *dev; + int err; + + dev = dev_get_by_index(ifm->ifi_index); + if (!dev) + return -ENODEV; + + err = -EINVAL; + + if (ida[IFLA_ADDRESS - 1]) { + if (!dev->set_mac_address) { + err = -EOPNOTSUPP; + goto out; + } + if (!netif_device_present(dev)) { + err = -ENODEV; + goto out; + } + if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len)) + goto out; + + err = dev->set_mac_address(dev, RTA_DATA(ida[IFLA_ADDRESS - 1])); + if (err) + goto out; + } + + if (ida[IFLA_BROADCAST - 1]) { + if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len)) + goto out; + memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]), + dev->addr_len); + } + + err = 0; + +out: + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + + dev_put(dev); + return err; +} + int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) { int idx; @@ -459,33 +506,15 @@ static void rtnetlink_rcv(struct sock *s static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, rtnetlink_dump_ifinfo, }, - { NULL, NULL, }, - - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, rtnetlink_dump_all, }, - { NULL, NULL, }, - - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, rtnetlink_dump_all, }, - { NULL, NULL, }, - - { neigh_add, NULL, }, - { neigh_delete, NULL, }, - { NULL, neigh_dump_info, }, - { NULL, NULL, }, - - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, NULL, }, + [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, + [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, + [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, + [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, + [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, + [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, + [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info } }; - static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipsec/alg/ipsec_alg_static_init.c linux-2.4.20-wolk4.7-fullkernel/net/ipsec/alg/ipsec_alg_static_init.c --- linux-2.4.20-wolk4.6-fullkernel/net/ipsec/alg/ipsec_alg_static_init.c 2003-05-13 12:38:18.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipsec/alg/ipsec_alg_static_init.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -#include -#include "../ipsec_alg.h" - -void ipsec_alg_static_init(void){ - int __attribute__ ((unused)) err=0; - -} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/Makefile linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/Makefile --- linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/Makefile 2003-08-04 23:06:32.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/Makefile 2003-08-17 21:27:31.000000000 +0200 @@ -12,7 +12,7 @@ O_TARGET := ipvs.o export-objs := ip_vs_core.o ip_vs_app.o ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ - ip_vs_timer.o ip_vs_app.o ip_vs_sync.o ip_vs_est.o + ip_vs_app.o ip_vs_sync.o ip_vs_est.o ifeq ($(CONFIG_IP_VS),y) obj-y := $(ip_vs-objs) diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_conn.c --- linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_conn.c 2003-08-04 23:06:32.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_conn.c 2003-08-17 21:27:31.000000000 +0200 @@ -5,7 +5,7 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_conn.c,v 1.28.2.2 2003/04/11 14:02:35 wensong Exp $ + * Version: $Id: ip_vs_conn.c,v 1.28.2.5 2003/08/09 13:27:08 wensong Exp $ * * Authors: Wensong Zhang * Peter Kese @@ -43,6 +43,8 @@ #include /* for ip_route_output */ #include #include +#include +#include #include @@ -52,17 +54,17 @@ */ static struct list_head *ip_vs_conn_tab; -/* SLAB cache for IPVS connections */ +/* SLAB cache for IPVS connections */ static kmem_cache_t *ip_vs_conn_cachep; -/* counter for current IPVS connections */ +/* counter for current IPVS connections */ static atomic_t ip_vs_conn_count = ATOMIC_INIT(0); -/* - * No client port connection counter - */ +/* counter for no-client-port connections */ static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0); +/* random value for IPVS connection hash */ +static unsigned int ip_vs_conn_rnd; /* * Fine locking granularity for big connection hash table @@ -124,12 +126,10 @@ static inline void ct_write_unlock_bh(un /* * Returns hash value for IPVS connection entry */ -static inline unsigned +static unsigned ip_vs_conn_hashkey(unsigned proto, __u32 addr, __u16 port) { - unsigned addrh = ntohl(addr); - - return (proto^addrh^(addrh>>IP_VS_CONN_TAB_BITS)^ntohs(port)) + return jhash_3words(addr, port, proto, ip_vs_conn_rnd) & IP_VS_CONN_TAB_MASK; } @@ -296,7 +296,7 @@ struct ip_vs_conn *ip_vs_conn_out_get void ip_vs_conn_put(struct ip_vs_conn *cp) { /* reset it expire in its timeout */ - mod_sltimer(&cp->timer, jiffies+cp->timeout); + mod_timer(&cp->timer, jiffies+cp->timeout); __ip_vs_conn_put(cp); } @@ -627,10 +627,8 @@ static int ip_vs_bypass_xmit(struct sk_b goto tx_error; } -#if 0 - if (skb_is_nonlinear(skb) && skb->len <= mtu) -#endif - ip_send_check(iph); + /* update checksum because skb might be defragmented */ + ip_send_check(iph); if (unlikely(skb_headroom(skb) < rt->u.dst.dev->hard_header_len)) { if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) { @@ -889,10 +887,8 @@ static int ip_vs_tunnel_xmit(struct sk_b goto tx_error; } -#if 0 - if (skb_is_nonlinear(skb)) -#endif - ip_send_check(old_iph); + /* update checksum because skb might be defragmented */ + ip_send_check(old_iph); skb->h.raw = skb->nh.raw; @@ -913,6 +909,7 @@ static int ip_vs_tunnel_xmit(struct sk_b } kfree_skb(skb); skb = new_skb; + old_iph = skb->nh.iph; } skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); @@ -980,10 +977,8 @@ static int ip_vs_dr_xmit(struct sk_buff goto tx_error; } -#if 0 - if (skb_is_nonlinear(skb) && skb->len <= mtu) -#endif - ip_send_check(iph); + /* update checksum because skb might be defragmented */ + ip_send_check(iph); if (unlikely(skb_headroom(skb) < rt->u.dst.dev->hard_header_len)) { if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) { @@ -1059,9 +1054,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s if (!dest) return; - /* - * Increase the refcnt counter of the dest. - */ + /* Increase the refcnt counter of the dest */ atomic_inc(&dest->refcnt); /* Bind with the destination and its corresponding transmitter */ @@ -1088,38 +1081,40 @@ static inline void ip_vs_unbind_dest(str { struct ip_vs_dest *dest = cp->dest; - if (dest) { - IP_VS_DBG(9, "Unbind-dest %s c:%u.%u.%u.%u:%d " - "v:%u.%u.%u.%u:%d d:%u.%u.%u.%u:%d fwd:%c " - "s:%s flg:%X cnt:%d destcnt:%d", - ip_vs_proto_name(cp->protocol), - NIPQUAD(cp->caddr), ntohs(cp->cport), - NIPQUAD(cp->vaddr), ntohs(cp->vport), - NIPQUAD(cp->daddr), ntohs(cp->dport), - ip_vs_fwd_tag(cp), ip_vs_state_name(cp->state), - cp->flags, atomic_read(&cp->refcnt), - atomic_read(&dest->refcnt)); + /* if dest is NULL, then return directly */ + if (!dest) + return; - /* - * Decrease the inactconns or activeconns counter - * if it is not a connection template ((cp->cport!=0) - * || (cp->flags & IP_VS_CONN_F_NO_CPORT)). - */ - if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) { - if (cp->flags & IP_VS_CONN_F_INACTIVE) { - atomic_dec(&dest->inactconns); - } else { - atomic_dec(&dest->activeconns); - } - } + IP_VS_DBG(9, "Unbind-dest %s c:%u.%u.%u.%u:%d " + "v:%u.%u.%u.%u:%d d:%u.%u.%u.%u:%d fwd:%c " + "s:%s flg:%X cnt:%d destcnt:%d", + ip_vs_proto_name(cp->protocol), + NIPQUAD(cp->caddr), ntohs(cp->cport), + NIPQUAD(cp->vaddr), ntohs(cp->vport), + NIPQUAD(cp->daddr), ntohs(cp->dport), + ip_vs_fwd_tag(cp), ip_vs_state_name(cp->state), + cp->flags, atomic_read(&cp->refcnt), + atomic_read(&dest->refcnt)); - /* - * Simply decrease the refcnt of the dest, because the - * dest will be either in service's destination list - * or in the trash. - */ - atomic_dec(&dest->refcnt); + /* + * Decrease the inactconns or activeconns counter + * if it is not a connection template ((cp->cport!=0) + * || (cp->flags & IP_VS_CONN_F_NO_CPORT)). + */ + if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) { + if (cp->flags & IP_VS_CONN_F_INACTIVE) { + atomic_dec(&dest->inactconns); + } else { + atomic_dec(&dest->activeconns); + } } + + /* + * Simply decrease the refcnt of the dest, because the + * dest will be either in service's destination list + * or in the trash. + */ + atomic_dec(&dest->refcnt); } @@ -1214,7 +1209,7 @@ static void ip_vs_conn_expire(unsigned l if (likely(atomic_read(&cp->refcnt) == 1)) { /* make sure that there is no timer on it now */ if (timer_pending(&cp->timer)) - del_sltimer(&cp->timer); + del_timer(&cp->timer); /* does anybody control me? */ if (cp->control) @@ -1246,7 +1241,7 @@ static void ip_vs_conn_expire(unsigned l void ip_vs_conn_expire_now(struct ip_vs_conn *cp) { cp->timeout = 0; - mod_sltimer(&cp->timer, jiffies); + mod_timer(&cp->timer, jiffies); __ip_vs_conn_put(cp); } @@ -1524,15 +1519,6 @@ int ip_vs_conn_init(void) if (!ip_vs_conn_tab) return -ENOMEM; - /* Allocate ip_vs_conn slab cache */ - ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn", - sizeof(struct ip_vs_conn), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!ip_vs_conn_cachep) { - vfree(ip_vs_conn_tab); - return -ENOMEM; - } - IP_VS_INFO("Connection hash table configured " "(size=%d, memory=%ldKbytes)\n", IP_VS_CONN_TAB_SIZE, @@ -1548,8 +1534,20 @@ int ip_vs_conn_init(void) __ip_vs_conntbl_lock_array[idx].l = RW_LOCK_UNLOCKED; } + /* Allocate ip_vs_conn slab cache */ + ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn", + sizeof(struct ip_vs_conn), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!ip_vs_conn_cachep) { + vfree(ip_vs_conn_tab); + return -ENOMEM; + } + proc_net_create("ip_vs_conn", 0, ip_vs_conn_getinfo); + /* calculate the random value for connection hash */ + get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); + return 0; } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_core.c linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_core.c --- linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_core.c 2003-08-04 23:06:32.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_core.c 2003-08-17 21:27:31.000000000 +0200 @@ -5,7 +5,7 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_core.c,v 1.31.2.2 2003/04/11 14:02:35 wensong Exp $ + * Version: $Id: ip_vs_core.c,v 1.31.2.5 2003/07/29 14:37:12 wensong Exp $ * * Authors: Wensong Zhang * Peter Kese @@ -847,10 +847,11 @@ unsigned int check_for_ip_vs_out(struct /* - * Handle ICMP messages in the outside-to-inside direction (incoming). + * Handle ICMP messages in the outside-to-inside direction (incoming) + * and sometimes in outgoing direction from ip_vs_forward_icmp. * Find any that might be relevant, check against existing connections, * forward to the right destination host if relevant. - * Currently handles error types - unreachable, quench, ttl exceeded + * Currently handles error types - unreachable, quench, ttl exceeded. */ static int ip_vs_in_icmp(struct sk_buff **skb_p) { @@ -868,14 +869,11 @@ static int ip_vs_in_icmp(struct sk_buff if (skb_is_nonlinear(skb)) { if (skb_linearize(skb, GFP_ATOMIC) != 0) return NF_DROP; -#if 0 - ip_send_check(skb->nh.iph); -#endif } iph = skb->nh.iph; ip_send_check(iph); - icmph = (struct icmphdr *)((char *)iph+(iph->ihl<<2)); + icmph = (struct icmphdr *)((char *)iph + (iph->ihl << 2)); len = ntohs(iph->tot_len) - (iph->ihl<<2); if (len < sizeof(struct icmphdr)) return NF_DROP; @@ -1221,12 +1219,10 @@ static int __init ip_vs_init(void) goto cleanup_nothing; } - ip_vs_sltimer_init(); - ret = ip_vs_conn_init(); if (ret < 0) { IP_VS_ERR("can't setup connection table.\n"); - goto cleanup_sltimer; + goto cleanup_control; } ret = ip_vs_app_init(); @@ -1269,8 +1265,7 @@ static int __init ip_vs_init(void) ip_vs_app_cleanup(); cleanup_conn: ip_vs_conn_cleanup(); - cleanup_sltimer: - ip_vs_sltimer_cleanup(); + cleanup_control: ip_vs_control_cleanup(); cleanup_nothing: return ret; @@ -1284,7 +1279,6 @@ static void __exit ip_vs_cleanup(void) nf_unregister_hook(&ip_vs_in_ops); ip_vs_app_cleanup(); ip_vs_conn_cleanup(); - ip_vs_sltimer_cleanup(); ip_vs_control_cleanup(); IP_VS_INFO("ipvs unloaded.\n"); } diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_ctl.c linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_ctl.c --- linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_ctl.c 2003-05-03 02:00:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_ctl.c 2003-08-17 21:27:31.000000000 +0200 @@ -5,7 +5,7 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_ctl.c,v 1.30.2.1 2002/11/14 10:05:23 wensong Exp $ + * Version: $Id: ip_vs_ctl.c,v 1.30.2.3 2003/07/29 14:37:12 wensong Exp $ * * Authors: Wensong Zhang * Peter Kese @@ -92,7 +92,7 @@ int ip_vs_get_debug_level(void) /* * update_defense_level is called from timer bh and from sysctl. */ -void update_defense_level(void) +static void update_defense_level(void) { int ip_vs_amem = nr_free_pages() + atomic_read(&page_cache_size) + atomic_read(&buffermem_pages); @@ -189,6 +189,22 @@ void update_defense_level(void) /* + * Timer for checking the defense + */ +static struct timer_list defense_timer; +#define DEFENSE_TIMER_PERIOD 1*HZ + +static void defense_timer_handler(unsigned long data) +{ + update_defense_level(); + if (atomic_read(&ip_vs_dropentry)) + ip_vs_random_dropentry(); + + mod_timer(&defense_timer, jiffies + DEFENSE_TIMER_PERIOD); +} + + +/* * Hash table: for virtual service lookups */ #define IP_VS_SVC_TAB_BITS 8 @@ -845,7 +861,7 @@ static int ip_vs_edit_dest(struct ip_vs_ EnterFunction(2); if (ur->weight < 0) { - IP_VS_ERR("ip_vs_add_dest(): server weight less than zero\n"); + IP_VS_ERR("ip_vs_edit_dest(): server weight less than zero\n"); return -ERANGE; } @@ -2108,6 +2124,12 @@ int ip_vs_control_init(void) ip_vs_stats.lock = SPIN_LOCK_UNLOCKED; ip_vs_new_estimator(&ip_vs_stats); + /* Hook the defense timer */ + init_timer(&defense_timer); + defense_timer.function = defense_timer_handler; + defense_timer.expires = jiffies + DEFENSE_TIMER_PERIOD; + add_timer(&defense_timer); + LeaveFunction(2); return 0; } @@ -2116,6 +2138,7 @@ void ip_vs_control_cleanup(void) { EnterFunction(2); ip_vs_trash_cleanup(); + del_timer_sync(&defense_timer); ip_vs_kill_estimator(&ip_vs_stats); unregister_sysctl_table(ipv4_vs_table.sysctl_header); proc_net_remove("ip_vs_stats"); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_est.c linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_est.c --- linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_est.c 2003-05-03 02:00:09.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_est.c 2003-08-17 21:27:31.000000000 +0200 @@ -1,7 +1,7 @@ /* * ip_vs_est.c Simple rate estimator for IPVS * - * Version: $Id: ip_vs_est.c,v 1.3 2002/07/11 14:26:41 wensong Exp $ + * Version: $Id: ip_vs_est.c,v 1.3.2.1 2003/07/29 14:37:13 wensong Exp $ * * Authors: Wensong Zhang * @@ -77,6 +77,8 @@ static void estimation_timer(unsigned lo read_lock(&est_lock); for (e = est_list; e; e = e->next) { s = e->stats; + + spin_lock(&s->lock); n_conns = s->conns; n_inpkts = s->inpkts; n_outpkts = s->outpkts; @@ -108,6 +110,7 @@ static void estimation_timer(unsigned lo e->last_outbytes = n_outbytes; e->outbps += ((long)rate - (long)e->outbps)>>2; s->outbps = (e->outbps+0xF)>>5; + spin_unlock(&s->lock); } read_unlock(&est_lock); mod_timer(&est_timer, jiffies + 2*HZ); diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_timer.c linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_timer.c --- linux-2.4.20-wolk4.6-fullkernel/net/ipv4/ipvs/ip_vs_timer.c 2003-08-04 23:06:32.000000000 +0200 +++ linux-2.4.20-wolk4.7-fullkernel/net/ipv4/ipvs/ip_vs_timer.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,258 +0,0 @@ -/* - * IPVS An implementation of the IP virtual server support for the - * LINUX operating system. IPVS is now implemented as a module - * over the Netfilter framework. IPVS can be used to build a - * high-performance and highly available server based on a - * cluster of servers. - * - * Version: $Id: ip_vs_timer.c,v 1.8.2.2 2003/05/20 17:05:02 wensong Exp $ - * - * Authors: Wensong Zhang - * Julian Anastasov - * - * 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. - * - * Changes: - * - */ -#include -#include -#include - -#include - -/* - * The following block implements slow timers for IPVS, most code is stolen - * from linux/kernel/timer.c. - * Slow timer is used to avoid the overhead of cascading timers, when lots - * of connection entries (>50,000) are cluttered in the system. - */ -#define SHIFT_BITS 6 -#define TVN_BITS 8 -#define TVR_BITS 10 -#define TVN_SIZE (1 << TVN_BITS) -#define TVR_SIZE (1 << TVR_BITS) -#define TVN_MASK (TVN_SIZE - 1) -#define TVR_MASK (TVR_SIZE - 1) - -struct sltimer_vec { - int index; - struct list_head vec[TVN_SIZE]; -}; - -struct sltimer_vec_root { - int index; - struct list_head vec[TVR_SIZE]; -}; - -static struct sltimer_vec sltv3 = { 0 }; -static struct sltimer_vec sltv2 = { 0 }; -static struct sltimer_vec_root sltv1 = { 0 }; - -static struct sltimer_vec * const sltvecs[] = { - (struct sltimer_vec *)&sltv1, &sltv2, &sltv3 -}; - -#define NOOF_SLTVECS (sizeof(sltvecs) / sizeof(sltvecs[0])) - -static void init_sltimervecs (void) -{ - int i; - - for (i = 0; i < TVN_SIZE; i++) { - INIT_LIST_HEAD(sltv3.vec + i); - INIT_LIST_HEAD(sltv2.vec + i); - } - for (i = 0; i < TVR_SIZE; i++) - INIT_LIST_HEAD(sltv1.vec + i); -} - -static unsigned long sltimer_jiffies = 0; - -static inline void internal_add_sltimer(struct timer_list *timer) -{ - /* - * must hold the sltimer lock when calling this - */ - unsigned long expires = timer->expires; - unsigned long idx = expires - sltimer_jiffies; - struct list_head * vec; - - if (idx < 1 << (SHIFT_BITS + TVR_BITS)) { - int i = (expires >> SHIFT_BITS) & TVR_MASK; - vec = sltv1.vec + i; - } else if (idx < 1 << (SHIFT_BITS + TVR_BITS + TVN_BITS)) { - int i = (expires >> (SHIFT_BITS+TVR_BITS)) & TVN_MASK; - vec = sltv2.vec + i; - } else if ((signed long) idx < 0) { - /* - * can happen if you add a timer with expires == jiffies, - * or you set a timer to go off in the past - */ - vec = sltv1.vec + sltv1.index; - } else if (idx <= 0xffffffffUL) { - int i = (expires >> (SHIFT_BITS+TVR_BITS+TVN_BITS)) & TVN_MASK; - vec = sltv3.vec + i; - } else { - /* Can only get here on architectures with 64-bit jiffies */ - INIT_LIST_HEAD(&timer->list); - } - /* - * Timers are FIFO! - */ - list_add(&timer->list, vec->prev); -} - - -static spinlock_t __ip_vs_sltimerlist_lock = SPIN_LOCK_UNLOCKED; - -void add_sltimer(struct timer_list *timer) -{ - spin_lock(&__ip_vs_sltimerlist_lock); - if (timer->list.next) - goto bug; - internal_add_sltimer(timer); - out: - spin_unlock(&__ip_vs_sltimerlist_lock); - return; - - bug: - printk("bug: kernel sltimer added twice at %p.\n", - __builtin_return_address(0)); - goto out; -} - -static inline int detach_sltimer(struct timer_list *timer) -{ - if (!timer_pending(timer)) - return 0; - list_del(&timer->list); - return 1; -} - -void mod_sltimer(struct timer_list *timer, unsigned long expires) -{ - int ret; - - spin_lock(&__ip_vs_sltimerlist_lock); - timer->expires = expires; - ret = detach_sltimer(timer); - internal_add_sltimer(timer); - spin_unlock(&__ip_vs_sltimerlist_lock); -} - -int del_sltimer(struct timer_list * timer) -{ - int ret; - - spin_lock(&__ip_vs_sltimerlist_lock); - ret = detach_sltimer(timer); - timer->list.next = timer->list.prev = 0; - spin_unlock(&__ip_vs_sltimerlist_lock); - return ret; -} - - -static inline void cascade_sltimers(struct sltimer_vec *tv) -{ - /* - * cascade all the timers from tv up one level - */ - struct list_head *head, *curr, *next; - - head = tv->vec + tv->index; - curr = head->next; - - /* - * We are removing _all_ timers from the list, so we don't have to - * detach them individually, just clear the list afterwards. - */ - while (curr != head) { - struct timer_list *tmp; - - tmp = list_entry(curr, struct timer_list, list); - next = curr->next; - list_del(curr); // not needed - internal_add_sltimer(tmp); - curr = next; - } - INIT_LIST_HEAD(head); - tv->index = (tv->index + 1) & TVN_MASK; -} - -static inline void run_sltimer_list(void) -{ - spin_lock(&__ip_vs_sltimerlist_lock); - while ((long)(jiffies - sltimer_jiffies) >= 0) { - struct list_head *head, *curr; - if (!sltv1.index) { - int n = 1; - do { - cascade_sltimers(sltvecs[n]); - } while (sltvecs[n]->index == 1 && ++n < NOOF_SLTVECS); - } - repeat: - head = sltv1.vec + sltv1.index; - curr = head->next; - if (curr != head) { - struct timer_list *timer; - void (*fn)(unsigned long); - unsigned long data; - - timer = list_entry(curr, struct timer_list, list); - fn = timer->function; - data= timer->data; - - detach_sltimer(timer); - timer->list.next = timer->list.prev = NULL; - spin_unlock(&__ip_vs_sltimerlist_lock); - fn(data); - spin_lock(&__ip_vs_sltimerlist_lock); - goto repeat; - } - sltimer_jiffies += 1< +#include +#endif + +#include "proxyremap.h" +#include "proxydict.h" + + +/*-------------------------------------------------------------------------- +Implementation. +*/ + +// Hash function +#define hash_fnc(m,server,port,proto) \ + (((proto)*7+(server)*13+(port)*5)%m->hash_size) + +// Size of hash table given maximal number of connections: +#define hash_size_max_con(max_con) (2*(max_con)) + +// The memory area we maintain: +typedef struct { + int hash_size; + int max_con; + int cur_con; + + int free_first; + + // Then we have: + // int hash_table[hash_size]; + // int next[max_con]; + // ProxyRemapBlock info[max_con]; + // + // The idea is the following: + // Given a connection we map it by hash_fnc into hash_table. This gives an + // index in next which contains a -1 terminated linked list of connections + // mapping to that hash value. + // + // The entries in next not allocated is also in linked list where + // the first free index is free_first. +} memory; + +#define Memory(m) ((memory*)m) +#define Hash_table(m) ((int*)(((char*)m)+sizeof(memory))) +#define Next(m) ((int*)(((char*)m)+sizeof(memory)+ \ + sizeof(int)*((memory*)m)->hash_size)) +#define Info(m) ((ProxyRemapBlock*)(((char*)m)+ \ + sizeof(memory)+ \ + sizeof(int)*((memory*)m)->hash_size+\ + sizeof(int)*((memory*)m)->max_con \ + )) + +int proxyGetMemSize(int max_con) { + return sizeof(memory)+ + sizeof(int)*hash_size_max_con(max_con)+ + sizeof(int)*max_con+ + sizeof(ProxyRemapBlock)*max_con; +} + +void proxyInitMem(void* data, int max_con) { + // Init m: + memory* m=Memory(data); + m->max_con=max_con; + m->cur_con=0; + m->hash_size=hash_size_max_con(max_con); + + { + // Get pointers: + int* hash_table=Hash_table(data); + int* next=Next(data); + int i; + + // Init the hash table: + for(i=0; ihash_size; i++) hash_table[i]=-1; + + // Init the free-list + for(i=0; imax_con; i++) next[i]=i+1; + m->free_first=0; + } +} + +int proxyGetCurConn(void* data) { + return Memory(data)->cur_con; +} + +int proxyGetMaxConn(void* data) { + return Memory(data)->max_con; +} + +ProxyRemapBlock* proxyLookup(void* data, unsigned ipaddr, unsigned short port, char proto) { + memory* m=Memory(data); + int* hash_table=Hash_table(m); + int* next=Next(m); + ProxyRemapBlock* info=Info(m); + int i; + + for(i=hash_table[hash_fnc(m,ipaddr,port,proto)]; i!=-1; i=next[i]) { + if(info[i].proto==proto && + info[i].sport==port && + info[i].saddr==ipaddr) return &info[i]; + } + + return 0; +} + +int proxyConsumeBlock(void* data, ProxyRemapBlock* blk) { + memory* m=Memory(data); + int* hash_table=Hash_table(m); + int* next=Next(m); + ProxyRemapBlock* info=Info(m); + int hash=hash_fnc(m,blk->saddr,blk->sport,blk->proto); + int foo; + + if(blk->open) { + if(m->cur_con == m->max_con) return -1; + + // Insert the block at a free entry: + info[m->free_first]=*blk; + m->cur_con++; + + foo=next[m->free_first]; + + // And insert it in the hash tabel: + next[m->free_first]=hash_table[hash]; + hash_table[hash]=m->free_first; + m->free_first=foo; + } else { + int* toupdate; + + // Find the block + for(toupdate=&hash_table[hash]; + *toupdate!=-1; + toupdate=&next[*toupdate]) { + if(info[*toupdate].proto==blk->proto && + info[*toupdate].sport==blk->sport && + info[*toupdate].saddr==blk->saddr) break; + } + if(*toupdate==-1) return -1; + + foo=*toupdate; + + // Delete it from the hashing list: + *toupdate=next[*toupdate]; + + // And put it on the free list: + next[foo]=m->free_first; + m->free_first=foo; + + m->cur_con--; + } + + return 0; +} diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/sched/proxydict.h linux-2.4.20-wolk4.7-fullkernel/net/sched/proxydict.h --- linux-2.4.20-wolk4.6-fullkernel/net/sched/proxydict.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/net/sched/proxydict.h 2003-08-17 21:29:57.000000000 +0200 @@ -0,0 +1,32 @@ +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------- +This is common code for for handling the tabels containing information about +which proxyserver connections are associated with which machines.. +*/ + +// Returns the number of bytes that should be available in the area +// maintained by this module given the maximal number of concurrent +// connections. +int proxyGetMemSize(int max_connections); + +// Initializes a memory area to use. There must be as many bytes +// available as returned by getMemSize. +void proxyInitMem(void* data, int max_connections); + +// Queries: +int proxyGetCurConn(void* data); // Returns current number of connections +int proxyMaxCurConn(void* data); // Returns maximal number of connections + +// This is called to open and close conenctions. Returns -1 if +// a protocol error occores (i.e.: If it is discovered) +int proxyConsumeBlock(void* data, ProxyRemapBlock*); + +// Returns the RemapBlock associated with this connection or 0: +ProxyRemapBlock* proxyLookup(void* data, unsigned ipaddr, unsigned short port, char proto); + +#ifdef __cplusplus +} +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/sched/proxyremap.h linux-2.4.20-wolk4.7-fullkernel/net/sched/proxyremap.h --- linux-2.4.20-wolk4.6-fullkernel/net/sched/proxyremap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/net/sched/proxyremap.h 2003-08-17 21:29:57.000000000 +0200 @@ -0,0 +1,33 @@ +#ifndef PROXYREMAP_H +#define PROXYREMAP_H + +// This describes the information that is written in proxyremap.log and which +// are used in the communication between proxyremapserver and proxyremapclient. +// Everything is in network order. + +// First this header is send: +#define PROXY_WELCOME_LINE "ProxyRemap 1.02. This is a binary protocol.\r\n" + +// Then this block is send every time a connection is opened or closed. +// Note how it is alligned to use small space usage - arrays of this +// structure are saved in many places. +typedef struct { + // Server endpoint of connection: + unsigned saddr; + unsigned short sport; + + // IP protocol for this connection (typically udp or tcp): + unsigned char proto; + + // Is the connection opened or closed? + unsigned char open; + + // Client the packets should be accounted to: + unsigned caddr; + unsigned char macaddr[6]; // Might be 0. + + // An informal two-charecter code from the proxyserver. Used for debugging. + char proxyinfo[2]; +} ProxyRemapBlock; + +#endif diff -Naurp linux-2.4.20-wolk4.6-fullkernel/net/sched/sch_wrr.c linux-2.4.20-wolk4.7-fullkernel/net/sched/sch_wrr.c --- linux-2.4.20-wolk4.6-fullkernel/net/sched/sch_wrr.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.7-fullkernel/net/sched/sch_wrr.c 2003-08-17 21:29:57.000000000 +0200 @@ -0,0 +1,1364 @@ +/*----------------------------------------------------------------------------- +Weighted Round Robin scheduler. + +Written by Christian Worm Mortensen, cworm@it-c.dk. + +Introduction +============ +This module implements a weighted round robin queue with build-in classifier. +The classifier currently map each MAC or IP address (configurable either MAC +or IP and either source or destination) to different classes. Each such class +is called a band. Whan using MAC addresses only bridged packets can be +classified other packets go to a default MAC address. + +Each band has a weight value, where 0 +#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 + +// There seems to be problems when calling functions from userspace when +// using vmalloc and vfree. +//#define my_malloc(size) vmalloc(size) +//#define my_free(ptr) vfree(ptr) +#define my_malloc(size) kmalloc(size,GFP_KERNEL) +#define my_free(ptr) kfree(ptr) + +// Kernel depend stuff: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + #define KERNEL22 +#endif + +#ifdef KERNEL22 + #define LOCK_START start_bh_atomic(); + #define LOCK_END end_bh_atomic(); + #define ENQUEUE_SUCCESS 1 + #define ENQUEUE_FAIL 0 + #ifdef CONFIG_IP_MASQUERADE + #include + #define MASQ_SUPPORT + #endif +#else + #define LOCK_START sch_tree_lock(sch); + #define LOCK_END sch_tree_unlock(sch); + #define ENQUEUE_SUCCESS 0 + #define ENQUEUE_FAIL NET_XMIT_DROP + #ifdef CONFIG_NETFILTER + #include + #define MASQ_SUPPORT + #endif +#endif + +#include "proxydict.c" + +// The penalty (priority) type: +typedef u64 penalty_base_t; +#define penalty_base_t_max ((penalty_base_t)-1) +typedef struct penalty_t { + penalty_base_t ms; + penalty_base_t ls; +} penalty_t; +#define penalty_leq(a,b) (a.mselements=0; + h->root_1=poll-1; + + for(i=0; ielements==0; +} + +static char heap_contains(struct heap* h, int id) { + return h->root_1[id+1].id2idx!=0; +} + +static int heap_root(struct heap* h) { + return h->root_1[1].id; +} + +static penalty_t heap_get_penalty(struct heap* h, int id) { + return h->root_1[ h->root_1[id+1].id2idx ].penalty; +} + +static void heap_penalty_changed_internal(struct heap* h,int idx); + +static void heap_set_penalty(struct heap* h, int id, penalty_t p) { + int idx=h->root_1[id+1].id2idx; + h->root_1[idx].penalty=p; + heap_penalty_changed_internal(h,idx); +} + +static void heap_insert(struct heap* h, int id, penalty_t p) { + // Insert at the end of the heap: + h->elements++; + h->root_1[h->elements].id=id; + h->root_1[h->elements].penalty=p; + h->root_1[id+1].id2idx=h->elements; + + // And put it in the right position: + heap_penalty_changed_internal(h,h->elements); +} + +static void heap_remove(struct heap* h, int id) { + int idx=h->root_1[id+1].id2idx; + int mvid; + h->root_1[id+1].id2idx=0; + + if(h->elements==idx) { h->elements--; return; } + + mvid=h->root_1[h->elements].id; + h->root_1[idx].id=mvid; + h->root_1[idx].penalty=h->root_1[h->elements].penalty; + h->root_1[mvid+1].id2idx=idx; + + h->elements--; + heap_penalty_changed_internal(h,idx); +} + +static void heap_swap(struct heap* h, int idx0, int idx1) { + penalty_t tmp_p; + int tmp_id; + int id0,id1; + + // Simple content: + tmp_p=h->root_1[idx0].penalty; + tmp_id=h->root_1[idx0].id; + h->root_1[idx0].penalty=h->root_1[idx1].penalty; + h->root_1[idx0].id=h->root_1[idx1].id; + h->root_1[idx1].penalty=tmp_p; + h->root_1[idx1].id=tmp_id; + + // Update reverse pointers: + id0=h->root_1[idx0].id; + id1=h->root_1[idx1].id; + h->root_1[id0+1].id2idx=idx0; + h->root_1[id1+1].id2idx=idx1; +} + +static void heap_penalty_changed_internal(struct heap* h,int cur) { + if(cur==1 || penalty_leq(h->root_1[cur>>1].penalty,h->root_1[cur].penalty)) { + // We are in heap order upwards - so we should move the element down + for(;;) { + int nxt0=cur<<1; + int nxt1=nxt0+1; + penalty_t pen_c=h->root_1[cur].penalty; + penalty_t pen_0=nxt0<=h->elements ? h->root_1[nxt0].penalty : penalty_max; + penalty_t pen_1=nxt1<=h->elements ? h->root_1[nxt1].penalty : penalty_max; + + if(penalty_le(pen_0,pen_c) && penalty_leq(pen_0,pen_1)) { + // Swap with child 0: + heap_swap(h,cur,nxt0); + cur=nxt0; + } else if(penalty_le(pen_1,pen_c)) { + // Swap with child 1: + heap_swap(h,cur,nxt1); + cur=nxt1; + } else { + // Heap in heap order: + return; + } + } + } else { + // We are not in heap order upwards (and thus we must be it downwards). + // We move up: + while(cur!=1) { // While not root + int nxt=cur>>1; + if(penalty_leq(h->root_1[nxt].penalty,h->root_1[cur].penalty)) return; + heap_swap(h,cur,nxt); + cur=nxt; + } + } +}; + +//----------------------------------------------------------------------------- +// Classification based on MAC or IP adresses. Note that of historical reason +// these are prefixed with mac_ since originally only MAC bases classification +// was supported. +// +// This code should be in a separate filter module - but it isn't. + +// Interface: + +struct mac_head; + +// Initialices/destroys the structure we maintain. +// Returns -1 on error +static int mac_init(struct mac_head*, int max_macs, char srcaddr, + char usemac, char usemasq, void* proxyremap); +static void mac_done(struct mac_head*); +static void mac_reset(struct mac_head*); + +// Classify a packet. Returns a number n where 0<=n>1; + m_ptr=((const char*)base)+m_idx*size; + + i=compare(key,m_ptr); + if(i<0) // key is less + return bsearch(key,base,m_idx,size,compare); + else if(i>0) + return bsearch(key,((const char*)m_ptr)+size,nmemb-m_idx-1,size,compare); + + return m_ptr; +} + +static int mac_init(struct mac_head* h, int max_macs, char srcaddr, + char usemac, char usemasq,void* proxyremap) { + h->mac_cur=0; + h->mac_reused=0; + h->incr_time=0; + h->srcaddr=srcaddr; + h->usemac=usemac; + h->usemasq=usemasq; + h->mac_max=max_macs; + h->proxyremap=proxyremap; + + h->macs=(struct mac_addr*) + my_malloc( sizeof(struct mac_addr)*max_macs); + h->cls2mac=(char*)my_malloc( 6*max_macs); + if(!h->macs || !h->cls2mac) { + if(h->macs) my_free(h->macs); + if(h->cls2mac) my_free(h->cls2mac); + return -1; + } + return 0; +} + +static void mac_done(struct mac_head* h) { + my_free(h->macs); + my_free(h->cls2mac); +} + +static void mac_reset(struct mac_head* h) { + h->mac_cur=0; + h->mac_reused=0; + h->incr_time=0; +} + +static int lookup_mac(struct mac_head* h, unsigned char* addr) { + int i; + int class; + + // First try to find the address in the table: + struct mac_addr* m=(struct mac_addr*) + bsearch(addr,h->macs,h->mac_cur,sizeof(struct mac_addr),mac_compare); + if(m) { + // Found: + m->lastused=h->incr_time++; + return m->class; + } + + // Okay - the MAC adress was not in table + if(h->mac_cur==h->mac_max) { + // And the table is full - delete the oldest entry: + + // Find the oldest entry: + int lowidx=0; + int i; + for(i=1; imac_cur; i++) + if(h->macs[i].lastused < h->macs[lowidx].lastused) lowidx=i; + + class=h->macs[lowidx].class; + + // And delete it: + memmove(&h->macs[lowidx],&h->macs[lowidx+1], + (h->mac_cur-lowidx-1)*sizeof(struct mac_addr)); + h->mac_reused++; + h->mac_cur--; + } else { + class=h->mac_cur; + } + + // The table is now not full - find the position we should put the address in: + for(i=0; imac_cur; i++) if(mac_compare(addr,&h->macs[i])<0) break; + + // We should insert at position i: + memmove(&h->macs[i+1],&h->macs[i],(h->mac_cur-i)*sizeof(struct mac_addr)); + m=&h->macs[i]; + memcpy(m->addr,addr,ETH_ALEN); + m->lastused=h->incr_time++; + m->class=class; + h->mac_cur++; + + // Finally update the cls2mac variabel: + memcpy(h->cls2mac+ETH_ALEN*class,addr,ETH_ALEN); + + return m->class; +} + +int valid_ip_checksum(struct iphdr* ip, int size) { + __u16 header_len=ip->ihl<<2; + __u16 c=0; + __u16* ipu=(u16*)ip; + int a; + + // We require 4 bytes in the packet since we access the port numbers: + if((size>1); a++, ipu++) { + if(a!=5) { // If not the checksum field + __u16 oldc=c; + c+=(*ipu); + if(ccheck==(__u16)~c; +} + +static int mac_classify(struct mac_head* head, struct sk_buff *skb) +{ + // We set this to the address we map to. In case we map to an IP + // address the last two entries are set to 0. + unsigned char addr[ETH_ALEN]; + + + // This is the size of the network part of the packet, I think: + int size=((char*)skb->data+skb->len)-((char*)skb->nh.iph); + + // Set a default value for the address: + memset(addr,0,ETH_ALEN); + + // Accept IP-ARP traffic with big-enough packets: + if(ntohs(skb->protocol)==ETH_P_ARP && + ntohs(skb->nh.arph->ar_pro)==ETH_P_IP) { + // Map all ARP trafic to a default adress to make sure + // it goes through + } else if ((ntohs(skb->protocol)==ETH_P_IP) && + valid_ip_checksum(skb->nh.iph,size)) { + // Accept IP packets which have correct checksum. + + // This is the IP header: + struct iphdr* iph=skb->nh.iph; + + // And this is the port numbers: + const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); + __u16 sport=portp[0]; + __u16 dport=portp[1]; + + // We will set this to the IP address of the packet that should be + // accounted to: + unsigned ipaddr; + + // Used below: + ProxyRemapBlock* prm; + + // Set ipaddr: + if(head->srcaddr) + ipaddr=iph->saddr; + else + ipaddr=iph->daddr; + +#ifdef MASQ_SUPPORT + // Update ipaddr if packet is masqgraded: + if(head->usemasq) { + #ifdef KERNEL22 + struct ip_masq* src; + + // HACK!: + // ip_masq_in_get must be called for packets comming from the outside + // to the firewall. We have a a packet which is comming from the + // firewall to the outside - so we switch the parameters: + if((src=ip_masq_in_get( + iph->protocol, + iph->daddr,dport, + iph->saddr,sport))) { + // Use masqgraded address: + ipaddr=src->saddr; + + // It seems like we must put it back: + ip_masq_put(src); + } + #else + // Thanks to Rusty Russell for help with the following code: + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct; + ct = ip_conntrack_get(skb, &ctinfo); + if (ct) { + if(head->srcaddr) + ipaddr=ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.src.ip; + else + ipaddr=ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.dst.ip; + } + #endif + } +#endif + + // Set prm based on ipaddr: + prm=0; + if(head->proxyremap) { + if(head->srcaddr) { + prm=proxyLookup(head->proxyremap,ipaddr,sport,skb->nh.iph->protocol); + } else { + prm=proxyLookup(head->proxyremap,ipaddr,dport,skb->nh.iph->protocol); + } + } + + // And finally set addr to the address: + memset(addr,0,ETH_ALEN); + if(prm) { + // This package should be remapped: + if(head->usemac) + memcpy(addr,prm->macaddr,ETH_ALEN); + else { + memcpy(addr,&prm->caddr,sizeof(unsigned)); + } + } else { + // This packet should not be remapped: + if(head->usemac) { + // We should find MAC address of packet. + // Unfortunatly, this is not always available. + // On bridged packets it always is, however.. + #ifdef KERNEL22 + if(skb->pkt_bridged) { + if(head->srcaddr) { + memcpy(addr,skb->mac.ethernet->h_source,ETH_ALEN); + } else { + memcpy(addr,skb->mac.ethernet->h_dest,ETH_ALEN); + } + } + #endif + } else { + memcpy(addr,&ipaddr,4); + } + } + } else { + // All other traffic is dropped - this ensures that packets + // we consider probably have valid addresses so we don't + // get to many strange addresses into our table. And that we + // don't use bandwidth on strange packets.. + return -1; + } + + return lookup_mac(head,addr); +} + +//----------------------------------------------------------------------------- +// The qdisc itself + +// Pr-class information. +struct wrrc_sched_data { + struct Qdisc* que; // The queue for this class + struct tc_wrr_class_modf class_modf; // Information about the class. + + // For classes in the heap this is the priority value priosum + // was updated with for this class: + u64 priosum_val; +}; + +// Pr-qdisc information: +struct wrr_sched_data +{ + // A heap containing all the bands that will send something + struct heap h; + struct heap_element* poll; // bandc elements + + // The sum of the prioities of the elements in the heap where + // a priority of 1 is saved as 2^32 + u64 priosum; + + // A class for each band + struct wrrc_sched_data* bands; // bandc elements + + // Information maintained by the proxydict module of 0 if we + // have no proxy remapping + void* proxydict; + + // Always incrementning counters, we always have that any value of + // counter_low_penal < any value of counter_high_penal. + penalty_base_t counter_low_penal; + penalty_base_t counter_high_penal; + + // Penalty updating: + struct tc_wrr_qdisc_modf qdisc_modf; + + // Statistics: + int packets_requed; + + // The filter: + struct mac_head filter; + int bandc; // Number of bands +}; + +// Priority handling. +// weight is in interval [0..2^32] +// priosum has whole numbers in the upper and fragments in the lower 32 bits. +static void weight_transmit(struct tc_wrr_class_weight* p, + struct tc_wrr_qdisc_weight q, + unsigned heapsize, + u64 priosum, u64 weight, + unsigned size) { + + unsigned long now=jiffies/HZ; + + // Penalty for transmitting: + u64 change,old; + u32 divisor; + + change=0; + switch(q.weight_mode) { + case 1: change=p->decr*size; break; + case 2: change=p->decr*size*heapsize; break; + case 3: // Note: 64 bit division is not always available.. + divisor=(u32)(weight>>16); + if(divisor<=0) divisor=1; + change=p->decr*size*(((u32)(priosum>>16))/divisor); break; + } + old=p->val; + p->val-=change; + if(p->val>old || p->valmin) p->val=p->min; + + // Credit for time went: + change=(now-p->tim)*p->incr; + p->tim=now; + old=p->val; + p->val+=change; + if(p->valval>p->max) p->val=p->max; +} + +static void weight_setdefault(struct tc_wrr_class_weight* p) { + p->val=(u64)-1; + p->decr=0; + p->incr=0; + p->min=(u64)-1; + p->max=(u64)-1; + p->tim=jiffies/HZ; +} + +static void weight_setvalue(struct tc_wrr_class_weight* dst, + struct tc_wrr_class_weight* src) { + if(src->val!=0) { + dst->val=src->val; + dst->tim=jiffies/HZ; + } + if(src->min!=0) dst->min=src->min; + if(src->max!=0) dst->max=src->max; + if(src->decr!=((u64)-1)) dst->decr=src->decr; + if(src->incr!=((u64)-1)) dst->incr=src->incr; + if(dst->valmin) dst->val=dst->min; + if(dst->val>dst->max) dst->val=dst->max; +} + +static void wrr_destroy(struct Qdisc *sch) +{ + struct wrr_sched_data *q=(struct wrr_sched_data *)sch->data; + int i; + + // Destroy our filter: + mac_done(&q->filter); + + // Destroy all our childre ques: + for(i=0; ibandc; i++) + qdisc_destroy(q->bands[i].que); + + // And free memory: + my_free(q->bands); + my_free(q->poll); + if(q->proxydict) my_free(q->proxydict); + + MOD_DEC_USE_COUNT; +} + +static int wrr_init(struct Qdisc *sch, struct rtattr *opt) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + int i,maciniterr; + char crterr; + struct tc_wrr_qdisc_crt *qopt; + + // Parse options: + if (!opt) return -EINVAL; // Options must be specified + if (opt->rta_len < RTA_LENGTH(sizeof(*qopt))) return -EINVAL; + qopt = RTA_DATA(opt); + + if(qopt->bands_max>8192 || qopt->bands_max<2) { + // More than 8192 queues or less than 2? That cannot be true - it must be + // an error... + return -EINVAL; + } + + if(qopt->proxy_maxconn<0 || qopt->proxy_maxconn>20000) { + // More than this number of maximal concurrent connections is unrealistic + return -EINVAL; + } + +#ifndef MASQ_SUPPORT + if(qopt->usemasq) { + return -ENOSYS; + } +#endif + +#ifndef KERNEL22 + if(qopt->usemac) { // Not supported - please fix this! + return -ENOSYS; + } +#endif + + q->bandc=qopt->bands_max; + q->qdisc_modf=qopt->qdisc_modf; + + // Create structures: + q->poll=(struct heap_element*) + my_malloc( sizeof(struct heap_element)*q->bandc); + q->bands=(struct wrrc_sched_data*) + my_malloc( sizeof(struct wrrc_sched_data)*q->bandc); + + if(qopt->proxy_maxconn>0) { + q->proxydict=my_malloc(proxyGetMemSize(qopt->proxy_maxconn)); + } else { + q->proxydict=0; + } + + // Init mac module: + maciniterr=mac_init(&q->filter,qopt->bands_max,qopt->srcaddr, + qopt->usemac,qopt->usemasq,q->proxydict); + + // See if we got the memory we wanted: + if(!q->poll || !q->bands || + (qopt->proxy_maxconn>0 && !q->proxydict) || maciniterr<0) { + if(q->poll) my_free(q->poll); + if(q->bands) my_free(q->bands); + if(q->proxydict) my_free(q->proxydict); + if(maciniterr>=0) mac_done(&q->filter); + return -ENOMEM; + } + + // Initialize proxy: + if(q->proxydict) { + proxyInitMem(q->proxydict,qopt->proxy_maxconn); + } + + // Initialize values: + q->counter_low_penal=0; + q->counter_high_penal=penalty_base_t_max>>1; + q->packets_requed=0; + + // Initialize empty heap: + heap_init(&q->h,q->bandc,q->poll); + q->priosum=0; + + // Initialize each band: + crterr=0; + for (i=0; ibandc; i++) { + weight_setdefault(&q->bands[i].class_modf.weight1); + weight_setdefault(&q->bands[i].class_modf.weight2); + if(!crterr) { + struct Qdisc *child=qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if(child) + q->bands[i].que = child; + else { + // Queue couldn't be created :-( + crterr=1; + } + } + if(crterr) q->bands[i].que = &noop_qdisc; + } + + MOD_INC_USE_COUNT; + + if(crterr) { + // Destroy again: + wrr_destroy(sch); + return -ENOMEM; + } + + return 0; +} + +static void wrr_reset(struct Qdisc* sch) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + int i; + + // Reset own values: + q->counter_low_penal=0; + q->counter_high_penal=penalty_base_t_max>>1; + q->packets_requed=0; + + // Reset filter: + mac_reset(&q->filter); + + // Reinitialize heap: + heap_init(&q->h,q->bandc,q->poll); + q->priosum=0; + + // Reset all bands: + for (i=0; ibandc; i++) { + weight_setdefault(&q->bands[i].class_modf.weight1); + weight_setdefault(&q->bands[i].class_modf.weight2); + qdisc_reset(q->bands[i].que); + } + + // Reset proxy remapping information: + if(q->proxydict) + proxyInitMem(q->proxydict,proxyGetMaxConn(q->proxydict)); +} + +static int wrr_enqueue(struct sk_buff *skb, struct Qdisc* sch) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + int retvalue=ENQUEUE_FAIL; + + // The packet is in skb. + int band=mac_classify(&q->filter,skb); + + if(band>=0) { + // Enque packet for this band: + struct Qdisc* qdisc = q->bands[band].que; + + if ((retvalue=qdisc->enqueue(skb, qdisc)) == ENQUEUE_SUCCESS) { + // Successfull + sch->stats.bytes += skb->len; + sch->stats.packets++; + sch->q.qlen++; + + // Insert band into heap if not already there: + if(!heap_contains(&q->h,band)) { + penalty_t p; + if(!heap_empty(&q->h)) + p.ms=heap_get_penalty(&q->h,heap_root(&q->h)).ms; + else + p.ms=0; + p.ls=q->counter_low_penal++; + heap_insert(&q->h,band,p); + q->bands[band].priosum_val= + ((q->bands[band].class_modf.weight1.val>>48)+1)* + ((q->bands[band].class_modf.weight2.val>>48)+1); + q->priosum+=q->bands[band].priosum_val; + } + } + } else { + // If we decide not to enque it seems like we also need to free the packet: + kfree_skb(skb); + } + + if(retvalue!=ENQUEUE_SUCCESS) { + // Packet not enqued: + sch->stats.drops++; + } + + return retvalue; +} + +static struct sk_buff *wrr_dequeue(struct Qdisc* sch) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + struct sk_buff* skb; + int band; + u64 weight,priosum; + struct wrrc_sched_data* b; + + // Return if heap is empty: + if(heap_empty(&q->h)) return 0; + + // Find root element: + band=heap_root(&q->h); + + // Find priority of this element in interval [1;2^32] + b=&q->bands[band]; + weight=((b->class_modf.weight1.val>>48)+1)* + ((b->class_modf.weight2.val>>48)+1); //weight is in interval [1;2^32] + priosum=q->priosum; + q->priosum-=q->bands[band].priosum_val; + + // Deque the packet from the root: + skb=q->bands[band].que->dequeue(q->bands[band].que); + + if(skb) { + // There was a packet in this que. + unsigned adjlen; + penalty_t p; + + // Find length of packet adjusted with priority: + adjlen=(u32)(weight>>(32-16)); + if(adjlen==0) adjlen=1; + adjlen=(skb->len<<16)/adjlen; + + // Update penalty information for this class: + weight_transmit(&b->class_modf.weight1,q->qdisc_modf.weight1,q->h.elements,priosum,weight,skb->len); + weight_transmit(&b->class_modf.weight2,q->qdisc_modf.weight2,q->h.elements,priosum,weight,skb->len); + q->bands[band].priosum_val=((b->class_modf.weight1.val>>48)+1)* + ((b->class_modf.weight2.val>>48)+1); + q->priosum+=q->bands[band].priosum_val; + + // And update the class in the heap + p=heap_get_penalty(&q->h,band); + p.ms+=adjlen; + p.ls=q->counter_high_penal++; + heap_set_penalty(&q->h,band,p); + + // Return packet: + sch->q.qlen--; + return skb; + } + + // No packet - so machine should be removed from heap: + heap_remove(&q->h,band); + + // And try again: + return wrr_dequeue(sch); +} + +static int wrr_requeue(struct sk_buff *skb, struct Qdisc* sch) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + struct Qdisc* qdisc; + int ret; + + // Find band we took it from: + int band=mac_classify(&q->filter,skb); + if(band<0) { + // Who should now free the pakcet? + printk(KERN_DEBUG "sch_wrr: Oops - packet requed could never have been queued.\n"); + sch->stats.drops++; + return ENQUEUE_FAIL; + } + + q->packets_requed++; + + // Try to requeue it on that machine: + qdisc=q->bands[band].que; + + if((ret=qdisc->ops->requeue(skb,qdisc))==ENQUEUE_SUCCESS) { + // On success: + sch->q.qlen++; + + // We should restore priority information - but we don't + // + // p=heap_get_penalty(&q->h,band); + // ... + // heap_set_penalty(&q->h,band,p); + + return ENQUEUE_SUCCESS; + } else { + sch->stats.drops++; + return ret; + } +} + +static int wrr_drop(struct Qdisc* sch) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + + // Ugly... Drop button up in heap: + int i; + + for(i=q->h.elements; i>=1; i--) { + int band=q->h.root_1[i].id; + if(q->bands[band].que->ops->drop(q->bands[band].que)) { + // On success + sch->q.qlen--; + return 1; + } + } + + return 0; +} + +static int wrr_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + unsigned char *b = skb->tail; + struct tc_wrr_qdisc_stats opt; + + opt.qdisc_crt.qdisc_modf=q->qdisc_modf; + opt.qdisc_crt.srcaddr=q->filter.srcaddr; + opt.qdisc_crt.usemac=q->filter.usemac; + opt.qdisc_crt.usemasq=q->filter.usemasq; + opt.qdisc_crt.bands_max=q->filter.mac_max; + opt.nodes_in_heap=q->h.elements; + opt.bands_cur=q->filter.mac_cur; + opt.bands_reused=q->filter.mac_reused; + opt.packets_requed=q->packets_requed; + opt.priosum=q->priosum; + + if(q->proxydict) { + opt.qdisc_crt.proxy_maxconn=proxyGetMaxConn(q->proxydict); + opt.proxy_curconn=proxyGetCurConn(q->proxydict); + } else { + opt.qdisc_crt.proxy_maxconn=0; + opt.proxy_curconn=0; + } + + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + return skb->len; + +rtattr_failure: // seems like RTA_PUT jump to this label.. + skb_trim(skb, b - skb->data); + return -1; +} + +static int wrr_tune_std(struct Qdisc *sch, struct rtattr *opt) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + struct tc_wrr_qdisc_modf_std *qopt = RTA_DATA(opt); + + if(opt->rta_len < RTA_LENGTH(sizeof(*qopt))) return -EINVAL; + + LOCK_START + + if(qopt->change_class) { + int idx=lookup_mac(&q->filter,qopt->addr); + weight_setvalue + (&q->bands[idx].class_modf.weight1,&qopt->class_modf.weight1); + weight_setvalue + (&q->bands[idx].class_modf.weight2,&qopt->class_modf.weight2); + } else { + if(qopt->qdisc_modf.weight1.weight_mode!=-1) + q->qdisc_modf.weight1.weight_mode=qopt->qdisc_modf.weight1.weight_mode; + if(qopt->qdisc_modf.weight2.weight_mode!=-1) + q->qdisc_modf.weight2.weight_mode=qopt->qdisc_modf.weight2.weight_mode; + } + + LOCK_END + + return 0; +} + +static int wrr_tune_proxy(struct Qdisc *sch, struct rtattr *opt) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + struct tc_wrr_qdisc_modf_proxy *qopt = RTA_DATA(opt); + int i; + + // Return if we are not configured with proxy support: + if(!q->proxydict) return -ENOSYS; + + // Return if not enough data given: + if(opt->rta_lenrta_len< + RTA_LENGTH(sizeof(*qopt)+sizeof(ProxyRemapBlock)*qopt->changec)) + return -EINVAL; + + LOCK_START; + + if(qopt->reset) { + proxyInitMem(q->proxydict,proxyGetMaxConn(q->proxydict)); + } + + // Do all the changes: + for(i=0; ichangec; i++) { + proxyConsumeBlock(q->proxydict,&((ProxyRemapBlock*)&qopt->changes)[i]); + } + + LOCK_END; + + return 0; +} + +static int wrr_tune(struct Qdisc *sch, struct rtattr *opt) { + if(((struct tc_wrr_qdisc_modf_std*)RTA_DATA(opt))->proxy) { + return wrr_tune_proxy(sch,opt); + } else { + return wrr_tune_std(sch,opt); + } +} + +//----------------------------------------------------------------------------- +// Classes. +// External and internal IDs are equal. They are the band number plus 1. + +// Replace a class with another: +static int wrr_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, + struct Qdisc **old) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + if(arg>q->bandc || arg==0) return -EINVAL; + arg--; + + if (new == NULL) + new = &noop_qdisc; + +#ifdef KERNEL22 + *old = xchg(&q->bands[arg].que, new); +#else + LOCK_START + *old = q->bands[arg].que; + q->bands[arg].que = new; + qdisc_reset(*old); + LOCK_END +#endif + + return 0; +} + +// Returns the qdisc for a class: +static struct Qdisc * wrr_leaf(struct Qdisc *sch, unsigned long arg) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + if(arg>q->bandc || arg==0) return NULL; + arg--; + return q->bands[arg].que; +} + +static unsigned long wrr_get(struct Qdisc *sch, u32 classid) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + unsigned long band = TC_H_MIN(classid); + if(band>q->bandc || band==0) return 0; + return band; +} + +static void wrr_put(struct Qdisc *q, unsigned long cl) +{ + return; +} + +static int wrr_delete(struct Qdisc *sch, unsigned long cl) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + if(cl==0 || cl>q->bandc) return -ENOENT; + cl--; + return 0; +} + +static int wrr_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + unsigned char *b = skb->tail; + struct tc_wrr_class_stats opt; + + // Handle of this class: + tcm->tcm_handle = sch->handle|cl; + + if(cl==0 || cl>q->bandc) + goto rtattr_failure; + cl--; + + if(cl>=q->filter.mac_cur) { + // Band is unused: + memset(&opt,0,sizeof(opt)); + opt.used=0; + } else { + opt.used=1; + opt.class_modf.weight1=q->bands[cl].class_modf.weight1; + opt.class_modf.weight2=q->bands[cl].class_modf.weight2; + weight_transmit(&opt.class_modf.weight1,q->qdisc_modf.weight1,0,0,0,0); + weight_transmit(&opt.class_modf.weight2,q->qdisc_modf.weight2,0,0,0,0); + memcpy(opt.addr,q->filter.cls2mac+cl*ETH_ALEN,ETH_ALEN); + opt.usemac=q->filter.usemac; + opt.heappos=q->h.root_1[cl+1].id2idx; + if(opt.heappos!=0) { // Is in heap + opt.penal_ls=heap_get_penalty(&q->h,cl).ls; + opt.penal_ms=heap_get_penalty(&q->h,cl).ms; + } else { + opt.penal_ls=0; + opt.penal_ms=0; + } + } + + // Put quing information: + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + return skb->len; + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int wrr_change(struct Qdisc *sch, u32 handle, u32 parent, + struct rtattr **tca, unsigned long *arg) +{ + unsigned long cl = *arg; + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + struct rtattr *opt = tca[TCA_OPTIONS-1]; + struct tc_wrr_class_modf *copt = RTA_DATA(opt); + + if(cl==0 || cl>q->bandc) return -EINVAL; + cl--; + + if (opt->rta_len < RTA_LENGTH(sizeof(*copt))) return -EINVAL; + + LOCK_START; + + weight_setvalue(&q->bands[cl].class_modf.weight1,&copt->weight1); + weight_setvalue(&q->bands[cl].class_modf.weight2,&copt->weight2); + + LOCK_END; + + return 0; +} + +static void wrr_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data; + int prio; + + if (arg->stop) return; + + for (prio = 1; prio <= q->bandc; prio++) { + if (arg->count < arg->skip) { + arg->count++; + continue; + } + if (arg->fn(sch, prio, arg) < 0) { + arg->stop = 1; + break; + } + arg->count++; + } +} + +static struct tcf_proto ** wrr_find_tcf(struct Qdisc *sch, unsigned long cl) +{ + return NULL; +} + +static unsigned long wrr_bind(struct Qdisc *sch, + unsigned long parent, u32 classid) +{ + return wrr_get(sch, classid); +} + +//----------------------------------------------------------------------------- +// Generel + +static struct Qdisc_class_ops wrr_class_ops = +{ + wrr_graft, + wrr_leaf, + + wrr_get, + wrr_put, + wrr_change, + wrr_delete, + wrr_walk, + + wrr_find_tcf, + wrr_bind, + wrr_put, + +#if !defined(KERNEL22) || defined(CONFIG_RTNETLINK) + wrr_dump_class, +#endif +}; + +struct Qdisc_ops wrr_qdisc_ops = +{ + NULL, + &wrr_class_ops, + "wrr", + sizeof(struct wrr_sched_data), + + wrr_enqueue, + wrr_dequeue, + wrr_requeue, + wrr_drop, + + wrr_init, + wrr_reset, + wrr_destroy, + wrr_tune, + +#if !defined(KERNEL22) || defined(CONFIG_RTNETLINK) + wrr_dump, +#endif +}; + +#ifdef MODULE + +int init_module(void) +{ + return register_qdisc(&wrr_qdisc_ops); +} + +void cleanup_module(void) +{ + unregister_qdisc(&wrr_qdisc_ops); +} + +#ifndef KERNEL22 + MODULE_LICENSE("GPL"); +#endif + +#endif +