./ocfs2-tools-1.6.4/0000775000176100017610000000000011515641642011045 500000000000000./ocfs2-tools-1.6.4/documentation/0000775000176100017610000000000011515641637013722 500000000000000./ocfs2-tools-1.6.4/documentation/samples/0000775000176100017610000000000011515641637015366 500000000000000./ocfs2-tools-1.6.4/documentation/samples/cluster.conf0000664000176100017610000000034410673531131017626 00000000000000node: ip_port = 7777 ip_address = 192.168.0.112 number = 0 name = node0 cluster = ocfs2 node: ip_port = 7777 ip_address = 192.168.0.116 number = 1 name = node1 cluster = ocfs2 cluster: node_count = 2 name = ocfs2 ./ocfs2-tools-1.6.4/documentation/ocfs2_faq.txt0000664000176100017610000010740110673531131016240 00000000000000 OCFS2 - Frequently Asked Questions ================================== General ------- Q01 How do I get started? A01 a) Download and install the module and tools rpms. b) Create cluster.conf and propagate to all nodes. c) Configure and start the O2CB cluster service. d) Format the volume. e) Mount the volume. Q02 How do I know the version number running? A02 # cat /proc/fs/ocfs2/version OCFS2 1.2.1 Fri Apr 21 13:51:24 PDT 2006 (build bd2f25ba0af9677db3572e3ccd92f739) Q03 How do I configure my system to auto-reboot after a panic? A03 To auto-reboot system 60 secs after a panic, do: # echo 60 > /proc/sys/kernel/panic To enable the above on every reboot, add the following to /etc/sysctl.conf: kernel.panic = 60 ============================================================================== Download and Install -------------------- Q01 Where do I get the packages from? A01 For Novell's SLES9, upgrade to SP3 to get the required modules installed. Also, install ocfs2-tools and ocfs2console packages. For Red Hat's RHEL4, download and install the appropriate module package and the two tools packages, ocfs2-tools and ocfs2console. Appropriate module refers to one matching the kernel version, flavor and architecture. Flavor refers to smp, hugemem, etc. Q02 What are the latest versions of the OCFS2 packages? A02 The latest module package version is 1.2.2. The latest tools/console packages versions are 1.2.1. Q03 How do I interpret the package name ocfs2-2.6.9-22.0.1.ELsmp-1.2.1-1.i686.rpm? A03 The package name is comprised of multiple parts separated by '-'. a) ocfs2 - Package name b) 2.6.9-22.0.1.ELsmp - Kernel version and flavor c) 1.2.1 - Package version d) 1 - Package subversion e) i686 - Architecture Q04 How do I know which package to install on my box? A04 After one identifies the package name and version to install, one still needs to determine the kernel version, flavor and architecture. To know the kernel version and flavor, do: # uname -r 2.6.9-22.0.1.ELsmp To know the architecture, do: # rpm -qf /boot/vmlinuz-`uname -r` --queryformat "%{ARCH}\n" i686 Q05 Why can't I use "uname -p" to determine the kernel architecture? A05 "uname -p" does not always provide the exact kernel architecture. Case in point the RHEL3 kernels on x86_64. Even though Red Hat has two different kernel architectures available for this port, ia32e and x86_64, "uname -p" identifies both as the generic "x86_64". Q06 How do I install the rpms? A06 First install the tools and console packages: # rpm -Uvh ocfs2-tools-1.2.1-1.i386.rpm ocfs2console-1.2.1-1.i386.rpm Then install the appropriate kernel module package: # rpm -Uvh ocfs2-2.6.9-22.0.1.ELsmp-1.2.1-1.i686.rpm Q07 Do I need to install the console? A07 No, the console is not required but recommended for ease-of-use. Q08 What are the dependencies for installing ocfs2console? A08 ocfs2console requires e2fsprogs, glib2 2.2.3 or later, vte 0.11.10 or later, pygtk2 (EL4) or python-gtk (SLES9) 1.99.16 or later, python 2.3 or later and ocfs2-tools. Q09 What modules are installed with the OCFS2 1.2 package? A09 a) configfs.ko b) ocfs2.ko c) ocfs2_dlm.ko d) ocfs2_dlmfs.ko e) ocfs2_nodemanager.ko f) debugfs Q10 What tools are installed with the ocfs2-tools 1.2 package? A10 a) mkfs.ocfs2 b) fsck.ocfs2 c) tunefs.ocfs2 d) debugfs.ocfs2 e) mount.ocfs2 f) mounted.ocfs2 g) ocfs2cdsl h) ocfs2_hb_ctl i) o2cb_ctl j) o2cb - init service to start/stop the cluster k) ocfs2 - init service to mount/umount ocfs2 volumes l) ocfs2console - installed with the console package Q11 What is debugfs and is it related to debugfs.ocfs2? A11 debugfs is an in-memory filesystem developed by Greg Kroah-Hartman. It is useful for debugging as it allows kernel space to easily export data to userspace. For more, http://kerneltrap.org/node/4394. It is currently being used by OCFS2 to dump the list of filesystem locks and could be used for more in the future. It is bundled with OCFS2 as the various distributions are currently not bundling it. While debugfs and debugfs.ocfs2 are unrelated in general, the latter is used as the front-end for the debugging info provided by the former. For example, refer to the troubleshooting section. ============================================================================== Configure --------- Q01 How do I populate /etc/ocfs2/cluster.conf? A01 If you have installed the console, use it to create this configuration file. For details, refer to the user's guide. If you do not have the console installed, check the Appendix in the User's guide for a sample cluster.conf and the details of all the components. Do not forget to copy this file to all the nodes in the cluster. If you ever edit this file on any node, ensure the other nodes are updated as well. Q02 Should the IP interconnect be public or private? A02 Using a private interconnect is recommended. While OCFS2 does not take much bandwidth, it does require the nodes to be alive on the network and sends regular keepalive packets to ensure that they are. To avoid a network delay being interpreted as a node disappearing on the net which could lead to a node-self-fencing, a private interconnect is recommended. One could use the same interconnect for Oracle RAC and OCFS2. Q03 What should the node name be and should it be related to the IP address? A03 The node name needs to match the hostname. The IP address need not be the one associated with that hostname. As in, any valid IP address on that node can be used. OCFS2 will not attempt to match the node name (hostname) with the specified IP address. Q04 How do I modify the IP address, port or any other information specified in cluster.conf? A04 While one can use ocfs2console to add nodes dynamically to a running cluster, any other modifications require the cluster to be offlined. Stop the cluster on all nodes, edit /etc/ocfs2/cluster.conf on one and copy to the rest, and restart the cluster on all nodes. Always ensure that cluster.conf is the same on all the nodes in the cluster. ============================================================================== O2CB Cluster Service -------------------- Q01 How do I configure the cluster service? A01 # /etc/init.d/o2cb configure Enter 'y' if you want the service to load on boot and the name of the cluster (as listed in /etc/ocfs2/cluster.conf). Q02 How do I start the cluster service? A02 a) To load the modules, do: # /etc/init.d/o2cb load b) To Online it, do: # /etc/init.d/o2cb online [cluster_name] If you have configured the cluster to load on boot, you could combine the two as follows: # /etc/init.d/o2cb start [cluster_name] The cluster name is not required if you have specified the name during configuration. Q03 How do I stop the cluster service? A03 a) To offline it, do: # /etc/init.d/o2cb offline [cluster_name] b) To unload the modules, do: # /etc/init.d/o2cb unload If you have configured the cluster to load on boot, you could combine the two as follows: # /etc/init.d/o2cb stop [cluster_name] The cluster name is not required if you have specified the name during configuration. Q04 How can I learn the status of the cluster? A04 To learn the status of the cluster, do: # /etc/init.d/o2cb status Q05 I am unable to get the cluster online. What could be wrong? A05 Check whether the node name in the cluster.conf exactly matches the hostname. One of the nodes in the cluster.conf need to be in the cluster for the cluster to be online. ============================================================================== Format ------ Q01 How do I format a volume? A01 You could either use the console or use mkfs.ocfs2 directly to format the volume. For console, refer to the user's guide. # mkfs.ocfs2 -L "oracle_home" /dev/sdX The above formats the volume with default block and cluster sizes, which are computed based upon the size of the volume. # mkfs.ocfs2 -b 4k -C 32K -L "oracle_home" -N 4 /dev/sdX The above formats the volume for 4 nodes with a 4K block size and a 32K cluster size. Q02 What does the number of node slots during format refer to? A02 The number of node slots specifies the number of nodes that can concurrently mount the volume. This number is specified during format and can be increased using tunefs.ocfs2. This number cannot be decreased. Q03 What should I consider when determining the number of node slots? A03 OCFS2 allocates system files, like Journal, for each node slot. So as to not to waste space, one should specify a number within the ballpark of the actual number of nodes. Also, as this number can be increased, there is no need to specify a much larger number than one plans for mounting the volume. Q04 Does the number of node slots have to be the same for all volumes? A04 No. This number can be different for each volume. Q05 What block size should I use? A05 A block size is the smallest unit of space addressable by the file system. OCFS2 supports block sizes of 512 bytes, 1K, 2K and 4K. The block size cannot be changed after the format. For most volume sizes, a 4K size is recommended. On the other hand, the 512 bytes block is never recommended. Q06 What cluster size should I use? A06 A cluster size is the smallest unit of space allocated to a file to hold the data. OCFS2 supports cluster sizes of 4K, 8K, 16K, 32K, 64K, 128K, 256K, 512K and 1M. For database volumes, a cluster size of 128K or larger is recommended. For Oracle home, 32K to 64K. Q07 Any advantage of labelling the volumes? A07 As in a shared disk environment, the disk name (/dev/sdX) for a particular device be different on different nodes, labelling becomes a must for easy identification. You could also use labels to identify volumes during mount. # mount -L "label" /dir The volume label is changeable using the tunefs.ocfs2 utility. ============================================================================== Mount ----- Q01 How do I mount the volume? A01 You could either use the console or use mount directly. For console, refer to the user's guide. # mount -t ocfs2 /dev/sdX /dir The above command will mount device /dev/sdX on directory /dir. Q02 How do I mount by label? A02 To mount by label do: # mount -L "label" /dir Q03 What entry to I add to /etc/fstab to mount an ocfs2 volume? A03 Add the following: /dev/sdX /dir ocfs2 noauto,_netdev 0 0 The _netdev option indicates that the devices needs to be mounted after the network is up. Q04 What do I need to do to mount OCFS2 volumes on boot? A04 a) Enable o2cb service using: # chkconfig --add o2cb b) Enable ocfs2 service using: # chkconfig --add ocfs2 c) Configure o2cb to load on boot using: # /etc/init.d/o2cb configure d) Add entries into /etc/fstab as follows: /dev/sdX /dir ocfs2 _netdev 0 0 Q05 How do I know my volume is mounted? A05 a) Enter mount without arguments, or # mount b) List /etc/mtab, or # cat /etc/mtab c) List /proc/mounts, or # cat /proc/mounts d) Runs ocfs2 service # /etc/init.d/ocfs2 status mount command reads the /etc/mtab to show the information. Q06 What are the /config and /dlm mountpoints for? A06 OCFS2 comes bundled with two in-memory filesystems configfs and ocfs2_dlmfs. configfs is used by the ocfs2 tools to communicate to the in-kernel node manager the list of nodes in the cluster and to the in-kernel heartbeat thread the resource to heartbeat on. ocfs2_dlmfs is used by ocfs2 tools to communicate with the in-kernel dlm to take and release clusterwide locks on resources. Q07 Why does it take so much time to mount the volume? A07 It takes around 5 secs for a volume to mount. It does so so as to let the heartbeat thread stabilize. In a later release, we plan to add support for a global heartbeat, which will make most mounts instant. ============================================================================== Oracle RAC ---------- Q01 Any special flags to run Oracle RAC? A01 OCFS2 volumes containing the Voting diskfile (CRS), Cluster registry (OCR), Data files, Redo logs, Archive logs and control files must be mounted with the "datavolume" and "nointr" mount options. The datavolume option ensures that the Oracle processes opens these files with the o_direct flag. The "nointr" option ensures that the ios are not interrupted by signals. # mount -o datavolume,nointr -t ocfs2 /dev/sda1 /u01/db Q02 What about the volume containing Oracle home? A02 Oracle home volume should be mounted normally, that is, without the "datavolume" and "nointr" mount options. These mount options are only relevant for Oracle files listed above. # mount -t ocfs2 /dev/sdb1 /software/orahome Q03 Does that mean I cannot have my data file and Oracle home on the same volume? A03 Yes. The volume containing the Oracle data files, redo-logs, etc. should never be on the same volume as the distribution (including the trace logs like, alert.log). ============================================================================== Moving data from OCFS (Release 1) to OCFS2 ------------------------------------------ Q01 Can I mount OCFS volumes as OCFS2? A01 No. OCFS and OCFS2 are not on-disk compatible. We had to break the compatibility in order to add many of the new features. At the same time, we have added enough flexibility in the new disk layout so as to maintain backward compatibility in the future. Q02 Can OCFS volumes and OCFS2 volumes be mounted on the same machine simultaneously? A02 No. OCFS only works on 2.4 linux kernels (Red Hat's AS2.1/EL3 and SuSE's SLES8). OCFS2, on the other hand, only works on the 2.6 kernels (Red Hat's EL4 and SuSE's SLES9). Q03 Can I access my OCFS volume on 2.6 kernels (SLES9/RHEL4)? A03 Yes, you can access the OCFS volume on 2.6 kernels using FSCat tools, fsls and fscp. These tools can access the OCFS volumes at the device layer, to list and copy the files to another filesystem. FSCat tools are available on oss.oracle.com. Q04 Can I in-place convert my OCFS volume to OCFS2? A04 No. The on-disk layout of OCFS and OCFS2 are sufficiently different that it would require a third disk (as a temporary buffer) inorder to in-place upgrade the volume. With that in mind, it was decided not to develop such a tool but instead provide tools to copy data from OCFS without one having to mount it. Q05 What is the quickest way to move data from OCFS to OCFS2? A05 Quickest would mean having to perform the minimal number of copies. If you have the current backup on a non-OCFS volume accessible from the 2.6 kernel install, then all you would need to do is to retore the backup on the OCFS2 volume(s). If you do not have a backup but have a setup in which the system containing the OCFS2 volumes can access the disks containing the OCFS volume, you can use the FSCat tools to extract data from the OCFS volume and copy onto OCFS2. ============================================================================== Coreutils --------- Q01 Like with OCFS (Release 1), do I need to use o_direct enabled tools to perform cp, mv, tar, etc.? A01 No. OCFS2 does not need the o_direct enabled tools. The file system allows processes to open files in both o_direct and bufferred mode concurrently. ============================================================================== Troubleshooting --------------- Q01 How do I enable and disable filesystem tracing? A01 To list all the debug bits along with their statuses, do: # debugfs.ocfs2 -l To enable tracing the bit SUPER, do: # debugfs.ocfs2 -l SUPER allow To disable tracing the bit SUPER, do: # debugfs.ocfs2 -l SUPER off To totally turn off tracing the SUPER bit, as in, turn off tracing even if some other bit is enabled for the same, do: # debugfs.ocfs2 -l SUPER deny To enable heartbeat tracing, do: # debugfs.ocfs2 -l HEARTBEAT ENTRY EXIT allow To disable heartbeat tracing, do: # debugfs.ocfs2 -l HEARTBEAT off ENTRY EXIT deny Q02 How do I get a list of filesystem locks and their statuses? A02 OCFS2 1.0.9+ has this feature. To get this list, do: a) Mount debugfs is mounted at /debug. # mount -t debugfs debugfs /debug b) Dump the locks. # echo "fs_locks" | debugfs.ocfs2 /dev/sdX >/tmp/fslocks Q03 How do I read the fs_locks output? A03 Let's look at a sample output: Lockres: M000000000000000006672078b84822 Mode: Protected Read Flags: Initialized Attached RO Holders: 0 EX Holders: 0 Pending Action: None Pending Unlock Action: None Requested Mode: Protected Read Blocking Mode: Invalid First thing to note is the Lockres, which is the lockname. The dlm identifies resources using locknames. The lockname is a combination of a lock type (S superblock, M metadata, D filedata, R rename, W readwrite), inode number and generation. To get the inode number and generation from lockname, do: #echo "stat " | debugfs.ocfs2 /dev/sdX Inode: 419616 Mode: 0666 Generation: 2025343010 (0x78b84822) .... To map the lockname to a directory entry, do: # echo "locate " | debugfs.ocfs2 /dev/sdX debugfs.ocfs2 1.2.0 debugfs: 419616 /linux-2.6.15/arch/i386/kernel/semaphore.c One could also provide the inode number instead of the lockname. # echo "locate <419616>" | debugfs.ocfs2 /dev/sdX debugfs.ocfs2 1.2.0 debugfs: 419616 /linux-2.6.15/arch/i386/kernel/semaphore.c To get a lockname from a directory entry, do: # echo "encode /linux-2.6.15/arch/i386/kernel/semaphore.c" | debugfs.ocfs2 /dev/sdX M000000000000000006672078b84822 D000000000000000006672078b84822 W000000000000000006672078b84822 The first is the Metadata lock, then Data lock and last ReadWrite lock for the same resource. The DLM supports 3 lock modes: NL no lock, PR protected read and EX exclusive. If you have a dlm hang, the resource to look for would be one with the "Busy" flag set. The next step would be to query the dlm for the lock resource. Note: The dlm debugging is still a work in progress. To do dlm debugging, first one needs to know the dlm domain, which matches the volume UUID. # echo "stats" | debugfs.ocfs2 -n /dev/sdX | grep UUID: | while read a b ; do echo $b ; done 82DA8137A49A47E4B187F74E09FBBB4B Then do: # echo R dlm_domain lockname > /proc/fs/ocfs2_dlm/debug For example: # echo R 82DA8137A49A47E4B187F74E09FBBB4B M000000000000000006672078b84822 > /proc/fs/ocfs2_dlm/debug # dmesg | tail struct dlm_ctxt: 82DA8137A49A47E4B187F74E09FBBB4B, node=75, key=965960985 lockres: M000000000000000006672078b84822, owner=79, state=0 last used: 0, on purge list: no granted queue: type=3, conv=-1, node=79, cookie=11673330234144325711, ast=(empty=y,pend=n), bast=(empty=y,pend=n) converting queue: blocked queue: It shows that the lock is mastered by node 75 and that node 79 has been granted a PR lock on the resource. This is just to give a flavor of dlm debugging. ============================================================================== Limits ------ Q01 Is there a limit to the number of subdirectories in a directory? A01 Yes. OCFS2 currently allows up to 32000 subdirectories. While this limit could be increased, we will not be doing it till we implement some kind of efficient name lookup (htree, etc.). Q02 Is there a limit to the size of an ocfs2 file system? A02 Yes, current software addresses block numbers with 32 bits. So the file system device is limited to (2 ^ 32) * blocksize (see mkfs -b). With a 4KB block size this amounts to a 16TB file system. This block addressing limit will be relaxed in future software. At that point the limit becomes addressing clusters of 1MB each with 32 bits which leads to a 4PB file system. ============================================================================== System Files ------------ Q01 What are system files? A01 System files are used to store standard filesystem metadata like bitmaps, journals, etc. Storing this information in files in a directory allows OCFS2 to be extensible. These system files can be accessed using debugfs.ocfs2. To list the system files, do: # echo "ls -l //" | debugfs.ocfs2 /dev/sdX 18 16 1 2 . 18 16 2 2 .. 19 24 10 1 bad_blocks 20 32 18 1 global_inode_alloc 21 20 8 1 slot_map 22 24 9 1 heartbeat 23 28 13 1 global_bitmap 24 28 15 2 orphan_dir:0000 25 32 17 1 extent_alloc:0000 26 28 16 1 inode_alloc:0000 27 24 12 1 journal:0000 28 28 16 1 local_alloc:0000 29 3796 17 1 truncate_log:0000 The first column lists the block number. Q02 Why do some files have numbers at the end? A02 There are two types of files, global and local. Global files are for all the nodes, while local, like journal:0000, are node specific. The set of local files used by a node is determined by the slot mapping of that node. The numbers at the end of the system file name is the slot#. To list the slot maps, do: # echo "slotmap" | debugfs.ocfs2 -n /dev/sdX Slot# Node# 0 39 1 40 2 41 3 42 ============================================================================== Heartbeat --------- Q01 How does the disk heartbeat work? A01 Every node writes every two secs to its block in the heartbeat system file. The block offset is equal to its global node number. So node 0 writes to the first block, node 1 to the second, etc. All the nodes also read the heartbeat sysfile every two secs. As long as the timestamp is changing, that node is deemed alive. Q02 When is a node deemed dead? A02 An active node is deemed dead if it does not update its timestamp for O2CB_HEARTBEAT_THRESHOLD (default=7) loops. Once a node is deemed dead, the surviving node which manages to cluster lock the dead node's journal, recovers it by replaying the journal. Q03 What about self fencing? A03 A node self-fences if it fails to update its timestamp for ((O2CB_HEARTBEAT_THRESHOLD - 1) * 2) secs. The [o2hb-xx] kernel thread, after every timestamp write, sets a timer to panic the system after that duration. If the next timestamp is written within that duration, as it should, it first cancels that timer before setting up a new one. This way it ensures the system will self fence if for some reason the [o2hb-x] kernel thread is unable to update the timestamp and thus be deemed dead by other nodes in the cluster. Q04 How can one change the parameter value of O2CB_HEARTBEAT_THRESHOLD? A04 This parameter value could be changed by adding it to /etc/sysconfig/o2cb and RESTARTING the O2CB cluster. This value should be the SAME on ALL the nodes in the cluster. Q05 What should one set O2CB_HEARTBEAT_THRESHOLD to? A05 It should be set to the timeout value of the io layer. Most multipath solutions have a timeout ranging from 60 secs to 120 secs. For 60 secs, set it to 31. For 120 secs, set it to 61. O2CB_HEARTBEAT_THRESHOLD = (((timeout in secs) / 2) + 1) Q06 What if a node umounts a volume? A06 During umount, the node will broadcast to all the nodes that have mounted that volume to drop that node from its node maps. As the journal is shutdown before this broadcast, any node crash after this point is ignored as there is no need for recovery. Q07 I encounter "Kernel panic - not syncing: ocfs2 is very sorry to be fencing this system by panicing" whenever I run a heavy io load? A07 We have encountered a bug with the default "cfq" io scheduler which causes a process doing heavy io to temporarily starve out other processes. While this is not fatal for most environments, it is for OCFS2 as we expect the hb thread to be r/w to the hb area atleast once every 12 secs (default). Bug with the fix has been filed with Red Hat and Novell. For more, refer to the tracker bug filed on bugzilla: http://oss.oracle.com/bugzilla/show_bug.cgi?id=671 Till this issue is resolved, one is advised to use the "deadline" io scheduler. To use deadline, add "elevator=deadline" to the kernel command line as follows: 1. For SLES9, edit the command line in /boot/grub/menu.lst. title Linux 2.6.5-7.244-bigsmp elevator=deadline kernel (hd0,4)/boot/vmlinuz-2.6.5-7.244-bigsmp root=/dev/sda5 vga=0x314 selinux=0 splash=silent resume=/dev/sda3 elevator=deadline showopts console=tty0 console=ttyS0,115200 noexec=off initrd (hd0,4)/boot/initrd-2.6.5-7.244-bigsmp 2. For RHEL4, edit the command line in /boot/grub/grub.conf: title Red Hat Enterprise Linux AS (2.6.9-22.EL) root (hd0,0) kernel /vmlinuz-2.6.9-22.EL ro root=LABEL=/ console=ttyS0,115200 console=tty0 elevator=deadline noexec=off initrd /initrd-2.6.9-22.EL.img To see the current kernel command line, do: # cat /proc/cmdline ============================================================================== Quorum and Fencing ------------------ Q01 What is a quorum? A01 A quorum is a designation given to a group of nodes in a cluster which are still allowed to operate on shared storage. It comes up when there is a failure in the cluster which breaks the nodes up into groups which can communicate in their groups and with the shared storage but not between groups. Q02 How does OCFS2's cluster services define a quorum? A02 The quorum decision is made by a single node based on the number of other nodes that are considered alive by heartbeating and the number of other nodes that are reachable via the network. A node has quorum when: * it sees an odd number of heartbeating nodes and has network connectivity to more than half of them. or * it sees an even number of heartbeating nodes and has network connectivity to at least half of them *and* has connectivity to the heartbeating node with the lowest node number. Q03 What is fencing? A03 Fencing is the act of forecefully removing a node from a cluster. A node with OCFS2 mounted will fence itself when it realizes that it doesn't have quorum in a degraded cluster. It does this so that other nodes won't get stuck trying to access its resources. Currently OCFS2 will panic the machine when it realizes it has to fence itself off from the cluster. As described in Q02, it will do this when it sees more nodes heartbeating than it has connectivity to and fails the quorum test. Q04 How does a node decide that it has connectivity with another? A04 When a node sees another come to life via heartbeating it will try and establish a TCP connection to that newly live node. It considers that other node connected as long as the TCP connection persists and the connection is not idle for 10 seconds. Once that TCP connection is closed or idle it will not be reestablished until heartbeat thinks the other node has died and come back alive. Q05 How long does the quorum process take? A05 First a node will realize that it doesn't have connectivity with another node. This can happen immediately if the connection is closed but can take a maximum of 10 seconds of idle time. Then the node must wait long enough to give heartbeating a chance to declare the node dead. It does this by waiting two iterations longer than the number of iterations needed to consider a node dead (see Q03 in the Heartbeat section of this FAQ). The current default of 7 iterations of 2 seconds results in waiting for 9 iterations or 18 seconds. By default, then, a maximum of 28 seconds can pass from the time a network fault occurs until a node fences itself. Q06 How can one avoid a node from panic-ing when one shutdowns the other node in a 2-node cluster? A06 This typically means that the network is shutting down before all the OCFS2 volumes are being umounted. Ensure the ocfs2 init script is enabled. This script ensures that the OCFS2 volumes are umounted before the network is shutdown. To check whether the service is enabled, do: # chkconfig --list ocfs2 ocfs2 0:off 1:off 2:on 3:on 4:on 5:on 6:off Q07 How does one list out the startup and shutdown ordering of the OCFS2 related services? A07 To list the startup order for runlevel 3 on RHEL4, do: # cd /etc/rc3.d # ls S*ocfs2* S*o2cb* S*network* S10network S24o2cb S25ocfs2 To list the shutdown order on RHEL4, do: # cd /etc/rc6.d # ls K*ocfs2* K*o2cb* K*network* K19ocfs2 K20o2cb K90network To list the startup order for runlevel 3 on SLES9, do: # cd /etc/init.d/rc3.d # ls S*ocfs2* S*o2cb* S*network* S05network S07o2cb S08ocfs2 To list the shutdown order on SLES9, do: # cd /etc/init.d/rc3.d # ls K*ocfs2* K*o2cb* K*network* K14ocfs2 K15o2cb K17network Please note that the default ordering in the ocfs2 scripts only include the network service and not any shared-device specific service, like iscsi. If one is using iscsi or any shared device requiring a service to be started and shutdown, please ensure that that service runs before and shutsdown after the ocfs2 init service. ============================================================================== Novell SLES9 ------------ Q01 Why are OCFS2 packages for SLES9 not made available on oss.oracle.com? A01 OCFS2 packages for SLES9 are available directly from Novell as part of the kernel. Same is true for the various Asianux distributions and for ubuntu. As OCFS2 is now part of the mainline kernel (http://lwn.net/Articles/166954/), we expect more distributions to bundle the product with the kernel. Q02 What versions of OCFS2 are available with SLES9 and how do they match with the Red Hat versions available on oss.oracle.com? A02 As both Novell and Oracle ship OCFS2 on different schedules, the package versions do not match. We expect to resolve itself over time as the number of patch fixes reduce. Novell is shipping two SLES9 releases, viz., SP2 and SP3. The latest kernel with the SP2 release is 2.6.5-7.202.7. It ships with OCFS2 1.0.8. The latest kernel with the SP3 release is 2.6.5-7.257. It ships with OCFS2 1.2.1. ============================================================================== What's New in 1.2 ----------------- Q01 What is new in OCFS2 1.2? A01 OCFS2 1.2 has two new features: a) It is endian-safe. With this release, one can mount the same volume concurrently on x86, x86-64, ia64 and big endian architectures ppc64 and s390x. b) Supports readonly mounts. The fs uses this feature to auto remount ro when encountering on-disk corruptions (instead of panic-ing). Q02 Do I need to re-make the volume when upgrading? A02 No. OCFS2 1.2 is fully on-disk compatible with 1.0. Q03 Do I need to upgrade anything else? A03 Yes, the tools needs to be upgraded to ocfs2-tools 1.2. ocfs2-tools 1.0 will not work with OCFS2 1.2 nor will 1.2 tools work with 1.0 modules. ============================================================================== Upgrading to the latest release ------------------------------- Q01 How do I upgrade to the latest release? A01 1. Download the latest ocfs2-tools and ocfs2console for the target platform and the appropriate ocfs2 module package for the kernel version, flavor and architecture. (For more, refer to the "Download and Install" section above.) 2. Umount all OCFS2 volumes. # umount -at ocfs2 3. Shutdown the cluster and unload the modules. # /etc/init.d/o2cb offline # /etc/init.d/o2cb unload 4. If required, upgrade the tools and console. # rpm -Uvh ocfs2-tools-1.2.1-1.i386.rpm ocfs2console-1.2.1-1.i386.rpm 5. Upgrade the module. # rpm -Uvh ocfs2-2.6.9-22.0.1.ELsmp-1.2.2-1.i686.rpm 6. Ensure init services ocfs2 and o2cb are enabled. # chkconfig --add o2cb # chkconfig --add ocfs2 7. To check whether the services are enabled, do: # chkconfig --list o2cb o2cb 0:off 1:off 2:on 3:on 4:on 5:on 6:off # chkconfig --list ocfs2 ocfs2 0:off 1:off 2:on 3:on 4:on 5:on 6:off 8. At this stage one could either reboot the node or simply, restart the cluster and mount the volume. Q02 Can I do a rolling upgrade from 1.0.x/1.2.x to 1.2.2? A02 Rolling upgrade to 1.2.2 is not recommended. Shutdown the cluster on all nodes before upgrading the nodes. Q03 After upgrade I am getting the following error on mount "mount.ocfs2: Invalid argument while mounting /dev/sda6 on /ocfs". A03 Do "dmesg | tail". If you see the error: >> ocfs2_parse_options:523 ERROR: Unrecognized mount option >> "heartbeat=local" or missing value it means that you are trying to use the 1.2 tools and 1.0 modules. Ensure that you have unloaded the 1.0 modules and installed and loaded the 1.2 modules. Use modinfo to determine the version of the module installed and/or loaded. Q04 The cluster fails to load. What do I do? A04 Check "demsg | tail" for any relevant errors. One common error is as follows: >> SELinux: initialized (dev configfs, type configfs), not configured for labeling >> audit(1139964740.184:2): avc: denied { mount } for ... The above error indicates that you have SELinux activated. A bug in SELinux does not allow configfs to mount. Disable SELinux by setting "SELINUX=disabled" in /etc/selinux/config. Change is activated on reboot. ============================================================================== Processes --------- Q01 List and describe all OCFS2 threads? A01 [o2net] One per node. Is a workqueue thread started when the cluster is brought online and stopped when offline. It handles the network communication for all threads. It gets the list of active nodes from the o2hb thread and sets up tcp/ip communication channels with each active node. It sends regular keepalive packets to detect any interruption on the channels. [user_dlm] One per node. Is a workqueue thread started when dlmfs is loaded and stopped on unload. (dlmfs is an in-memory file system which allows user space processes to access the dlm in kernel to lock and unlock resources.) Handles lock downconverts when requested by other nodes. [ocfs2_wq] One per node. Is a workqueue thread started when ocfs2 module is loaded and stopped on unload. Handles blockable file system tasks like truncate log flush, orphan dir recovery and local alloc recovery, which involve taking dlm locks. Various code paths queue tasks to this thread. For example, ocfs2rec queues orphan dir recovery so that while the task is kicked off as part of recovery, its completion does not affect the recovery time. [o2hb-14C29A7392] One per heartbeat device. Is a kernel thread started when the heartbeat region is populated in configfs and stopped when it is removed. It writes every 2 secs to its block in the heartbeat region to indicate to other nodes that that node is alive. It also reads the region to maintain a nodemap of live nodes. It notifies o2net and dlm any changes in the nodemap. [ocfs2vote-0] One per mount. Is a kernel thread started when a volume is mounted and stopped on umount. It downgrades locks when requested by other nodes in reponse to blocking ASTs (BASTs). It also fixes up the dentry cache in reponse to files unlinked or renamed on other nodes. [dlm_thread] One per dlm domain. Is a kernel thread started when a dlm domain is created and stopped when destroyed. This is the core dlm which maintains the list of lock resources and handles the cluster locking infrastructure. [dlm_reco_thread] One per dlm domain. Is a kernel thread which handles dlm recovery whenever a node dies. If the node is the dlm recovery master, it remasters all the locks owned by the dead node. [dlm_wq] One per dlm domain. Is a workqueue thread. o2net queues dlm tasks on this thread. [kjournald] One per mount. Is used as OCFS2 uses JDB for journalling. [ocfs2cmt-0] One per mount. Is a kernel thread started when a volume is mounted and stooped on umount. Works in conjunction with kjournald. [ocfs2rec-0] Is started whenever another node needs to be be recovered. This could be either on mount when it discovers a dirty journal or during operation when hb detects a dead node. ocfs2rec handles the file system recovery and it runs after the dlm has finished its recovery. ============================================================================== ./ocfs2-tools-1.6.4/documentation/users_guide.txt0000664000176100017610000002512710673531131016717 00000000000000OCFS2 Users Guide 1. Introduction 2. Installation 2.1 Installing from source 2.2 Installing from RPM 3. Configuration (/etc/ocfs2/cluster.conf) 3.1. Valid parameters: 3.2. /etc/ocfs2/cluster.conf sample 3.3. Generate the configuration file. 3.3.1. Using ocfs2console (GUI) interface. 3.3.2. Using o2cb_ctl command line Interface. 3.4. Starting the OCFS2 Clustering Services 3.4.1. Enabling automatic load on boot. 3.4.2. Performing manual load. 3.4.3. Stopping O2CB. 3.5 If o2cb.init does not work on your platform 4. Creating an OCFS2 partition. 5. Mounting the OCFS2 partition. 1. Introduction ------------ OCFS2 is a general purpose cluster filesystem. Unlike the initial release of OCFS, which supported only Oracle database workloads, OCFS2 provides full support as a general purpose filesystem. OCFS2 is a complete rewrite of the previous version, designed to work as a seamless addition to the Linux kernel. 2. Installation ------------ If you are using an official OCFS2 release then the only supported method for installation is from RPM. 2.2. Installing from source ====================== You can always get the latest OCFS2 kernel source via the subversion tree: http://oss.oracle.com/projects/ocfs2/src/trunk/ Additionally, we provide a set of git tree's to pull from at: http://oss.oracle.com/git/ocfs2.git/ http://oss.oracle.com/git/ocfs2-dev.git/ The ocfs2-dev.git tree can be considered our development tree which is kept as up to date with the subversion tree as possible. ocfs2.git is a ready-for-submission tree of clean patch sets. You'll also want to get the latest ocfs2-tools subversion tree: http://oss.oracle.com/projects/ocfs2-tools/src/trunk/ Additionally we make tarballs available at: http://oss.oracle.com/projects/ocfs2-tools/files/source/ Installing ocfs2-tools is done via the standard autoconf setup of "./configure && make && make install". You will likely want to use the init script provided in vendor/common/o2cb.init - it was written for SLES9 and RHEL4 but may work on other platforms. 2.2. Installing from RPM =================== Three RPMs are required to install OCFS2. These RPMs can be obtained from the ocfs2-tools download site, http://oss.oracle.com/projects/ocfs2-tools/files/ ocfs2-tools (OCFS2 support tools) ocfs2console (GUI Interface) ocfs2 (kernel modules). 'ocfs2-tools' and 'ocfs2console' are generic for each architecture that OCFS2 supports (x86, ia64, x86_64 or ppc64). The 'ocfs2' package contains the kernel modules, which must match up exactly with the running kernel version (`uname -r` including -smp/-bigsmp/-hugemem/etc.) The naming convention for these packages is: ocfs2console-..rpm ocfs2tools-..rpm (e.g.: ocfs2console-0.99.699-1.i386.rpm) ocfs2--..rpm (e.g.: ocfs2-2.6.9-5.EL-0.99.2015-1.i686.rpm) 3. Configuration (/etc/ocfs2/cluster.conf) --------------------------------------- The main configuration file for OCFS2 is '/etc/ocfs2/cluster.conf'. This file should be the same on all nodes in the cluster, and changes to this file must be propagated to the other nodes in the cluster. If a new node is being added to the cluster, all existing nodes must have their 'cluster.conf' updated BEFORE mounting the ocfs2 partition from the new node. OCFS2 provides and strongly recommends generating and editing this file using 'ocfs2console'. This file can also be created using 'o2cb_ctl'. Refer to the man pages for more details on these commands. The configuration file /etc/ocfs2/cluster.conf is in stanza format, with one stanza describing the generic cluster attributes and one stanza for each node. 3.1. Valid parameters: ================ 3.1. Valid parameters for the cluster stanza ======================================= node_count - This parameter specifies the number of nodes in the cluster. This parameter is exclusive for cluster stanza. name - This parameter identifies the name of the cluster. 3.1. Valid parameters for the node stanza ==================================== ip_port - This parameter specifies what IP port will be used by the OCFS2 cluster stack to communicate to the other nodes. ip_address - IP address of the OCFS2 interconnect inteface. number - Node number in the cluster. For this parameter, there are two rules that needs to be followed. The node number has to be unique. name - This parameter specifies the name of this node. cluster - This is the name of the cluster. Has to match with the name specified in the cluster stanza. 3.2. /etc/ocfs2/cluster.conf sample: ============================== cluster: node_count = 3 name = OCFS2CLUSTER node: ip_port = 7777 ip_address = 139.185.118.107 number = 0 name = test1 cluster = OCFS2CLUSTER node: ip_port = 7777 ip_address = 139.185.118.106 number = 1 name = test2 cluster = OCFS2CLUSTER 3.3. Generate the configuration file. ------------------------------- 3.3.1. Using ocfs2console (GUI) interface. ---------------------------------- OCFS2 also provides a graphical utility for configuring and modifying your OCFS2 cluster. If your system has the graphical interface enabled, you can launch 'ocfs2console' to enter the graphical configuration utility. If X is running as non-root, you can use 'ssh -X root@localhost' to become root. This will allow you to run X applications as root on your current display. myuser:/home/myuser> $ ssh -X root@localhost Password: root@localhost> # ocfs2console When ocfs2console interface opens, proceed with the initial configuration. 3.3.2. Using o2cb_ctl command line Interface. ------------------------------------- This not the recommended method for creating the configuration file, but it can be used by determined users who have read and understood the 'o2cb_ctl' man page. The entire process must be performed as root. The example below will show how to create the cluster "mycluster" with two nodes (node1 and node2). First, create the cluster: # o2cb_ctl -C -n mycluster -t cluster -a name=mycluster -a node_count=2 Then, add two nodes: # o2cb_ctl -C -n node1 -t node -a number=0 -a ip_address=139.185.118.5 \ -a ip_port=7777 -a cluster=mycluster # o2cb_ctl -C -n node2 -t node -a number=0 -a ip_address=139.185.118.5 \ -a ip_port=7777 -a cluster=mycluster NOTE: During the initial creation of the configuration file, you should not make use of the o2cb_ctl parameter "-i" since there is no live configuration active. 3.4. Starting the OCFS2 Clustering Services ====================================== O2CB is the module that provides the clustering services for OCFS2. It is reponsible for node heartbeat, node management and Distributed Lock Manager (DLM). 3.4.1. Enabling automatic load on boot. =============================== To enable the automatic load of the O2CB driver on boot, execute the following script and answer the prompt. Make sure to enter the cluster name when asked or the load will fail at boot. # /etc/init.d/o2cb configure Configuring the O2CB driver. This will configure the on-boot properties of the O2CB driver. The following questions will determine whether the driver is loaded on boot. The current values will be shown in brackets ('[]'). Hitting without typing an answer will keep that current value. Ctrl-C will abort. Load O2CB driver on boot (y/n) [n]: y Cluster to start on boot (Enter "none" to clear) []: Writing O2CB configuration: OK This will configure O2CB to be loaded on boot and will load the ocfs2 modules on the next startup. 3.4.2. Performing manual load. ====================== If you don't want to configure O2CB to start on boot and don't want to configure a specific cluster to start by default, run the following commands to startup your ocfs2 cluster. # /etc/init.d/o2cb load # /etc/init.d/o2cb online mycluster This loads the modules and the live configuration of the cluster. This will not cause OCFS2 to load at boot time. 3.4.3. Stopping O2CB. ============= To stop a cluster and unload the modules: # /etc/init.d/o2cb stop 3.5 If o2cb.init does not work on your platform =========================================== Create your pseudo file system mount points: # mkdir /config /dlm Install the modules. Modprobe makes this easy: # modprobe ocfs2_dlmfs This will load configfs, ocfs2_nodemanager, ocfs2_dlm, ocfs2_dlmfs. Mount your configfs file system: # mount -t configfs none /config Mount your dlmfs file system: # mount -t ocfs2_dlmfs none /dlm Start your cluster (fill in 'CLUSTERNAME'): # o2cb_ctl -H -n CLUSTERNAME -t cluster -a online=yes You can now mount your OCFS2 partitions (see step 5) To stop the OCFS2 cluster services, make sure that all OCFS2 file systems are unmounted and then execute: # o2cb_ctl -H -n CLUSTERNAME -t cluster -a online=no 4. Creating an OCFS2 partition. --------------------------- Again, all steps here must be performed as root. Create a new physical partition using fdisk (or parted if it is an ia64 architecture). There is a minimum size for OCFS2 partitions, to store metadata and per-node information on disk. To calculate the minimal partition size for OCFS, use this formula: ((<#nodes> * ) + 40Mb) + Pseudo filesystems -> Userspace-driven configuration filesystem ocfs2_nodemanager File systems -> OCFS2 file system support ocfs2_dlm File systems -> OCFS2 file system support ocfs2_dlmfs File systems -> OCFS2 file system support ./ocfs2-tools-1.6.4/debian/changelog0000644000176100017610000002143411115551034014052 00000000000000ocfs2-tools (1.3.9-1) UNRELEASED; urgency=low * Update default timeouts in template and translations files. * debian/rules: fix clean target to not purge upstream patches/ directory. * debian/control: rework Build-Depends - sort them: debian build specific bits first, upstream after in configure check order. - add pkg-config. - add libselinux1-dev and libsepol1-dev. * add package ocfs2-tools-static-dev to include all development headers and static libraries required to build ocfs2-test (and possibly other tools that already in development stage. * stop shipping local copy of mount.ocfs2.8 -- Fabio M. Di Nitto Mon, 19 Nov 2007 06:53:59 +0100 ocfs2-tools (1.2.4-1) unstable; urgency=low * The "Lazo rosa" release. * New upstream release. This version was released on Apr 6th, 2007. Main changes are: - Allow network timeout configuration. - Bug fixes. - offsetof(3) issues have been fixed, so patches/102_stddef.h is no longer relevant. * Added debconf support for O2CB_IDLE_TIMEOUT_MS, O2CB_KEEPALIVE_DELAY_MS and O2CB_RECONNECT_DELAY_MS in postinst, config and templates mainly from Ubuntu. * po/es.po: While at it, updated Spanish translation. * po/vi.po: Updated Vietnamese translation, thanks to Clytie Siddall (closes: #438451). * po/ru.po: Updated Russian translation, thanks to Yuri Kozlov (closes: #438633). * po/fr.po: Updated French translation. Thanks to Jean-Baka Domelevo-Entfellner (closes: #440579). * po/cs.po: Updated Czech translation. Thanks to Miroslav Kure (closes: #442903). * Added /etc/init.d/ocfs2 in order to mount and unmount OCFS2 volumes, that I simply missed on past releases. This allows to unmount OCFS2 during a reboot and thus avoid a panic (closes: #416550). * debian/rules: Removed old code for quilt patching now that we include the Makefile from that package. * This version does not fail to build twice in a row (strange...). Closes: #442692. -- David Martínez Moreno Tue, 18 Sep 2007 02:02:31 +0200 ocfs2-tools (1.2.3-1) unstable; urgency=low * New upstream release. This version was released on Feb 2nd, 2007. Main changes are: - Backup superblock support added. - Local mount support added (with kernel 2.6.20+). - Heartbeat thread's IO priority can now be set (with kernel 2.6.20+). - Bugs fixed in fsck, debugfs and console . * Removed parts of debian/NEWS no longer relevant. * Renamed debian/README to debian/README.Debian in order to be included by dh_installdocs. * Added short description to o2cb init script in order to clean a lintian warning. -- David Martínez Moreno Thu, 16 Aug 2007 02:41:22 +0200 ocfs2-tools (1.2.2-1) unstable; urgency=low * New upstream release. This version was released on Oct 20th, 2006. Main changes are: - tunefs.ocfs2: Volumes can be resized offline. - debugfs.ocfs2: Commands bmap, findpath, ncheck and decode added. - Fixed bug in o2cb_ctl when adding nodes (closes: #405353). - Fixed lots of bugs. * Removed ocfs2console/blkid/blkid_types.h, that slipped in 1.2.1-1.2. * Acknowledged NMUs (closes: #380879, #389916). * Added Dutch translation (thanks, cobaco). Closes: #436863. * Merged 01-manpages-typos and some parts of 02-init-typos patches upstream. * debian/rules: Changed dh_install to --list-missing in order to ignore temporally the now installed headers. * debian/control: Replaced Source-Version with binary:Version. -- David Martínez Moreno Wed, 15 Aug 2007 02:46:28 +0200 ocfs2-tools (1.2.1-1.4) unstable; urgency=low * Non-maintainer upload. * add patches/102_stddef.h to fix FTBFS (missing #include to know about offsetof). closes: #428949. -- Pierre Habouzit Wed, 18 Jul 2007 17:37:23 +0200 ocfs2-tools (1.2.1-1.3) unstable; urgency=low * Non-maintainer upload to fix longstanding l10n issues * Fix the spelling of "milliseconds" in debconf templates * Unmark a string for translation. Closes: #372520 * Debconf templates translations: - Czech updated. Closes: #369582 - French updated. Closes: #374335 - Vietnamese added. Sent during the call for updates of the NMU campaign. - Swedish added. Sent during the call for updates of the NMU campaign. - German added. Sent during the call for updates of the NMU campaign. - Russian added. Sent during the call for updates of the NMU campaign. - Brazilian Portuguese added. Sent during the call for updates of the NMU campaign. - Fix the encoding of the Spanish translation..:-) -- Christian Perrier Mon, 18 Dec 2006 19:49:10 +0100 ocfs2-tools (1.2.1-1.2) unstable; urgency=medium * Non-maintainer upload. * Move dh_installdeb to after dh_pysupport, to make sure update-python-modules is indeed called in postinst. (Closes: #388529) -- Steinar H. Gunderson Thu, 28 Sep 2006 13:19:03 +0200 ocfs2-tools (1.2.1-1.1) unstable; urgency=low * Non-maintainer upload. * Update package to the last python policy (Closes: #380879). -- Pierre Habouzit Thu, 31 Aug 2006 13:45:20 +0200 ocfs2-tools (1.2.1-1) unstable; urgency=low * New upstream release (closes: #362204, #364549). This release also fixes the double-free error that new glibc triggered, so closes: #358784 as well. * Added Czech debconf translation. Thanks, Miroslav Kure. Closes: #353372. * Added French debconf translation. Thanks, Julien Rosal. Closes: #354274. * Rewrote debconf templates, rendering above changes partly useless. Thanks to Thomas Huriaux for the time and the patch. Closes: #352505. * Updated Spanish translation. * debian/control: - Added libdevmapper-dev to Build-Depends, and bumped debhelper dependency to >= 5. - Bumped Standards-Version to 3.7.2.0. * Added ocfs2_faq.txt to docs. * debian/compat: Bumped debhelper compatibility to 5. * Added README.Debian. * Removed changes in init script, now it is near to the original one. Many thanks to Joel Becker from Oracle for taking the time to explain it thoroughly. The modular case works again, I have embraced the faith. :-) Closes: #363121. -- David Martínez Moreno Tue, 30 May 2006 00:38:27 +0200 ocfs2-tools (1.1.5-2) unstable; urgency=low * Removed by upstream request: - usr/sbin/find_hardlinks - usr/sbin/find_dup_extents - usr/sbin/find_inode_paths - usr/sbin/set_random_bits - usr/sbin/decode_lockres - usr/sbin/encode_lockres - usr/sbin/mark_journal_dirty These utilities are for OCFS2 development only, and may cause severe data loss, apart from little use for normal OCFS2 user. * debian/control: Added quilt to Build-Depends, and rewrite part of the build system in order to support patch and unpatch targets. * Created patches: - debian/patches/01-manpages-typos -- David Martínez Moreno Fri, 10 Feb 2006 02:53:40 +0100 ocfs2-tools (1.1.5-1) unstable; urgency=low * New upstream release (closes: #329699). * debian/control: - Bumped Standards-Version to 3.6.2.2. - Added python-gtk2 to ocfs2console Depends. - Added po-debconf to Build-Depends. * debian/copyright: Updated date and FSF's address. * fsck.ocfs2/fsck.ocfs2.8.in: Killed two birds in a row: fixed tytso's surname and removed another lintian error. * Added to ocfs2-tools.install: - usr/sbin/find_hardlinks - usr/sbin/find_dup_extents - usr/sbin/find_inode_paths - usr/sbin/set_random_bits - usr/sbin/decode_lockres - usr/sbin/encode_lockres - usr/sbin/mark_journal_dirty * debian/rules: - Update dh_installinit call to not restart the cluster on updates and to start ocfs2 very early in the boot process. - Added --fail-missing to dh_install for tracking down new binaries in future versions. - Added code to remove stuff from the diff.gz. * Added debconf infrastructure for avoiding running "/etc/init.d/o2cb configure". The skeleton was stolen from an Ubuntu grave. While at it, added Spanish translation of debconf templates. -- David Martínez Moreno Thu, 26 Jan 2006 02:10:48 +0100 ocfs2-tools (0.99.12-1) unstable; urgency=low * First public release. * Copied shamelessly a lot of the Ubuntu diff to the Debian package (thanks to Fabionne). * Changed /bin/sh to /bin/bash in the init script to avoid evident bashisms. * Stripped down debian/ directory from the original tarball. * Fixed some typos in the init.d script and in the default configuration. Also added to the init script some Oracle string in order to ease identification in the boot process. -- David Martínez Moreno Mon, 18 Jul 2005 19:01:39 +0200 ./ocfs2-tools-1.6.4/debian/compat0000644000176100017610000000000211115551034013372 000000000000005 ./ocfs2-tools-1.6.4/debian/control0000644000176100017610000000454311115551034013605 00000000000000Source: ocfs2-tools Section: admin Priority: optional Maintainer: David Martínez Moreno Standards-Version: 3.7.2.0 Build-Depends: debhelper (>= 5), po-debconf, python-support (>= 0.4), quilt, pkg-config, comerr-dev, uuid-dev, libncurses5-dev, libreadline5-dev, libglib2.0-dev (>= 2.2.3), libblkid-dev (>= 1.36), libdevmapper-dev, libselinux1-dev, libsepol1-dev, python-dev, python-gtk2 Package: ocfs2-tools Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Section: admin Suggests: ocfs2console Description: tools for managing OCFS2 cluster filesystems OCFS2 is a general purpose cluster filesystem. Unlike the initial release of OCFS, which supported only Oracle database workloads, OCFS2 provides full support as a general purpose filesystem. OCFS2 is a complete rewrite of the previous version, designed to work as a seamless addition to the Linux kernel. . This package installs the tools to manage the OCFS2 filesystem, including mkfs, tunefs, fsck, debugfs, and the utilities to control the O2CB clustering stack. Package: ocfs2-tools-static-dev Architecture: any Depends: ${shlibs:Depends}, ocfs2-tools (= ${Source-Version}) Section: devel Description: tools for managing OCFS2 cluster filesystems - development files OCFS2 is a general purpose cluster filesystem. Unlike the initial release of OCFS, which supported only Oracle database workloads, OCFS2 provides full support as a general purpose filesystem. OCFS2 is a complete rewrite of the previous version, designed to work as a seamless addition to the Linux kernel. . This package installs the development headers and static libraries. Package: ocfs2console Architecture: any Depends: ${shlibs:Depends}, ${python:Depends}, ocfs2-tools (= ${binary:Version}), python-gtk2 Section: admin Description: tools for managing OCFS2 cluster filesystems (graphical interface) OCFS2 is a general purpose cluster filesystem. Unlike the initial release of OCFS, which supported only Oracle database workloads, OCFS2 provides full support as a general purpose filesystem. OCFS2 is a complete rewrite of the previous version, designed to work as a seamless addition to the Linux kernel. . A GUI frontend for managing OCFS2 volumes on the system. One can mount and unmount volumes, format, view overview information and individual files, and view and modify the current cluster configuration. ./ocfs2-tools-1.6.4/debian/copyright0000644000176100017610000000205611115551034014132 00000000000000This package was debianized by David Martínez Moreno on Tue, 5 Jul 2005 17:02:00 +0200. It was downloaded from http://oss.oracle.com/projects/ocfs2-tools/files/source/ Copyright: (c) 2004-2007 Oracle Corporation, All Rights Reserved. License: 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL file. ./ocfs2-tools-1.6.4/debian/ocfs2-tools.config0000644000176100017610000000264211115551034015541 00000000000000#!/bin/sh set -e ## Source debconf library. . /usr/share/debconf/confmodule ## be sure to read the values from the config file. if [ -e /etc/default/o2cb ]; then . /etc/default/o2cb if [ -z "$O2CB_HEARTBEAT_THRESHOLD" ];then O2CB_HEARTBEAT_THRESHOLD=7 fi if [ -z "$O2CB_IDLE_TIMEOUT_MS" ];then O2CB_IDLE_TIMEOUT_MS=10000 fi if [ -z "$O2CB_KEEPALIVE_DELAY_MS" ];then O2CB_KEEPALIVE_DELAY_MS=5000 fi if [ -z "$O2CB_RECONNECT_DELAY_MS" ];then O2CB_RECONNECT_DELAY_MS=2000 fi db_set ocfs2-tools/init "$O2CB_ENABLED" db_set ocfs2-tools/clustername "$O2CB_BOOTCLUSTER" db_set ocfs2-tools/heartbeat_threshold "$O2CB_HEARTBEAT_THRESHOLD" db_set ocfs2-tools/idle_timeout "$O2CB_IDLE_TIMEOUT_MS" db_set ocfs2-tools/keepalive_delay "$O2CB_KEEPALIVE_DELAY_MS" db_set ocfs2-tools/reconnect_delay "$O2CB_RECONNECT_DELAY_MS" fi if [ "$1" = "configure" ] || [ "$1" = "reconfigure" ]; then db_input medium ocfs2-tools/init || true db_go || true db_get ocfs2-tools/init if [ "$RET" = "true" ]; then db_input medium ocfs2-tools/clustername || true db_go || true db_input medium ocfs2-tools/heartbeat_threshold || true db_go || true db_input low ocfs2-tools/idle_timeout || true db_go || true db_input low ocfs2-tools/keepalive_delay || true db_go || true db_input low ocfs2-tools/reconnect_delay || true db_go || true fi fi #DEBHELPER# ./ocfs2-tools-1.6.4/debian/ocfs2-tools.docs0000644000176100017610000000013211115551034015214 00000000000000README.O2CB CREDITS MAINTAINERS documentation/users_guide.txt documentation/ocfs2_faq.txt ./ocfs2-tools-1.6.4/debian/ocfs2-tools.install0000644000176100017610000000102311515641543015743 00000000000000sbin/debugfs.ocfs2 sbin/fsck.ocfs2 sbin/mkfs.ocfs2 sbin/mount.ocfs2 sbin/mounted.ocfs2 sbin/o2cb_ctl sbin/ocfs2_hb_ctl sbin/tunefs.ocfs2 usr/bin/o2info usr/sbin/o2hbmonitor usr/share/man/man8/debugfs.ocfs2.8 usr/share/man/man8/fsck.ocfs2.8 usr/share/man/man8/fsck.ocfs2.checks.8 usr/share/man/man8/mkfs.ocfs2.8 usr/share/man/man8/mount.ocfs2.8 usr/share/man/man8/mounted.ocfs2.8 usr/share/man/man7/o2cb.7 usr/share/man/man8/o2cb_ctl.8 usr/share/man/man8/ocfs2_hb_ctl.8 usr/share/man/man8/tunefs.ocfs2.8 usr/share/man/man1/o2info.1 ./ocfs2-tools-1.6.4/debian/ocfs2-tools.manpages0000644000176100017610000000073311500500543016063 00000000000000debian/tmp/usr/share/man/man8/debugfs.ocfs2.8 debian/tmp/usr/share/man/man8/fsck.ocfs2.8 debian/tmp/usr/share/man/man8/fsck.ocfs2.checks.8 debian/tmp/usr/share/man/man8/mkfs.ocfs2.8 debian/tmp/usr/share/man/man8/tunefs.ocfs2.8 debian/tmp/usr/share/man/man8/mounted.ocfs2.8 debian/tmp/usr/share/man/man8/o2cb_ctl.8 debian/tmp/usr/share/man/man8/ocfs2_hb_ctl.8 debian/tmp/usr/share/man/man8/o2image.8 debian/tmp/usr/share/man/man7/o2cb.7 debian/tmp/usr/share/man/man1/o2info.1 ./ocfs2-tools-1.6.4/debian/ocfs2-tools.postinst0000644000176100017610000000273311115551034016160 00000000000000#!/bin/sh set -e ## Source debconf library. . /usr/share/debconf/confmodule if [ "$1" = "configure" ] || [ "$1" = "reconfigure" ]; then db_get ocfs2-tools/init O2CB_ENABLED="$RET" db_get ocfs2-tools/clustername O2CB_BOOTCLUSTER="$RET" db_get ocfs2-tools/heartbeat_threshold O2CB_HEARTBEAT_THRESHOLD="$RET" db_get ocfs2-tools/idle_timeout O2CB_IDLE_TIMEOUT_MS="$RET" db_get ocfs2-tools/keepalive_delay O2CB_KEEPALIVE_DELAY_MS="$RET" db_get ocfs2-tools/reconnect_delay O2CB_RECONNECT_DELAY_MS="$RET" cat > /etc/default/o2cb </dev/null || /usr/bin/which rpm 2>/dev/null || echo /bin/false) SUSEBUILD = $(shell if test -r /etc/SuSE-release; then echo yes; else echo no; fi) PYVERSION = $(shell echo $(pyexecdir) | sed -e 's/.*python\([0-9]\.[0-9]\).*/\1/') ifeq ($(SUSEBUILD),yes) PYGTK_NAME = python-gtk CHKCONFIG_DEP = aaa_base COMPILE_PY = 0 else PYGTK_NAME = pygtk2 CHKCONFIG_DEP = chkconfig COMPILE_PY = 1 endif SUBDIRS = include libtools-internal libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image o2info o2monitor listuuid sizetest extras fswreck patches ifdef BUILD_OCFS2CONSOLE SUBDIRS += ocfs2console endif SUBDIRS += vendor PKGCONFIG_SOURCES = \ o2cb.pc.in \ o2dlm.pc.in \ ocfs2.pc.in PKGCONFIG_FILES = $(patsubst %.pc.in,%.pc,$(PKGCONFIG_SOURCES)) DEBIAN_FILES = \ debian/README.Debian \ debian/changelog \ debian/compat \ debian/control \ debian/copyright \ debian/ocfs2-tools.config \ debian/ocfs2-tools.docs \ debian/ocfs2-tools.install \ debian/ocfs2-tools.manpages \ debian/ocfs2-tools.postinst \ debian/ocfs2-tools.postrm \ debian/ocfs2-tools.templates \ debian/ocfs2console.install \ debian/ocfs2console.manpages \ debian/ocfs2-tools-static-dev.install \ debian/rules DIST_FILES = \ COPYING \ CREDITS \ MAINTAINERS \ README \ README.O2CB \ Config.make.in \ Preamble.make \ Postamble.make \ aclocal.m4 \ blkid.m4 \ glib-2.0.m4 \ mbvendor.m4 \ python.m4 \ pythondev.m4 \ runlog.m4 \ config.guess \ config.sub \ configure \ configure.in \ install-sh \ mkinstalldirs \ rpmarch.guess \ svnrev.guess \ Vendor.make \ vendor.guess \ documentation/ocfs2_faq.txt \ documentation/users_guide.txt \ documentation/samples/cluster.conf \ $(PKGCONFIG_SOURCES) \ $(DEBIAN_FILES) DIST_RULES = dist-subdircreate .PHONY: dist dist-subdircreate dist-bye dist-fresh distclean dist-subdircreate: $(TOPDIR)/mkinstalldirs $(DIST_DIR)/documentation/samples $(TOPDIR)/mkinstalldirs $(DIST_DIR)/debian dist-bye: -rm -rf $(DIST_TOPDIR) dist-fresh: dist-bye $(TOPDIR)/mkinstalldirs $(DIST_TOPDIR) dist: dist-fresh dist-all GZIP=$(GZIP_OPTS) tar chozf $(DIST_TOPDIR).tar.gz $(DIST_TOPDIR) $(MAKE) dist-bye distclean: clean rm -f Config.make config.status config.cache config.log $(PKGCONFIG_FILES) INSTALL_RULES = install-pkgconfig install-pkgconfig: $(PKGCONFIG_FILES) $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(libdir)/pkgconfig for p in $(PKGCONFIG_FILES); do \ $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/pkgconfig/$$p; \ done include Vendor.make def: @echo $(TOOLSARCH) include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/COPYING0000664000176100017610000004311010673531131012012 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ./ocfs2-tools-1.6.4/CREDITS0000644000176100017610000000161011500500543011765 00000000000000fsck.ocfs2: Written by Zach Brown. fsck.ocfs2's behaviour is derived from e2fsck by Theodore Ts'o, Andreas Dilger, Stephen Tweedie, and others. libocfs2: Written by Joel Becker, Zach Brown, and Sunil Mushran Huge portions of libocfs2's API and behavior were derived from libext2fs by Theodore Ts'o, Andreas Dilger, Stephen Tweedie, and others. mkfs.ocfs2: Written by Kurt Hackel. Modified by Manish Singh, Joel Becker, and Mark Fasheh. debugfs.ocfs2: Written by Sunil Mushran. Modified by Mark Fasheh. mounted.ocfs2: Written by Sunil Mushran. tunefs.ocfs2 Written by Sunil Mushran. ocfs2cdsl: Written by Manish Singh. ocfs2console: Written by Manish Singh. o2info: Written by Tristan Ye. ocfs2console/blkid: From e2fsprogs 1.37, by Theodore Ts'o and Andreas Dilger. ocfs2console/ocfs2interface/ipwidget.py: From anaconda 10.1.1.13, by Jonathan Blandford and Michael Fulbright ./ocfs2-tools-1.6.4/MAINTAINERS0000664000176100017610000000070111270441036012451 00000000000000fsck.ocfs2: Zach Brown Joel Becker libocfs2: Joel Becker Zach Brown ocfs2tool: Manish Singh ocfs2cdsl: Manish Singh debugfs.ocfs2: Sunil Mushran mounted.ocfs2: Sunil Mushran tunefs.ocfs2: Sunil Mushran ./ocfs2-tools-1.6.4/README0000664000176100017610000000005210673531131011635 00000000000000These are tools for the OCFS2 filesystem. ./ocfs2-tools-1.6.4/README.O2CB0000664000176100017610000000705610673531131012334 00000000000000 O2CB is a simple set of clustering services required to get OCFS2 going. A more complete cluster infrastructure may replace it later. [Describing Your Cluster Configuration] It is recommended that you use ocfs2console to generate your cluster configuration. The cluster confguration is stored in /etc/ocfs2/cluster.conf. This is a hardcoded name right now (boo!), so you have to put it there. The file is in stanza format, with one stanza describing the generic cluster attributes and one stanza for each node. The stanza for the generic cluster attributes looks like so: cluster: name = ocfs2 node_count = 2 Both attributes are required. The cluster name must start with a letter and be made of the usual [-a-ZA-Z0-9_] characters. The node_count attribute must match the number of node stanzas. Each node is described by a stanza: node: name = ca-test17 cluster = ocfs2 number = 0 ip_address = 139.185.118.117 ip_port = 7777 Each attribute is required. The name has the same character restrictions that the cluster name does. The cluster attribute _must_ match the name of the cluster, or this node stanza will be ignored. [Starting the OCFS2 Clustering Services] O2CB is comprised of a simple node manager, heartbeat, TCP protocol, and DLM. The basic steps in startup are as follows: 1) Load the nodemanager, heartbeat, and tcp modules 2) Mount the nodemanager and heartbeat pseudo filesystems. 3) Load the cluster information via o2cb_ctl. This adds all the known nodes to the nodemanager's psuedo filesystem. 4) Load the DLM module. 5) Load the OCFS2 module. 6) Mount an OCFS2 filesystem. The /etc/init.d/o2cb program is responsible for handling steps 1-3 during the boot of a machine. If you are running from the source tree, the script is located at vendor/common/o2cb.init. Also, the o2cb_ctl program needs to be in your path. It lives at o2cb_ctl/o2cb_ctl in the source tree. To enable steps 1 and 2 on boot: # /etc/init.d/o2cb enable Writing O2CB configuration: OK or: # /etc/init.d/o2cb configure Configuring the O2CB driver. This will configure the on-boot properties of the O2CB driver. The following questions will determine whether the driver is loaded on boot. The current values will be shown in brackets ('[]'). Hitting without typing an answer will keep that current value. Ctrl-C will abort. Load O2CB driver on boot (y/n) [n]: y Cluster to start on boot (Enter "none" to clear) []: Writing O2CB configuration: OK If you want step 3 to occur on boot, you must name the cluster to start: # /etc/init.d/o2cb configure Configuring the O2CB driver. This will configure the on-boot properties of the O2CB driver. The following questions will determine whether the driver is loaded on boot. The current values will be shown in brackets ('[]'). Hitting without typing an answer will keep that current value. Ctrl-C will abort. Load O2CB driver on boot (y/n) [n]: y Cluster to start on boot (Enter "none" to clear) []: ocfs2 Writing O2CB configuration: OK You can now start the cluster by hand as well, with: # /etc/init.d/o2cb start If you don't want to configure O2CB to start on boot, or if you don't want to configure a specific cluster to start by default, you can run the steps manually. To run steps 1 and 2: # /etc/init.d/o2cb load To start a cluster (step 3): # /etc/init.d/o2cb online ocfs2 To stop a cluster and unload the modules, you simply use: # /etc/init.d/o2cb stop Unloading the modules doesn't work right now. ./ocfs2-tools-1.6.4/Config.make.in0000664000176100017610000000352511170734140013434 00000000000000PACKAGE = @PACKAGE@ VERSION = @VERSION@ DIST_VERSION = @DIST_VERSION@ MAJOR_VERSION = @MAJOR_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MICRO_VERSION = @MICRO_VERSION@ EXTRA_VERSION = @EXTRA_VERSION@ SHELL = @SHELL@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ includedir = @includedir@ libdir = @libdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ mandir = @mandir@ root_prefix = @root_prefix@ root_bindir = @root_bindir@ root_sbindir = @root_sbindir@ root_sysconfdir = @root_sysconfdir@ pyexecdir = @pyexecdir@ top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_LIBRARY = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_HEADER = @INSTALL_DATA@ LN_S = @LN_S@ CC = @CC@ CPP = @CPP@ AR = @AR@ RANLIB = @RANLIB@ WARNINGS = -Wall -Wstrict-prototypes -Wmissing-prototypes \ -Wmissing-declarations CFLAGS = @CFLAGS@ CFLAGS += $(WARNINGS) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ VENDOR = @VENDOR@ COM_ERR_CFLAGS = @COM_ERR_CFLAGS@ COM_ERR_LIBS = @COM_ERR_LIBS@ UUID_LIBS = @UUID_LIBS@ READLINE_LIBS = @READLINE_LIBS@ NCURSES_LIBS = @NCURSES_LIBS@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ PYTHON = @PYTHON@ PYTHON_INCLUDES = @PYTHON_INCLUDES@ BLKID_CFLAGS = @BLKID_CFLAGS@ BLKID_LIBS = @BLKID_LIBS@ HAVE_BLKID = @HAVE_BLKID@ LIBDLM_FOUND = @LIBDLM_FOUND@ BUILD_OCFS2CONSOLE = @BUILD_OCFS2CONSOLE@ BUILD_DEBUGOCFS2 = @BUILD_DEBUGOCFS2@ HAVE_COROSYNC = @HAVE_COROSYNC@ BUILD_OCFS2_CONTROLD = @BUILD_OCFS2_CONTROLD@ BUILD_PCMK_SUPPORT = @BUILD_PCMK_SUPPORT@ BUILD_CMAN_SUPPORT = @BUILD_CMAN_SUPPORT@ BUILD_FSDLM_SUPPORT = @BUILD_FSDLM_SUPPORT@ CPG_LDFLAGS = @CPG_LDFLAGS@ AIS_LDFLAGS = @AIS_LDFLAGS@ DL_LIBS = @DL_LIBS@ OCFS2_DEBUG = @OCFS2_DEBUG@ OCFS2_DEBUG_EXE = @OCFS2_DEBUG_EXE@ OCFS2_DYNAMIC_FSCK = @OCFS2_DYNAMIC_FSCK@ OCFS2_DYNAMIC_CTL = @OCFS2_DYNAMIC_CTL@ ./ocfs2-tools-1.6.4/Preamble.make0000644000176100017610000000146711232161243013347 00000000000000ifeq ($(TOPDIR)/Config.make,$(wildcard $(TOPDIR)/Config.make)) include $(TOPDIR)/Config.make else .PHONY: dummy-notconfigured dummy-notconfigured: @echo "Please run the configure script first" endif LIBRARIES = UNINST_LIBRARIES = BIN_PROGRAMS = SBIN_PROGRAMS = UNINST_PROGRAMS = MODULES = HEADERS = MANS = HEADERS_SUBDIR = INSTALL_RULES = CLEAN_FILES = CLEAN_RULES = DIST_FILES = DIST_RULES = INCLUDES = DEFINES = CFLAGS += -pipe # protect with configure? CDEPFLAGS = -MD -MP -MF $(@D)/.$(basename $(@F)).d LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ VERSION_FILES = VERSION_PREFIX = VERSION_SRC = DIST_TOPDIR = $(TOPDIR)/$(PACKAGE)-$(DIST_VERSION) DIST_CURDIR = . DIST_DIR = $(DIST_TOPDIR)/$(DIST_CURDIR) GZIP_OPTS = --best .PHONY: all strip install all: all-rules strip: strip-rules install: install-rules ./ocfs2-tools-1.6.4/Postamble.make0000644000176100017610000001161011115551034013536 00000000000000ifdef VERSION_SRC ifndef VERSION_FILES $(error Need VERSION_FILES defined for version objects) endif ifndef VERSION_PREFIX $(error Need VERSION_PREFIX defined for version objects) endif VERSION_OBJ = $(subst .c,.o,$(VERSION_SRC)) VERSION_NUM = $(VERSION_PREFIX)_BUILD_VERSION VERSION_DATE = $(VERSION_PREFIX)_BUILD_DATE VERSION_MD5 = $(VERSION_PREFIX)_BUILD_MD5 VERDEFS = -D$(VERSION_NUM)=\""$(VERSION)"\" \ -D$(VERSION_DATE)=\""$(shell LANG=C date)"\" \ -D$(VERSION_MD5)=\""$(shell cat stamp-md5)"\" VERMAGIC = $(if $(filter $(VERSION_OBJ),$@),$(VERDEFS)) ifneq ($(MAKECMDGOALS),install) VERSTAMP = stamp endif stamp: ; stamp-md5: $(VERSION_FILES) @cat $(VERSION_FILES) Makefile | md5sum | sed -e 's/ .*//' > stamp-md5 $(VERSION_OBJ): stamp-md5 $(VERSTAMP) endif LOCAL_CFLAGS = $($(subst /,_,$(basename $@))_CFLAGS) LOCAL_CPPFLAGS = $($(subst /,_,$(basename $@))_CPPFLAGS) %.o: %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(INCLUDES) $(DEFINES) $(VERMAGIC) $(CDEPFLAGS) -o $@ -c $< %.p: %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(INCLUDES) $(DEFINES) $(VERMAGIC) -E -o $@ -c $< %.s: %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(INCLUDES) $(DEFINES) $(VERMAGIC) -S -o $@ -c $< .PHONY: subdirs $(SUBDIRS) subdirs: $(SUBDIRS) $(SUBDIRS): $(MAKE) -C $@ .PHONY: all-rules all-rules: subdirs $(UNINST_LIBRARIES) $(LIBRARIES) $(BIN_PROGRAMS) $(SBIN_PROGRAMS) $(UNINST_PROGRAMS) $(MODULES) $(MANS) $(ALL_RULES) INSTALL_SUBDIRS = $(addsuffix -install,$(SUBDIRS)) .PHONY: install-rules install-subdirs $(INSTALL_RULES) install-libraries install-headers install-bin-programs install-bin-extra install-sbin-programs install-sbin-extra install-subdirs: $(INSTALL_SUBDIRS) $(INSTALL_SUBDIRS): $(MAKE) -C $(subst -install,,$@) install install-libraries: $(LIBRARIES) ifdef LIBRARIES $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(libdir) for lib in $(LIBRARIES); do \ $(INSTALL_LIBRARY) $$lib $(DESTDIR)$(libdir)/$$lib; \ done endif ifeq ($(filter /%,$(HEADERS_SUBDIR)),) Hsubdir = /$(HEADERS_SUBDIR) else Hsubdir = $(HEADERS_SUBDIR) endif ifeq ($(filter include/%,$(HEADERS)),) Hinstall = else Hinstall = include/ endif install-headers: $(HEADERS) ifdef HEADERS $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(includedir)$(Hsubdir) for hdr in $(patsubst include/%,%,$(HEADERS)); do \ $(INSTALL_HEADER) $(Hinstall)$$hdr $(DESTDIR)$(includedir)$(Hsubdir)/$$hdr; \ done endif install-bin-programs: $(BIN_PROGRAMS) ifdef BIN_PROGRAMS $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(bindir) for prog in $(BIN_PROGRAMS); do \ $(INSTALL_PROGRAM) $$prog $(DESTDIR)$(bindir)/$$prog; \ done endif install-bin-extra: $(BIN_EXTRA) ifdef BIN_EXTRA $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(bindir) for prog in $(BIN_EXTRA); do \ $(INSTALL_PROGRAM) $$prog $(DESTDIR)$(bindir)/$$prog; \ done endif install-sbin-programs: $(SBIN_PROGRAMS) ifdef SBIN_PROGRAMS $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(sbindir) for prog in $(SBIN_PROGRAMS); do \ $(INSTALL_PROGRAM) $$prog $(DESTDIR)$(sbindir)/$$prog; \ done endif install-sbin-extra: $(SBIN_EXTRA) ifdef SBIN_EXTRA $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(sbindir) for prog in $(SBIN_EXTRA); do \ $(INSTALL_PROGRAM) $$prog $(DESTDIR)$(sbindir)/$$prog; \ done endif install-mans: $(MANS) ifdef MANS $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(mandir) for man in $(MANS); do \ dir=`echo $$man | sed -e 's/^.*\\./man/'`; \ $(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(mandir)/$$dir; \ $(INSTALL_DATA) $$man $(DESTDIR)$(mandir)/$$dir/$$man; \ done endif install-rules: install-subdirs $(INSTALL_RULES) install-libraries install-headers install-bin-programs install-bin-extra install-sbin-programs install-sbin-extra install-mans CLEAN_SUBDIRS = $(addsuffix -clean,$(SUBDIRS)) .PHONY: clean clean-subdirs $(CLEAN_RULES) $(CLEAN_SUBDIRS) clean-subdirs: $(CLEAN_SUBDIRS) $(CLEAN_SUBDIRS): $(MAKE) -C $(subst -clean,,$@) clean clean: clean-subdirs $(CLEAN_RULES) rm -f *.o *.p .*.d core $(BIN_PROGRAMS) $(SBIN_PROGRAMS) $(LIBRARIES) $(UNINST_PROGRAMS) $(UNINST_LIBRARIES) stamp-md5 DIST_SUBDIRS = $(addsuffix -dist,$(SUBDIRS)) .PHONY: dist-all dist-mkdir dist-copy dist-subdirs $(DIST_RULES) $(DIST_SUBDIRS) dist-subdirs: $(DIST_SUBDIRS) $(DIST_SUBDIRS): $(MAKE) -C $(subst -dist,,$@) dist-all \ DIST_CURDIR=$(DIST_CURDIR)/$(subst -dist,,$@) dist-mkdir: $(SHELL) $(TOPDIR)/mkinstalldirs $(DIST_DIR) DIST_ALL_FILES = Makefile $(BIN_EXTRA) $(SBIN_EXTRA) $(MANS) $(VERSION_FILES) $(DIST_FILES) dist-copy: dist-mkdir $(DIST_ALL_FILES) $(DIST_RULES) @for file in $(DIST_ALL_FILES); do \ echo " cp -p $$file $(DIST_DIR)/$$file"; \ cp -p $$file $(DIST_DIR)/$$file; \ done dist-all: dist-copy dist-subdirs LOCAL_DFILES := $(wildcard .*.d) ifneq ($(LOCAL_DFILES),) .PHONY: $(LOCAL_DFILES) -include $(LOCAL_DFILES) endif ifeq (Cscope.make,$(wildcard Cscope.make)) include Cscope.make endif ./ocfs2-tools-1.6.4/aclocal.m40000664000176100017610000000025310673531131012620 00000000000000m4_include([pkg.m4]) m4_include([glib-2.0.m4]) m4_include([runlog.m4]) m4_include([python.m4]) m4_include([pythondev.m4]) m4_include([blkid.m4]) m4_include([mbvendor.m4]) ./ocfs2-tools-1.6.4/blkid.m40000664000176100017610000000466310673531131012320 00000000000000dnl Support for libblkid included in our tree for ocfs2console AC_DEFUN([OCFS2_BLKID], [ HAVE_BLKID= PKG_CHECK_MODULES(BLKID, blkid >= 1.36, HAVE_BLKID=yes, [AC_MSG_WARN([blkid >= 1.36 not found, using internal version])]) AC_SUBST(HAVE_BLKID) if test "x$HAVE_BLKID" != "xyes"; then AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CONFIG_COMMANDS([ocfs2console/blkid/blkid_types.h], [ outfile=ocfs2console/blkid/blkid_types.h-tmp cat > $outfile <<_______EOF /* * If linux/types.h is already been included, assume it has defined * everything we need. (cross fingers) Other header files may have * also defined the types that we need. */ #if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \\ !defined(_EXT2_TYPES_H)) #define _BLKID_TYPES_H typedef unsigned char __u8; typedef signed char __s8; #if ($ocfs2_SIZEOF_INT == 8) typedef int __s64; typedef unsigned int __u64; #else #if ($ocfs2_SIZEOF_LONG == 8) typedef long __s64; typedef unsigned long __u64; #else #if ($ocfs2_SIZEOF_LONG_LONG == 8) #if defined(__GNUC__) typedef __signed__ long long __s64; #else typedef signed long long __s64; #endif /* __GNUC__ */ typedef unsigned long long __u64; #endif /* SIZEOF_LONG_LONG == 8 */ #endif /* SIZEOF_LONG == 8 */ #endif /* SIZEOF_INT == 8 */ #if ($ocfs2_SIZEOF_INT == 2) typedef int __s16; typedef unsigned int __u16; #else #if ($ocfs2_SIZEOF_SHORT == 2) typedef short __s16; typedef unsigned short __u16; #else ?==error: undefined 16 bit type #endif /* SIZEOF_SHORT == 2 */ #endif /* SIZEOF_INT == 2 */ #if ($ocfs2_SIZEOF_INT == 4) typedef int __s32; typedef unsigned int __u32; #else #if ($ocfs2_SIZEOF_LONG == 4) typedef long __s32; typedef unsigned long __u32; #else #if ($ocfs2_SIZEOF_SHORT == 4) typedef short __s32; typedef unsigned short __u32; #else ?== error: undefined 32 bit type #endif /* SIZEOF_SHORT == 4 */ #endif /* SIZEOF_LONG == 4 */ #endif /* SIZEOF_INT == 4 */ #endif /* _*_TYPES_H */ _______EOF if cmp -s $outfile ocfs2console/blkid/blkid_types.h; then AC_MSG_NOTICE([ocfs2console/blkid/blkid_types.h is unchanged]) rm -f $outfile else mv $outfile ocfs2console/blkid/blkid_types.h fi ],[ ocfs2_SIZEOF_SHORT=$ac_cv_sizeof_short ocfs2_SIZEOF_INT=$ac_cv_sizeof_int ocfs2_SIZEOF_LONG=$ac_cv_sizeof_long ocfs2_SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long ]) fi ]) ./ocfs2-tools-1.6.4/glib-2.0.m40000664000176100017610000002014110673531132012433 00000000000000# Configure paths for GLIB # Owen Taylor 1997-2001 dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject or dnl gthread is specified in MODULES, pass to pkg-config dnl AC_DEFUN([AM_PATH_GLIB_2_0], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(glibtest, [ --disable-glibtest do not try to compile and run a test GLIB program], , enable_glibtest=yes) pkg_config_args=glib-2.0 for module in . $4 do case "$module" in gmodule) pkg_config_args="$pkg_config_args gmodule-2.0" ;; gmodule-no-export) pkg_config_args="$pkg_config_args gmodule-no-export-2.0" ;; gobject) pkg_config_args="$pkg_config_args gobject-2.0" ;; gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done AC_PATH_PROG(PKG_CONFIG, pkg-config, no) no_glib="" if test x$PKG_CONFIG != xno ; then if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then : else echo *** pkg-config too old; version 0.7 or better required. no_glib=yes PKG_CONFIG=no fi else no_glib=yes fi min_glib_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" enable_glibtest=no fi if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then : else no_glib=yes fi fi if test x"$no_glib" = x ; then GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0` GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0` GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args` GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args` glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_glibtest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$GLIB_LIBS $LIBS" dnl dnl Now check if the installed GLIB is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.glibtest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.glibtest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_glib_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_glib_version"); exit(1); } if ((glib_major_version != $glib_config_major_version) || (glib_minor_version != $glib_config_minor_version) || (glib_micro_version != $glib_config_micro_version)) { printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, glib_major_version, glib_minor_version, glib_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((glib_major_version != GLIB_MAJOR_VERSION) || (glib_minor_version != GLIB_MINOR_VERSION) || (glib_micro_version != GLIB_MICRO_VERSION)) { printf("*** GLIB header files (version %d.%d.%d) do not match\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", glib_major_version, glib_minor_version, glib_micro_version); } else { if ((glib_major_version > major) || ((glib_major_version == major) && (glib_minor_version > minor)) || ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", glib_major_version, glib_minor_version, glib_micro_version); printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_glib" = x ; then AC_MSG_RESULT(yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://www.freedesktop.org/software/pkgconfig/" else if test -f conf.glibtest ; then : else echo "*** Could not run GLIB test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$LIBS $GLIB_LIBS" AC_TRY_LINK([ #include #include ], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GLIB or finding the wrong" echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GLIB is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GLIB_CFLAGS="" GLIB_LIBS="" GLIB_GENMARSHAL="" GOBJECT_QUERY="" GLIB_MKENUMS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) AC_SUBST(GLIB_GENMARSHAL) AC_SUBST(GOBJECT_QUERY) AC_SUBST(GLIB_MKENUMS) rm -f conf.glibtest ]) ./ocfs2-tools-1.6.4/mbvendor.m40000664000176100017610000000452610673531132013046 00000000000000# MB_VENDOR([VARIABLE]) # --------------------- AC_DEFUN([MB_VENDOR], [AC_MSG_CHECKING([for vendor]) AC_ARG_WITH(vendor, [ --with-vendor=VENDOR Vendor to tailor build defaults and packages to [common]],[ mb_vendor="$withval" if test -x "vendor/${mb_vendor}/vendor.guess"; then if "vendor/${mb_vendor}/vendor.guess" >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then AC_MSG_RESULT([$mb_vendor]) else AC_MSG_RESULT([not found]) AC_MSG_ERROR([Vendor $mb_vendor not detected]) fi else AC_MSG_RESULT([not supported]) AC_MSG_ERROR([Vendor $mb_vendor not supported]) fi ], [ mb_vendor=`./vendor.guess 2>&AS_MESSAGE_LOG_FD` if test -z "$mb_vendor"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT([$mb_vendor]) fi ]) dnl Use 2.13 safe ifelse() ifelse([$1], [], [], [ $1="$mb_vendor" AC_SUBST($1) ]) ]) # MB_VENDOR # MB_VENDOR_KERNEL([VARIABLE]) # --------------------- AC_DEFUN([MB_VENDOR_KERNEL], [AC_MSG_CHECKING([for vendor kernel]) AC_ARG_WITH(vendorkernel, [ --with-vendorkernel=KERNELVERSION Vendor kernel version to compile against [detected]], [ mb_vendorkernel="$withval" if test -z "$mb_vendor"; then AC_MSG_RESULT([no vendor]) AC_MSG_ERROR([No vendor specified or discovered]) fi if test -x "vendor/${mb_vendor}/kernel.guess"; then mb_vkinclude="`vendor/${mb_vendor}/kernel.guess build ${mb_vendorkernel} 2>&AS_MESSAGE_LOG_FD`" if test -z "$mb_vkinclude"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([Vendor kernel $mb_vendorkernel not detected]) else AC_MSG_RESULT([$mb_vkinclude]) fi else AC_MSG_RESULT([not supported]) AC_MSG_ERROR([Vendor $mb_vendor does not support kernel detection]) fi ], [ if test -x "vendor/${mb_vendor}/kernel.guess"; then mb_vkinclude="`vendor/${mb_vendor}/kernel.guess build 2>&AS_MESSAGE_LOG_FD`" if test -z "$mb_vkinclude"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT([$mb_vkinclude]) fi else mb_vkinclude= AC_MSG_RESULT([not supported]) fi ]) dnl Use 2.13 safe ifelse() ifelse([$1], [], [], [ $1="$mb_vkinclude" AC_SUBST($1) ]) ]) # MB_VENDOR_KERNEL ./ocfs2-tools-1.6.4/python.m40000664000176100017610000001672510673531132012557 00000000000000## ------------------------ ## Python file handling ## From Andrew Dalke ## Updated by James Henstridge ## ------------------------ # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 # Free Software Foundation, Inc. # 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. # 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. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 1.5 are not dnl supported because the default installation locations changed from dnl $prefix/lib/site-python in 1.4 to $prefix/lib/python1.5/site-packages dnl in 1.5. m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python2.4 python2.3 python2.2 dnl python2.1 python2.0 python1.6 python1.5]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT(yes)], [AC_MSG_ERROR(too old)]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null || echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"`]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null || echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"`]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # hexversion has been introduced in Python 1.5.2; it's probably not # worth to support older versions (1.5.1 was released on October 31, 1998). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys, string # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. minver = map(int, string.split('$2', '.')) + [[0, 0, 0]] minverhex = 0 for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) ./ocfs2-tools-1.6.4/pythondev.m40000664000176100017610000000173710673531132013253 00000000000000## Find the install dirs for the python installation. ## By James Henstridge dnl a macro to check for ability to create python extensions dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) dnl function also defines PYTHON_INCLUDES AC_DEFUN([AM_CHECK_PYTHON_HEADERS], [AC_REQUIRE([AM_PATH_PYTHON]) AC_MSG_CHECKING(for headers required to compile python extensions) dnl deduce PYTHON_INCLUDES py_prefix=`$PYTHON -c "import sys; print sys.prefix"` py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" if test "$py_prefix" != "$py_exec_prefix"; then PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" fi AC_SUBST(PYTHON_INCLUDES) dnl check if the headers exist: save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" AC_TRY_CPP([#include ],dnl [AC_MSG_RESULT(found) $1],dnl [AC_MSG_RESULT(not found) $2]) CPPFLAGS="$save_CPPFLAGS" ]) ./ocfs2-tools-1.6.4/runlog.m40000664000176100017610000000221010673531132012524 00000000000000# Copyright (C) 2001, 2003 Free Software Foundation, Inc. -*- Autoconf -*- # 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. # 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) ./ocfs2-tools-1.6.4/config.guess0000775000176100017610000012470210673531131013306 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. timestamp='2004-11-12' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amd64:OpenBSD:*:*) echo x86_64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; cats:OpenBSD:*:*) echo arm-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; luna88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mips64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit 0 ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit 0 ;; *:OS400:*:*) echo powerpc-ibm-os400 exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit 0 ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms && exit 0 ;; I*) echo ia64-dec-vms && exit 0 ;; V*) echo vax-dec-vms && exit 0 ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ./ocfs2-tools-1.6.4/config.sub0000775000176100017610000007535310673531131012760 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. timestamp='2004-11-30' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | msp430-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ./ocfs2-tools-1.6.4/configure0000755000176100017610000105676711515641626012722 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="libocfs2/bitmap.c" # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS PACKAGE MAJOR_VERSION MINOR_VERSION MICRO_VERSION EXTRA_VERSION DIST_VERSION VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os OCFS2_DEBUG CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S RANLIB ac_ct_RANLIB AR EGREP VENDOR root_prefix root_bindir root_sbindir root_sysconfdir PKG_CONFIG COM_ERR_CFLAGS COM_ERR_LIBS UUID_LIBS NCURSES_LIBS READLINE_LIBS OCFS2_DEBUG_EXE GLIB_CFLAGS GLIB_LIBS GLIB_GENMARSHAL GOBJECT_QUERY GLIB_MKENUMS OCFS2_DYNAMIC_FSCK OCFS2_DYNAMIC_CTL BUILD_DEBUGOCFS2 HAVE_COROSYNC CPG_LDFLAGS AIS_LDFLAGS LIBDLM_FOUND BUILD_FSDLM_SUPPORT DL_LIBS BUILD_OCFS2_CONTROLD BUILD_PCMK_SUPPORT BUILD_CMAN_SUPPORT PYTHON PYTHON_VERSION PYTHON_PREFIX PYTHON_EXEC_PREFIX PYTHON_PLATFORM pythondir pkgpythondir pyexecdir pkgpyexecdir PYTHON_INCLUDES BLKID_CFLAGS BLKID_LIBS HAVE_BLKID BUILD_OCFS2CONSOLE LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug=yes/no Turn on debugging default=no --enable-debugexe=yes/no Enable debug executables for library source files default=no --disable-glibtest do not try to compile and run a test GLIB program --enable-dynamic-fsck=yes/no Build fsck dynamically default=no --enable-dynamic-ctl=yes/no Build cluster control tools dynamically default=no --enable-ocfs2console=yes/no Build GUI frontend default=yes Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-vendor=VENDOR Vendor to tailor build defaults and packages to common --with-root-prefix=PREFIX override prefix variable for files to be placed in the root Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE=ocfs2-tools # Adjust these for the software version. MAJOR_VERSION=1 MINOR_VERSION=6 MICRO_VERSION=4 EXTRA_VERSION= DIST_VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION if test -z "$EXTRA_VERSION"; then VERSION=$DIST_VERSION else VERSION=$DIST_VERSION-$EXTRA_VERSION fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # Make sure we can run config.sub. $ac_config_sub sun4 >/dev/null 2>&1 || { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 echo "$as_me: error: cannot run $ac_config_sub" >&2;} { (exit 1); exit 1; }; } echo "$as_me:$LINENO: checking build system type" >&5 echo $ECHO_N "checking build system type... $ECHO_C" >&6 if test "${ac_cv_build+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_build_alias=$build_alias test -z "$ac_cv_build_alias" && ac_cv_build_alias=`$ac_config_guess` test -z "$ac_cv_build_alias" && { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: $ac_cv_build" >&5 echo "${ECHO_T}$ac_cv_build" >&6 build=$ac_cv_build build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$as_me:$LINENO: checking host system type" >&5 echo $ECHO_N "checking host system type... $ECHO_C" >&6 if test "${ac_cv_host+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_host_alias=$host_alias test -z "$ac_cv_host_alias" && ac_cv_host_alias=$ac_cv_build_alias ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: $ac_cv_host" >&5 echo "${ECHO_T}$ac_cv_host" >&6 host=$ac_cv_host host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` case "$host" in *-*-linux*) ;; *) { { echo "$as_me:$LINENO: error: This filesystem will only work on Linux" >&5 echo "$as_me: error: This filesystem will only work on Linux" >&2;} { (exit 1); exit 1; }; } ;; esac # # If CFLAGS is non-empty, leave the debugging and optimization symobls # to the caller. Otherwise, set them according to --enable-debug. # OCFS2_DEBUG= echo "$as_me:$LINENO: checking for debugging" >&5 echo $ECHO_N "checking for debugging... $ECHO_C" >&6 if test "x$CFLAGS" = "x"; then # Check whether --enable-debug or --disable-debug was given. if test "${enable_debug+set}" = set; then enableval="$enable_debug" else enable_debug=no fi; if test "x$enable_debug" = "xyes"; then OCFS2_DEBUG=yes CFLAGS="-g" else CFLAGS="-O2" fi echo "$as_me:$LINENO: result: $enable_debug" >&5 echo "${ECHO_T}$enable_debug" >&6 else echo "$as_me:$LINENO: result: skipped, CFLAGS is set" >&5 echo "${ECHO_T}skipped, CFLAGS is set" >&6 fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std1 is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std1. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6 ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # # If OCFS2_DEBUG was set, we know CFLAGS must be "-g". If we're using # GNU C, get extra debugging symbols. # if test "x$GCC" = "xyes" -a "x$OCFS2_DEBUG" = "xyes"; then CFLAGS="-ggdb" fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo "$as_me:$LINENO: checking whether ln -s works" >&5 echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no, using $LN_S" >&5 echo "${ECHO_T}no, using $LN_S" >&6 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then echo "$as_me:$LINENO: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi RANLIB=$ac_ct_RANLIB else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_AR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $AR in [\\/]* | ?:[\\/]*) ac_cv_path_AR="$AR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi AR=$ac_cv_path_AR if test -n "$AR"; then echo "$as_me:$LINENO: result: $AR" >&5 echo "${ECHO_T}$AR" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 if test "${ac_cv_c_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset x; /* SunOS 4.1.1 cc rejects this. */ char const *const *ccp; char **p; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; ccp = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++ccp; p = (char**) ccp; ccp = (char const *const *) p; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_const=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 echo "${ECHO_T}$ac_cv_c_const" >&6 if test $ac_cv_c_const = no; then cat >>confdefs.h <<\_ACEOF #define const _ACEOF fi echo "$as_me:$LINENO: checking for vendor" >&5 echo $ECHO_N "checking for vendor... $ECHO_C" >&6 # Check whether --with-vendor or --without-vendor was given. if test "${with_vendor+set}" = set; then withval="$with_vendor" mb_vendor="$withval" if test -x "vendor/${mb_vendor}/vendor.guess"; then if "vendor/${mb_vendor}/vendor.guess" >&5 2>&5; then echo "$as_me:$LINENO: result: $mb_vendor" >&5 echo "${ECHO_T}$mb_vendor" >&6 else echo "$as_me:$LINENO: result: not found" >&5 echo "${ECHO_T}not found" >&6 { { echo "$as_me:$LINENO: error: Vendor $mb_vendor not detected" >&5 echo "$as_me: error: Vendor $mb_vendor not detected" >&2;} { (exit 1); exit 1; }; } fi else echo "$as_me:$LINENO: result: not supported" >&5 echo "${ECHO_T}not supported" >&6 { { echo "$as_me:$LINENO: error: Vendor $mb_vendor not supported" >&5 echo "$as_me: error: Vendor $mb_vendor not supported" >&2;} { (exit 1); exit 1; }; } fi else mb_vendor=`./vendor.guess 2>&5` if test -z "$mb_vendor"; then echo "$as_me:$LINENO: result: not found" >&5 echo "${ECHO_T}not found" >&6 else echo "$as_me:$LINENO: result: $mb_vendor" >&5 echo "${ECHO_T}$mb_vendor" >&6 fi fi; VENDOR="$mb_vendor" if test "x$GCC" != "xyes"; then { { echo "$as_me:$LINENO: error: GCC is required" >&5 echo "$as_me: error: GCC is required" >&2;} { (exit 1); exit 1; }; } fi # Check whether --with-root-prefix or --without-root-prefix was given. if test "${with_root_prefix+set}" = set; then withval="$with_root_prefix" root_prefix=$withval else root_prefix="" fi; root_bindir='${root_prefix}/bin' root_sbindir='${root_prefix}/sbin' root_sysconfdir='${root_prefix}/etc' COM_ERR_LIBS= # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done succeeded=no if test -z "$PKG_CONFIG"; then # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PKG_CONFIG+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 echo "${ECHO_T}$PKG_CONFIG" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test "$PKG_CONFIG" = "no" ; then echo "*** The pkg-config script could not be found. Make sure it is" echo "*** in your path, or set the PKG_CONFIG environment variable" echo "*** to the full path to pkg-config." echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." else PKG_CONFIG_MIN_VERSION=0.9.0 if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then echo "$as_me:$LINENO: checking for com_err" >&5 echo $ECHO_N "checking for com_err... $ECHO_C" >&6 if $PKG_CONFIG --exists "com_err" ; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 succeeded=yes echo "$as_me:$LINENO: checking COM_ERR_CFLAGS" >&5 echo $ECHO_N "checking COM_ERR_CFLAGS... $ECHO_C" >&6 COM_ERR_CFLAGS=`$PKG_CONFIG --cflags "com_err"` echo "$as_me:$LINENO: result: $COM_ERR_CFLAGS" >&5 echo "${ECHO_T}$COM_ERR_CFLAGS" >&6 echo "$as_me:$LINENO: checking COM_ERR_LIBS" >&5 echo $ECHO_N "checking COM_ERR_LIBS... $ECHO_C" >&6 COM_ERR_LIBS=`$PKG_CONFIG --libs "com_err"` echo "$as_me:$LINENO: result: $COM_ERR_LIBS" >&5 echo "${ECHO_T}$COM_ERR_LIBS" >&6 else COM_ERR_CFLAGS="" COM_ERR_LIBS="" ## If we have a custom action on failure, don't print errors, but ## do set a variable so people can do so. COM_ERR_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "com_err"` fi else echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." echo "*** See http://www.freedesktop.org/software/pkgconfig" fi fi if test $succeeded = yes; then : else echo "$as_me:$LINENO: checking for com_err in -lcom_err" >&5 echo $ECHO_N "checking for com_err in -lcom_err... $ECHO_C" >&6 if test "${ac_cv_lib_com_err_com_err+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcom_err $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char com_err (); int main () { com_err (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_com_err_com_err=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_com_err_com_err=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_com_err_com_err" >&5 echo "${ECHO_T}$ac_cv_lib_com_err_com_err" >&6 if test $ac_cv_lib_com_err_com_err = yes; then COM_ERR_LIBS=-lcom_err fi if test "x$COM_ERR_LIBS" = "x"; then { { echo "$as_me:$LINENO: error: Unable to find com_err library" >&5 echo "$as_me: error: Unable to find com_err library" >&2;} { (exit 1); exit 1; }; } fi if test "${ac_cv_header_et_com_err_h+set}" = set; then echo "$as_me:$LINENO: checking for et/com_err.h" >&5 echo $ECHO_N "checking for et/com_err.h... $ECHO_C" >&6 if test "${ac_cv_header_et_com_err_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_et_com_err_h" >&5 echo "${ECHO_T}$ac_cv_header_et_com_err_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking et/com_err.h usability" >&5 echo $ECHO_N "checking et/com_err.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking et/com_err.h presence" >&5 echo $ECHO_N "checking et/com_err.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: et/com_err.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: et/com_err.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: et/com_err.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: et/com_err.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: et/com_err.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: et/com_err.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: et/com_err.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: et/com_err.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: et/com_err.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: et/com_err.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: et/com_err.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: et/com_err.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: et/com_err.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: et/com_err.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: et/com_err.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: et/com_err.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for et/com_err.h" >&5 echo $ECHO_N "checking for et/com_err.h... $ECHO_C" >&6 if test "${ac_cv_header_et_com_err_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_et_com_err_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_et_com_err_h" >&5 echo "${ECHO_T}$ac_cv_header_et_com_err_h" >&6 fi if test $ac_cv_header_et_com_err_h = yes; then : else { { echo "$as_me:$LINENO: error: Unable to find com_err headers" >&5 echo "$as_me: error: Unable to find com_err headers" >&2;} { (exit 1); exit 1; }; } fi fi UUID_LIBS= echo "$as_me:$LINENO: checking for uuid_unparse in -luuid" >&5 echo $ECHO_N "checking for uuid_unparse in -luuid... $ECHO_C" >&6 if test "${ac_cv_lib_uuid_uuid_unparse+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char uuid_unparse (); int main () { uuid_unparse (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_uuid_uuid_unparse=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_uuid_uuid_unparse=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_uuid_uuid_unparse" >&5 echo "${ECHO_T}$ac_cv_lib_uuid_uuid_unparse" >&6 if test $ac_cv_lib_uuid_uuid_unparse = yes; then UUID_LIBS=-luuid fi if test "x$UUID_LIBS" = "x"; then { { echo "$as_me:$LINENO: error: Unable to find uuid library" >&5 echo "$as_me: error: Unable to find uuid library" >&2;} { (exit 1); exit 1; }; } fi if test "${ac_cv_header_uuid_uuid_h+set}" = set; then echo "$as_me:$LINENO: checking for uuid/uuid.h" >&5 echo $ECHO_N "checking for uuid/uuid.h... $ECHO_C" >&6 if test "${ac_cv_header_uuid_uuid_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_uuid_uuid_h" >&5 echo "${ECHO_T}$ac_cv_header_uuid_uuid_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking uuid/uuid.h usability" >&5 echo $ECHO_N "checking uuid/uuid.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking uuid/uuid.h presence" >&5 echo $ECHO_N "checking uuid/uuid.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: uuid/uuid.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: uuid/uuid.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: uuid/uuid.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: uuid/uuid.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: uuid/uuid.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: uuid/uuid.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: uuid/uuid.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: uuid/uuid.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: uuid/uuid.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for uuid/uuid.h" >&5 echo $ECHO_N "checking for uuid/uuid.h... $ECHO_C" >&6 if test "${ac_cv_header_uuid_uuid_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_uuid_uuid_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_uuid_uuid_h" >&5 echo "${ECHO_T}$ac_cv_header_uuid_uuid_h" >&6 fi if test $ac_cv_header_uuid_uuid_h = yes; then : else { { echo "$as_me:$LINENO: error: Unable to find uuid headers" >&5 echo "$as_me: error: Unable to find uuid headers" >&2;} { (exit 1); exit 1; }; } fi NCURSES_LIBS= echo "$as_me:$LINENO: checking for tgetstr in -lncurses" >&5 echo $ECHO_N "checking for tgetstr in -lncurses... $ECHO_C" >&6 if test "${ac_cv_lib_ncurses_tgetstr+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char tgetstr (); int main () { tgetstr (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_ncurses_tgetstr=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_ncurses_tgetstr=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tgetstr" >&5 echo "${ECHO_T}$ac_cv_lib_ncurses_tgetstr" >&6 if test $ac_cv_lib_ncurses_tgetstr = yes; then NCURSES_LIBS=-lncurses fi if test "x$NCURSES_LIBS" = "x"; then { { echo "$as_me:$LINENO: error: Unable to find ncurses library" >&5 echo "$as_me: error: Unable to find ncurses library" >&2;} { (exit 1); exit 1; }; } fi saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -lncurses" READLINE_LIBS= echo "$as_me:$LINENO: checking for readline in -lreadline" >&5 echo $ECHO_N "checking for readline in -lreadline... $ECHO_C" >&6 if test "${ac_cv_lib_readline_readline+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char readline (); int main () { readline (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_readline_readline=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_readline_readline=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5 echo "${ECHO_T}$ac_cv_lib_readline_readline" >&6 if test $ac_cv_lib_readline_readline = yes; then READLINE_LIBS=-lreadline fi if test "x$READLINE_LIBS" = "x"; then { { echo "$as_me:$LINENO: error: Unable to find readline library" >&5 echo "$as_me: error: Unable to find readline library" >&2;} { (exit 1); exit 1; }; } fi if test "${ac_cv_header_readline_readline_h+set}" = set; then echo "$as_me:$LINENO: checking for readline/readline.h" >&5 echo $ECHO_N "checking for readline/readline.h... $ECHO_C" >&6 if test "${ac_cv_header_readline_readline_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_readline_readline_h" >&5 echo "${ECHO_T}$ac_cv_header_readline_readline_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking readline/readline.h usability" >&5 echo $ECHO_N "checking readline/readline.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking readline/readline.h presence" >&5 echo $ECHO_N "checking readline/readline.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: readline/readline.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: readline/readline.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: readline/readline.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: readline/readline.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: readline/readline.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: readline/readline.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: readline/readline.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: readline/readline.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: readline/readline.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: readline/readline.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for readline/readline.h" >&5 echo $ECHO_N "checking for readline/readline.h... $ECHO_C" >&6 if test "${ac_cv_header_readline_readline_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_readline_readline_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_readline_readline_h" >&5 echo "${ECHO_T}$ac_cv_header_readline_readline_h" >&6 fi if test $ac_cv_header_readline_readline_h = yes; then : else { { echo "$as_me:$LINENO: error: Unable to find readline headers" >&5 echo "$as_me: error: Unable to find readline headers" >&2;} { (exit 1); exit 1; }; } fi LDFLAGS="$saved_LDFLAGS" echo "$as_me:$LINENO: checking for debug executables" >&5 echo $ECHO_N "checking for debug executables... $ECHO_C" >&6 # Check whether --enable-debugexe or --disable-debugexe was given. if test "${enable_debugexe+set}" = set; then enableval="$enable_debugexe" else enable_debugexe=no fi; OCFS2_DEBUG_EXE= if test "x$enable_debugexe" = "xyes"; then OCFS2_DEBUG_EXE=yes fi echo "$as_me:$LINENO: result: $enable_debugexe" >&5 echo "${ECHO_T}$enable_debugexe" >&6 GLIB_REQUIRED_VERSION=2.2.3 # Check whether --enable-glibtest or --disable-glibtest was given. if test "${enable_glibtest+set}" = set; then enableval="$enable_glibtest" else enable_glibtest=yes fi; pkg_config_args=glib-2.0 for module in . do case "$module" in gmodule) pkg_config_args="$pkg_config_args gmodule-2.0" ;; gmodule-no-export) pkg_config_args="$pkg_config_args gmodule-no-export-2.0" ;; gobject) pkg_config_args="$pkg_config_args gobject-2.0" ;; gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PKG_CONFIG+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 echo "${ECHO_T}$PKG_CONFIG" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi no_glib="" if test x$PKG_CONFIG != xno ; then if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then : else echo *** pkg-config too old; version 0.7 or better required. no_glib=yes PKG_CONFIG=no fi else no_glib=yes fi min_glib_version=$GLIB_REQUIRED_VERSION echo "$as_me:$LINENO: checking for GLIB - version >= $min_glib_version" >&5 echo $ECHO_N "checking for GLIB - version >= $min_glib_version... $ECHO_C" >&6 if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" enable_glibtest=no fi if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then : else no_glib=yes fi fi if test x"$no_glib" = x ; then GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0` GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0` GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args` GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args` glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` if test "x$enable_glibtest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$GLIB_LIBS $LIBS" rm -f conf.glibtest if test "$cross_compiling" = yes; then echo $ac_n "cross compiling; assumed OK... $ac_c" else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.glibtest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_glib_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_glib_version"); exit(1); } if ((glib_major_version != $glib_config_major_version) || (glib_minor_version != $glib_config_minor_version) || (glib_micro_version != $glib_config_micro_version)) { printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, glib_major_version, glib_minor_version, glib_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((glib_major_version != GLIB_MAJOR_VERSION) || (glib_minor_version != GLIB_MINOR_VERSION) || (glib_micro_version != GLIB_MICRO_VERSION)) { printf("*** GLIB header files (version %d.%d.%d) do not match\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", glib_major_version, glib_minor_version, glib_micro_version); } else { if ((glib_major_version > major) || ((glib_major_version == major) && (glib_minor_version > minor)) || ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", glib_major_version, glib_minor_version, glib_micro_version); printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) no_glib=yes fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_glib" = x ; then echo "$as_me:$LINENO: result: yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)" >&5 echo "${ECHO_T}yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)" >&6 have_glib=yes else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://www.freedesktop.org/software/pkgconfig/" else if test -f conf.glibtest ; then : else echo "*** Could not run GLIB test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$LIBS $GLIB_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GLIB or finding the wrong" echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GLIB is incorrectly installed." fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GLIB_CFLAGS="" GLIB_LIBS="" GLIB_GENMARSHAL="" GOBJECT_QUERY="" GLIB_MKENUMS="" { { echo "$as_me:$LINENO: error: GLib $GLIB_REQUIRED_VERSION or better is required" >&5 echo "$as_me: error: GLib $GLIB_REQUIRED_VERSION or better is required" >&2;} { (exit 1); exit 1; }; } fi rm -f conf.glibtest # # Can we build statically? This is important # dyn_save_CFLAGS="$CFLAGS" dyn_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="-static $LIBS $GLIB_LIBS $COM_ERR_LIBS" echo "$as_me:$LINENO: checking whether glib and com_err can be linked statically" >&5 echo $ECHO_N "checking whether glib and com_err can be linked statically... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include int main () { char *e = error_message(-1); return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then static_lib_link=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 static_lib_link=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext echo "$as_me:$LINENO: result: $static_lib_link" >&5 echo "${ECHO_T}$static_lib_link" >&6 CFLAGS="$dyn_save_CFLAGS" LIBS="$dyn_save_LIBS" OCFS2_DYNAMIC_FSCK= echo "$as_me:$LINENO: checking whether to build fsck dynamically" >&5 echo $ECHO_N "checking whether to build fsck dynamically... $ECHO_C" >&6 # Check whether --enable-dynamic-fsck or --disable-dynamic-fsck was given. if test "${enable_dynamic_fsck+set}" = set; then enableval="$enable_dynamic_fsck" else enable_dynamic_fsck=detect fi; if test "x$enable_dynamic_fsck" = "xdetect"; then if test "x$static_lib_link" = "xyes"; then enable_dynamic_fsck=no else enable_dynamic_fsck=yes fi fi echo "$as_me:$LINENO: result: $enable_dynamic_fsck" >&5 echo "${ECHO_T}$enable_dynamic_fsck" >&6 if test "x$static_lib_link" = "xno" -a "x$enable_dynamic_fsck" = "xno"; then { { echo "$as_me:$LINENO: error: Unable to statically link fsck.ocfs2" >&5 echo "$as_me: error: Unable to statically link fsck.ocfs2" >&2;} { (exit 1); exit 1; }; } fi if test "x$enable_dynamic_fsck" = "xyes"; then OCFS2_DYNAMIC_FSCK=yes fi OCFS2_DYNAMIC_CTL= echo "$as_me:$LINENO: checking whether to build cluster control tools dynamically" >&5 echo $ECHO_N "checking whether to build cluster control tools dynamically... $ECHO_C" >&6 # Check whether --enable-dynamic-ctl or --disable-dynamic-ctl was given. if test "${enable_dynamic_ctl+set}" = set; then enableval="$enable_dynamic_ctl" else enable_dynamic_ctl=detect fi; if test "x$enable_dynamic_ctl" = "xdetect"; then if test "x$static_lib_link" = "xyes"; then enable_dynamic_ctl=no else enable_dynamic_ctl=yes fi fi echo "$as_me:$LINENO: result: $enable_dynamic_ctl" >&5 echo "${ECHO_T}$enable_dynamic_ctl" >&6 if test "x$static_lib_link" = "xno" -a "x$enable_dynamic_ctl" = "xno"; then { { echo "$as_me:$LINENO: error: Unable to statically link cluster control tools" >&5 echo "$as_me: error: Unable to statically link cluster control tools" >&2;} { (exit 1); exit 1; }; } fi if test "x$enable_dynamic_ctl" = "xyes"; then OCFS2_DYNAMIC_CTL=yes fi BUILD_DEBUGOCFS2= ocfs_tools_save_LIBS="$LIBS" LIBS="$LIBS -lncurses" echo "$as_me:$LINENO: checking for readline in -lreadline" >&5 echo $ECHO_N "checking for readline in -lreadline... $ECHO_C" >&6 if test "${ac_cv_lib_readline_readline+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char readline (); int main () { readline (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_readline_readline=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_readline_readline=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5 echo "${ECHO_T}$ac_cv_lib_readline_readline" >&6 if test $ac_cv_lib_readline_readline = yes; then if test "${ac_cv_header_readline_readline_h+set}" = set; then echo "$as_me:$LINENO: checking for readline/readline.h" >&5 echo $ECHO_N "checking for readline/readline.h... $ECHO_C" >&6 if test "${ac_cv_header_readline_readline_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_readline_readline_h" >&5 echo "${ECHO_T}$ac_cv_header_readline_readline_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking readline/readline.h usability" >&5 echo $ECHO_N "checking readline/readline.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking readline/readline.h presence" >&5 echo $ECHO_N "checking readline/readline.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: readline/readline.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: readline/readline.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: readline/readline.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: readline/readline.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: readline/readline.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: readline/readline.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: readline/readline.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: readline/readline.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: readline/readline.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: readline/readline.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: readline/readline.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for readline/readline.h" >&5 echo $ECHO_N "checking for readline/readline.h... $ECHO_C" >&6 if test "${ac_cv_header_readline_readline_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_readline_readline_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_readline_readline_h" >&5 echo "${ECHO_T}$ac_cv_header_readline_readline_h" >&6 fi if test $ac_cv_header_readline_readline_h = yes; then BUILD_DEBUGOCFS2=yes else { echo "$as_me:$LINENO: WARNING: readline not found, debugfs.ocfs2 will not be built" >&5 echo "$as_me: WARNING: readline not found, debugfs.ocfs2 will not be built" >&2;} fi else { echo "$as_me:$LINENO: WARNING: readline not found, debugfs.ocfs2 will not be built" >&5 echo "$as_me: WARNING: readline not found, debugfs.ocfs2 will not be built" >&2;} fi LIBS="$ocfs_tools_save_LIBS" pcmk_found= echo "$as_me:$LINENO: checking for crm_get_peer in -lcrmcluster" >&5 echo $ECHO_N "checking for crm_get_peer in -lcrmcluster... $ECHO_C" >&6 if test "${ac_cv_lib_crmcluster_crm_get_peer+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrmcluster $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char crm_get_peer (); int main () { crm_get_peer (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_crmcluster_crm_get_peer=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_crmcluster_crm_get_peer=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_crmcluster_crm_get_peer" >&5 echo "${ECHO_T}$ac_cv_lib_crmcluster_crm_get_peer" >&6 if test $ac_cv_lib_crmcluster_crm_get_peer = yes; then if test "${ac_cv_header_pacemaker_crm_config_h+set}" = set; then echo "$as_me:$LINENO: checking for pacemaker/crm_config.h" >&5 echo $ECHO_N "checking for pacemaker/crm_config.h... $ECHO_C" >&6 if test "${ac_cv_header_pacemaker_crm_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_pacemaker_crm_config_h" >&5 echo "${ECHO_T}$ac_cv_header_pacemaker_crm_config_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking pacemaker/crm_config.h usability" >&5 echo $ECHO_N "checking pacemaker/crm_config.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking pacemaker/crm_config.h presence" >&5 echo $ECHO_N "checking pacemaker/crm_config.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: pacemaker/crm_config.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: pacemaker/crm_config.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for pacemaker/crm_config.h" >&5 echo $ECHO_N "checking for pacemaker/crm_config.h... $ECHO_C" >&6 if test "${ac_cv_header_pacemaker_crm_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_pacemaker_crm_config_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_pacemaker_crm_config_h" >&5 echo "${ECHO_T}$ac_cv_header_pacemaker_crm_config_h" >&6 fi if test $ac_cv_header_pacemaker_crm_config_h = yes; then pcmk_found=yes else { echo "$as_me:$LINENO: WARNING: Pacemaker headers not found, pacemaker support will not be built" >&5 echo "$as_me: WARNING: Pacemaker headers not found, pacemaker support will not be built" >&2;} fi else { echo "$as_me:$LINENO: WARNING: libcrmcluster not found, pacemaker support will not be built" >&5 echo "$as_me: WARNING: libcrmcluster not found, pacemaker support will not be built" >&2;} fi # We use cman_replyto_shutdown to insure a new enough libcman cman_found= echo "$as_me:$LINENO: checking for cman_replyto_shutdown in -lcman" >&5 echo $ECHO_N "checking for cman_replyto_shutdown in -lcman... $ECHO_C" >&6 if test "${ac_cv_lib_cman_cman_replyto_shutdown+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcman $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char cman_replyto_shutdown (); int main () { cman_replyto_shutdown (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_cman_cman_replyto_shutdown=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_cman_cman_replyto_shutdown=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_cman_cman_replyto_shutdown" >&5 echo "${ECHO_T}$ac_cv_lib_cman_cman_replyto_shutdown" >&6 if test $ac_cv_lib_cman_cman_replyto_shutdown = yes; then if test "${ac_cv_header_libcman_h+set}" = set; then echo "$as_me:$LINENO: checking for libcman.h" >&5 echo $ECHO_N "checking for libcman.h... $ECHO_C" >&6 if test "${ac_cv_header_libcman_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_libcman_h" >&5 echo "${ECHO_T}$ac_cv_header_libcman_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking libcman.h usability" >&5 echo $ECHO_N "checking libcman.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking libcman.h presence" >&5 echo $ECHO_N "checking libcman.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: libcman.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: libcman.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: libcman.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: libcman.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: libcman.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: libcman.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: libcman.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: libcman.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: libcman.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: libcman.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: libcman.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: libcman.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: libcman.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: libcman.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: libcman.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: libcman.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for libcman.h" >&5 echo $ECHO_N "checking for libcman.h... $ECHO_C" >&6 if test "${ac_cv_header_libcman_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_libcman_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_libcman_h" >&5 echo "${ECHO_T}$ac_cv_header_libcman_h" >&6 fi if test $ac_cv_header_libcman_h = yes; then cman_found=yes else { echo "$as_me:$LINENO: WARNING: libcman.h not found, cman support will not be built" >&5 echo "$as_me: WARNING: libcman.h not found, cman support will not be built" >&2;} fi else { echo "$as_me:$LINENO: WARNING: libcman not found, cman support will not be built" >&5 echo "$as_me: WARNING: libcman not found, cman support will not be built" >&2;} fi cpg_found= HAVE_COROSYNC= if test "${ac_cv_header_corosync_cpg_h+set}" = set; then echo "$as_me:$LINENO: checking for corosync/cpg.h" >&5 echo $ECHO_N "checking for corosync/cpg.h... $ECHO_C" >&6 if test "${ac_cv_header_corosync_cpg_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_corosync_cpg_h" >&5 echo "${ECHO_T}$ac_cv_header_corosync_cpg_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking corosync/cpg.h usability" >&5 echo $ECHO_N "checking corosync/cpg.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking corosync/cpg.h presence" >&5 echo $ECHO_N "checking corosync/cpg.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: corosync/cpg.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: corosync/cpg.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: corosync/cpg.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: corosync/cpg.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: corosync/cpg.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: corosync/cpg.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: corosync/cpg.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: corosync/cpg.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: corosync/cpg.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for corosync/cpg.h" >&5 echo $ECHO_N "checking for corosync/cpg.h... $ECHO_C" >&6 if test "${ac_cv_header_corosync_cpg_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_corosync_cpg_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_corosync_cpg_h" >&5 echo "${ECHO_T}$ac_cv_header_corosync_cpg_h" >&6 fi if test $ac_cv_header_corosync_cpg_h = yes; then cpg_found=yes HAVE_COROSYNC=yes else if test "${ac_cv_header_openais_cpg_h+set}" = set; then echo "$as_me:$LINENO: checking for openais/cpg.h" >&5 echo $ECHO_N "checking for openais/cpg.h... $ECHO_C" >&6 if test "${ac_cv_header_openais_cpg_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_openais_cpg_h" >&5 echo "${ECHO_T}$ac_cv_header_openais_cpg_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking openais/cpg.h usability" >&5 echo $ECHO_N "checking openais/cpg.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking openais/cpg.h presence" >&5 echo $ECHO_N "checking openais/cpg.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: openais/cpg.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: openais/cpg.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: openais/cpg.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: openais/cpg.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: openais/cpg.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: openais/cpg.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: openais/cpg.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: openais/cpg.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: openais/cpg.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: openais/cpg.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: openais/cpg.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: openais/cpg.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: openais/cpg.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: openais/cpg.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: openais/cpg.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: openais/cpg.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for openais/cpg.h" >&5 echo $ECHO_N "checking for openais/cpg.h... $ECHO_C" >&6 if test "${ac_cv_header_openais_cpg_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_openais_cpg_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_openais_cpg_h" >&5 echo "${ECHO_T}$ac_cv_header_openais_cpg_h" >&6 fi if test $ac_cv_header_openais_cpg_h = yes; then cpg_found=yes else { echo "$as_me:$LINENO: WARNING: openais/cpg.h not found, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: openais/cpg.h not found, ocfs2_controld will not be built" >&2;} fi fi # # We can't use AC_CHECK_LIB on corosync or openais libraries, because they # are in ${libdir}/corosync or ${libdir}/openais, and we can't expand it in # configure.in. What we'll try instead is to search AIS_TRY_PATH for # -L/ -l. # NOTE that the initial colon ':' is *intentional*. We want the empty # string first in case the user passed LDFLAGS. # AIS_TRY_PATH=":/usr/lib64:/usr/lib:/usr/local/lib64:/usr/local/lib" CPG_LDFLAGS= if test "x$cpg_found" = "xyes"; then cpg_found= if test "x$HAVE_COROSYNC" = "xyes"; then cpg_package=corosync else cpg_package=openais fi TRY_PATH="$AIS_TRY_PATH" echo "$as_me:$LINENO: checking for cpg_initialize in -lcpg" >&5 echo $ECHO_N "checking for cpg_initialize in -lcpg... $ECHO_C" >&6 while test "x$TRY_PATH" != "x"; do TRY="`echo $TRY_PATH | cut -f1 -d:`" NEW_TRY_PATH="`echo $TRY_PATH | cut -f2- -d:`" if test "x$NEW_TRY_PATH" != "x$TRY_PATH"; then TRY_PATH="$NEW_TRY_PATH" else TRY_PATH="" fi if test "x$TRY" != "x"; then TRY="-L${TRY}/${cpg_package}" fi # TRY="$TRY" saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $TRY -lcpg" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char cpg_initialize (); int main () { cpg_initialize (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cpg_found=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$saved_LDFLAGS" if test "x$cpg_found" = "xyes"; then CPG_LDFLAGS="$TRY" break fi done fi if test "x$cpg_found" = "xyes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 { echo "$as_me:$LINENO: WARNING: libcpg not found, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: libcpg not found, ocfs2_controld will not be built" >&2;} fi ckpt_found= echo "$as_me:$LINENO: checking for openais/saCkpt.h" >&5 echo $ECHO_N "checking for openais/saCkpt.h... $ECHO_C" >&6 if test "${ac_cv_header_openais_saCkpt_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_openais_saCkpt_h=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_openais_saCkpt_h=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_header_openais_saCkpt_h" >&5 echo "${ECHO_T}$ac_cv_header_openais_saCkpt_h" >&6 if test $ac_cv_header_openais_saCkpt_h = yes; then ckpt_found=yes else { echo "$as_me:$LINENO: WARNING: openais/saCkpt.h not found, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: openais/saCkpt.h not found, ocfs2_controld will not be built" >&2;} fi AIS_LDFLAGS= if test "x$ckpt_found" = "xyes"; then ckpt_found= TRY_PATH="$AIS_TRY_PATH" echo "$as_me:$LINENO: checking for saCkptInitialize in -lSaCkpt" >&5 echo $ECHO_N "checking for saCkptInitialize in -lSaCkpt... $ECHO_C" >&6 while test "x$TRY_PATH" != "x"; do TRY="`echo $TRY_PATH | cut -f1 -d:`" NEW_TRY_PATH="`echo $TRY_PATH | cut -f2- -d:`" if test "x$NEW_TRY_PATH" != "x$TRY_PATH"; then TRY_PATH="$NEW_TRY_PATH" else TRY_PATH="" fi if test "x$TRY" != "x"; then TRY="-L${TRY}/openais" fi # TRY="$TRY" saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $TRY -lSaCkpt" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char saCkptInitialize (); int main () { saCkptInitialize (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ckpt_found=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$saved_LDFLAGS" if test "x$ckpt_found" = "xyes"; then AIS_LDFLAGS="$TRY" break fi done fi if test "x$ckpt_found" = "xyes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 { echo "$as_me:$LINENO: WARNING: libSaCkpt not found, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: libSaCkpt not found, ocfs2_controld will not be built" >&2;} fi libdlmcontrol_found= echo "$as_me:$LINENO: checking for dlmc_fs_connect in -ldlmcontrol" >&5 echo $ECHO_N "checking for dlmc_fs_connect in -ldlmcontrol... $ECHO_C" >&6 if test "${ac_cv_lib_dlmcontrol_dlmc_fs_connect+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldlmcontrol $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlmc_fs_connect (); int main () { dlmc_fs_connect (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dlmcontrol_dlmc_fs_connect=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dlmcontrol_dlmc_fs_connect=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dlmcontrol_dlmc_fs_connect" >&5 echo "${ECHO_T}$ac_cv_lib_dlmcontrol_dlmc_fs_connect" >&6 if test $ac_cv_lib_dlmcontrol_dlmc_fs_connect = yes; then echo "$as_me:$LINENO: checking for libdlmcontrol.h" >&5 echo $ECHO_N "checking for libdlmcontrol.h... $ECHO_C" >&6 if test "${ac_cv_header_libdlmcontrol_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_libdlmcontrol_h=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_libdlmcontrol_h=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_header_libdlmcontrol_h" >&5 echo "${ECHO_T}$ac_cv_header_libdlmcontrol_h" >&6 if test $ac_cv_header_libdlmcontrol_h = yes; then libdlmcontrol_found=yes else { echo "$as_me:$LINENO: WARNING: libdlmcontrol.h not found, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: libdlmcontrol.h not found, ocfs2_controld will not be built" >&2;} fi else { echo "$as_me:$LINENO: WARNING: libdlmcontrol not found, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: libdlmcontrol not found, ocfs2_controld will not be built" >&2;} fi LIBDLM_FOUND= if test "${ac_cv_header_libdlm_h+set}" = set; then echo "$as_me:$LINENO: checking for libdlm.h" >&5 echo $ECHO_N "checking for libdlm.h... $ECHO_C" >&6 if test "${ac_cv_header_libdlm_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_libdlm_h" >&5 echo "${ECHO_T}$ac_cv_header_libdlm_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking libdlm.h usability" >&5 echo $ECHO_N "checking libdlm.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking libdlm.h presence" >&5 echo $ECHO_N "checking libdlm.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: libdlm.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: libdlm.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: libdlm.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: libdlm.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: libdlm.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: libdlm.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: libdlm.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: libdlm.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: libdlm.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: libdlm.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: libdlm.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: libdlm.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: libdlm.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: libdlm.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: libdlm.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: libdlm.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for libdlm.h" >&5 echo $ECHO_N "checking for libdlm.h... $ECHO_C" >&6 if test "${ac_cv_header_libdlm_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_libdlm_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_libdlm_h" >&5 echo "${ECHO_T}$ac_cv_header_libdlm_h" >&6 fi if test $ac_cv_header_libdlm_h = yes; then LIBDLM_FOUND=yes else { echo "$as_me:$LINENO: WARNING: libdlm.h not found, fsdlm support will not be built" >&5 echo "$as_me: WARNING: libdlm.h not found, fsdlm support will not be built" >&2;} fi fsdlm_found= if test "x$LIBDLM_FOUND" = "xyes"; then echo "$as_me:$LINENO: checking for dlm_create_lockspace in -ldlm_lt" >&5 echo $ECHO_N "checking for dlm_create_lockspace in -ldlm_lt... $ECHO_C" >&6 if test "${ac_cv_lib_dlm_lt_dlm_create_lockspace+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldlm_lt $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlm_create_lockspace (); int main () { dlm_create_lockspace (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dlm_lt_dlm_create_lockspace=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dlm_lt_dlm_create_lockspace=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dlm_lt_dlm_create_lockspace" >&5 echo "${ECHO_T}$ac_cv_lib_dlm_lt_dlm_create_lockspace" >&6 if test $ac_cv_lib_dlm_lt_dlm_create_lockspace = yes; then fsdlm_found=yes fi if test "xfsdlm_found" = "xyes"; then { echo "$as_me:$LINENO: WARNING: libdlm_lt not found, fsdlm support will not be built" >&5 echo "$as_me: WARNING: libdlm_lt not found, fsdlm support will not be built" >&2;} fi fi BUILD_FSDLM_SUPPORT= DL_LIBS= if test "x$fsdlm_found" = "xyes"; then BUILD_FSDLM_SUPPORT=yes DL_LIBS=-ldl fi BUILD_OCFS2_CONTROLD= if test "x$cpg_found" = "xyes" -a "x$ckpt_found" = "xyes" -a "x$libdlmcontrol_found" = "xyes"; then if test "x$fsdlm_found" = "xyes"; then BUILD_OCFS2_CONTROLD=yes else { echo "$as_me:$LINENO: WARNING: fsdlm support is not available, ocfs2_controld will not be built" >&5 echo "$as_me: WARNING: fsdlm support is not available, ocfs2_controld will not be built" >&2;} fi fi BUILD_PCMK_SUPPORT= if test "x$pcmk_found" = "xyes" -a "x$BUILD_OCFS2_CONTROLD" = "xyes"; then BUILD_PCMK_SUPPORT=yes fi BUILD_CMAN_SUPPORT= if test "x$cman_found" = "xyes" -a "x$BUILD_OCFS2_CONTROLD" = "xyes"; then BUILD_CMAN_SUPPORT=yes fi BUILD_OCFS2CONSOLE= # Check whether --enable-ocfs2console or --disable-ocfs2console was given. if test "${enable_ocfs2console+set}" = set; then enableval="$enable_ocfs2console" else enable_ocfs2console=yes fi; if test "x$enable_ocfs2console" = "xyes"; then if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. echo "$as_me:$LINENO: checking whether $PYTHON version >= 2.3" >&5 echo $ECHO_N "checking whether $PYTHON version >= 2.3... $ECHO_C" >&6 prog="import sys, string # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. minver = map(int, string.split('2.3', '.')) + [0, 0, 0] minverhex = 0 for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 ($PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else { { echo "$as_me:$LINENO: error: too old" >&5 echo "$as_me: error: too old" >&2;} { (exit 1); exit 1; }; } fi am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. echo "$as_me:$LINENO: checking for a Python interpreter with version >= 2.3" >&5 echo $ECHO_N "checking for a Python interpreter with version >= 2.3... $ECHO_C" >&6 if test "${am_cv_pathless_PYTHON+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else for am_cv_pathless_PYTHON in python python2 python2.4 python2.3 python2.2 python2.1 python2.0 python1.6 python1.5 none; do test "$am_cv_pathless_PYTHON" = none && break prog="import sys, string # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. minver = map(int, string.split('2.3', '.')) + [0, 0, 0] minverhex = 0 for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then break fi done fi echo "$as_me:$LINENO: result: $am_cv_pathless_PYTHON" >&5 echo "${ECHO_T}$am_cv_pathless_PYTHON" >&6 # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. set dummy $am_cv_pathless_PYTHON; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PYTHON+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then echo "$as_me:$LINENO: result: $PYTHON" >&5 echo "${ECHO_T}$PYTHON" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi am_display_PYTHON=$am_cv_pathless_PYTHON fi if test "$PYTHON" = :; then have_python=no else echo "$as_me:$LINENO: checking for $am_display_PYTHON version" >&5 echo $ECHO_N "checking for $am_display_PYTHON version... $ECHO_C" >&6 if test "${am_cv_python_version+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else am_cv_python_version=`$PYTHON -c "import sys; print sys.version[:3]"` fi echo "$as_me:$LINENO: result: $am_cv_python_version" >&5 echo "${ECHO_T}$am_cv_python_version" >&6 PYTHON_VERSION=$am_cv_python_version PYTHON_PREFIX='${prefix}' PYTHON_EXEC_PREFIX='${exec_prefix}' echo "$as_me:$LINENO: checking for $am_display_PYTHON platform" >&5 echo $ECHO_N "checking for $am_display_PYTHON platform... $ECHO_C" >&6 if test "${am_cv_python_platform+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"` fi echo "$as_me:$LINENO: result: $am_cv_python_platform" >&5 echo "${ECHO_T}$am_cv_python_platform" >&6 PYTHON_PLATFORM=$am_cv_python_platform echo "$as_me:$LINENO: checking for $am_display_PYTHON script directory" >&5 echo $ECHO_N "checking for $am_display_PYTHON script directory... $ECHO_C" >&6 if test "${am_cv_python_pythondir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null || echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` fi echo "$as_me:$LINENO: result: $am_cv_python_pythondir" >&5 echo "${ECHO_T}$am_cv_python_pythondir" >&6 pythondir=$am_cv_python_pythondir pkgpythondir=\${pythondir}/$PACKAGE echo "$as_me:$LINENO: checking for $am_display_PYTHON extension module directory" >&5 echo $ECHO_N "checking for $am_display_PYTHON extension module directory... $ECHO_C" >&6 if test "${am_cv_python_pyexecdir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null || echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"` fi echo "$as_me:$LINENO: result: $am_cv_python_pyexecdir" >&5 echo "${ECHO_T}$am_cv_python_pyexecdir" >&6 pyexecdir=$am_cv_python_pyexecdir pkgpyexecdir=\${pyexecdir}/$PACKAGE have_python=yes fi if test "x$have_python" = "xyes"; then echo "$as_me:$LINENO: checking for headers required to compile python extensions" >&5 echo $ECHO_N "checking for headers required to compile python extensions... $ECHO_C" >&6 py_prefix=`$PYTHON -c "import sys; print sys.prefix"` py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" if test "$py_prefix" != "$py_exec_prefix"; then PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" fi save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then echo "$as_me:$LINENO: result: found" >&5 echo "${ECHO_T}found" >&6 have_pythondev=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: not found" >&5 echo "${ECHO_T}not found" >&6 have_pythondev=no fi rm -f conftest.err conftest.$ac_ext CPPFLAGS="$save_CPPFLAGS" if test "x$have_pythondev" = "xyes"; then if $PYTHON -c 'import gobject' >/dev/null 2>&1; then BUILD_OCFS2CONSOLE=yes HAVE_BLKID= succeeded=no if test -z "$PKG_CONFIG"; then # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PKG_CONFIG+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 echo "${ECHO_T}$PKG_CONFIG" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test "$PKG_CONFIG" = "no" ; then echo "*** The pkg-config script could not be found. Make sure it is" echo "*** in your path, or set the PKG_CONFIG environment variable" echo "*** to the full path to pkg-config." echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." else PKG_CONFIG_MIN_VERSION=0.9.0 if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then echo "$as_me:$LINENO: checking for blkid >= 1.36" >&5 echo $ECHO_N "checking for blkid >= 1.36... $ECHO_C" >&6 if $PKG_CONFIG --exists "blkid >= 1.36" ; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 succeeded=yes echo "$as_me:$LINENO: checking BLKID_CFLAGS" >&5 echo $ECHO_N "checking BLKID_CFLAGS... $ECHO_C" >&6 BLKID_CFLAGS=`$PKG_CONFIG --cflags "blkid >= 1.36"` echo "$as_me:$LINENO: result: $BLKID_CFLAGS" >&5 echo "${ECHO_T}$BLKID_CFLAGS" >&6 echo "$as_me:$LINENO: checking BLKID_LIBS" >&5 echo $ECHO_N "checking BLKID_LIBS... $ECHO_C" >&6 BLKID_LIBS=`$PKG_CONFIG --libs "blkid >= 1.36"` echo "$as_me:$LINENO: result: $BLKID_LIBS" >&5 echo "${ECHO_T}$BLKID_LIBS" >&6 else BLKID_CFLAGS="" BLKID_LIBS="" ## If we have a custom action on failure, don't print errors, but ## do set a variable so people can do so. BLKID_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "blkid >= 1.36"` fi else echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." echo "*** See http://www.freedesktop.org/software/pkgconfig" fi fi if test $succeeded = yes; then HAVE_BLKID=yes else { echo "$as_me:$LINENO: WARNING: blkid >= 1.36 not found, using internal version" >&5 echo "$as_me: WARNING: blkid >= 1.36 not found, using internal version" >&2;} fi if test "x$HAVE_BLKID" != "xyes"; then echo "$as_me:$LINENO: checking for short" >&5 echo $ECHO_N "checking for short... $ECHO_C" >&6 if test "${ac_cv_type_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((short *) 0) return 0; if (sizeof (short)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_short=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_short=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 echo "${ECHO_T}$ac_cv_type_short" >&6 echo "$as_me:$LINENO: checking size of short" >&5 echo $ECHO_N "checking size of short... $ECHO_C" >&6 if test "${ac_cv_sizeof_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_short" = yes; then # The cast to unsigned long works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_short=$ac_lo;; '') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (short), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } ;; esac else if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default long longval () { return (long) (sizeof (short)); } unsigned long ulongval () { return (long) (sizeof (short)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) exit (1); if (((long) (sizeof (short))) < 0) { long i = longval (); if (i != ((long) (sizeof (short)))) exit (1); fprintf (f, "%ld\n", i); } else { unsigned long i = ulongval (); if (i != ((long) (sizeof (short)))) exit (1); fprintf (f, "%lu\n", i); } exit (ferror (f) || fclose (f) != 0); ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_short=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (short), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f conftest.val else ac_cv_sizeof_short=0 fi fi echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 echo "${ECHO_T}$ac_cv_sizeof_short" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF echo "$as_me:$LINENO: checking for int" >&5 echo $ECHO_N "checking for int... $ECHO_C" >&6 if test "${ac_cv_type_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((int *) 0) return 0; if (sizeof (int)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_int=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_int=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 echo "${ECHO_T}$ac_cv_type_int" >&6 echo "$as_me:$LINENO: checking size of int" >&5 echo $ECHO_N "checking size of int... $ECHO_C" >&6 if test "${ac_cv_sizeof_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_int" = yes; then # The cast to unsigned long works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (int))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (int))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (int))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_int=$ac_lo;; '') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (int), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } ;; esac else if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default long longval () { return (long) (sizeof (int)); } unsigned long ulongval () { return (long) (sizeof (int)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) exit (1); if (((long) (sizeof (int))) < 0) { long i = longval (); if (i != ((long) (sizeof (int)))) exit (1); fprintf (f, "%ld\n", i); } else { unsigned long i = ulongval (); if (i != ((long) (sizeof (int)))) exit (1); fprintf (f, "%lu\n", i); } exit (ferror (f) || fclose (f) != 0); ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_int=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (int), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f conftest.val else ac_cv_sizeof_int=0 fi fi echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 echo "${ECHO_T}$ac_cv_sizeof_int" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF echo "$as_me:$LINENO: checking for long" >&5 echo $ECHO_N "checking for long... $ECHO_C" >&6 if test "${ac_cv_type_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((long *) 0) return 0; if (sizeof (long)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_long=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_long=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 echo "${ECHO_T}$ac_cv_type_long" >&6 echo "$as_me:$LINENO: checking size of long" >&5 echo $ECHO_N "checking size of long... $ECHO_C" >&6 if test "${ac_cv_sizeof_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_long" = yes; then # The cast to unsigned long works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_long=$ac_lo;; '') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (long), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } ;; esac else if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default long longval () { return (long) (sizeof (long)); } unsigned long ulongval () { return (long) (sizeof (long)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) exit (1); if (((long) (sizeof (long))) < 0) { long i = longval (); if (i != ((long) (sizeof (long)))) exit (1); fprintf (f, "%ld\n", i); } else { unsigned long i = ulongval (); if (i != ((long) (sizeof (long)))) exit (1); fprintf (f, "%lu\n", i); } exit (ferror (f) || fclose (f) != 0); ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_long=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (long), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f conftest.val else ac_cv_sizeof_long=0 fi fi echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 echo "${ECHO_T}$ac_cv_sizeof_long" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF echo "$as_me:$LINENO: checking for long long" >&5 echo $ECHO_N "checking for long long... $ECHO_C" >&6 if test "${ac_cv_type_long_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((long long *) 0) return 0; if (sizeof (long long)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_long_long=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_long_long=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5 echo "${ECHO_T}$ac_cv_type_long_long" >&6 echo "$as_me:$LINENO: checking size of long long" >&5 echo $ECHO_N "checking size of long long... $ECHO_C" >&6 if test "${ac_cv_sizeof_long_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_long_long" = yes; then # The cast to unsigned long works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long long))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_long_long=$ac_lo;; '') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } ;; esac else if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default long longval () { return (long) (sizeof (long long)); } unsigned long ulongval () { return (long) (sizeof (long long)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) exit (1); if (((long) (sizeof (long long))) < 0) { long i = longval (); if (i != ((long) (sizeof (long long)))) exit (1); fprintf (f, "%ld\n", i); } else { unsigned long i = ulongval (); if (i != ((long) (sizeof (long long)))) exit (1); fprintf (f, "%lu\n", i); } exit (ferror (f) || fclose (f) != 0); ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_long_long=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f conftest.val else ac_cv_sizeof_long_long=0 fi fi echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5 echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long _ACEOF ac_config_commands="$ac_config_commands ocfs2console/blkid/blkid_types.h" fi else { echo "$as_me:$LINENO: WARNING: could not find PyGTK, ocfs2console will not be built" >&5 echo "$as_me: WARNING: could not find PyGTK, ocfs2console will not be built" >&2;} fi else { echo "$as_me:$LINENO: WARNING: could not find Python headers, ocfs2console will not be built" >&5 echo "$as_me: WARNING: could not find Python headers, ocfs2console will not be built" >&2;} fi else { echo "$as_me:$LINENO: WARNING: could not find Python 2.3 or higher, ocfs2console will not be built" >&5 echo "$as_me: WARNING: could not find Python 2.3 or higher, ocfs2console will not be built" >&2;} fi fi ac_config_files="$ac_config_files Config.make o2cb.pc o2dlm.pc ocfs2.pc ocfs2console/ocfs2interface/confdefs.py debugfs.ocfs2/debugfs.ocfs2.8 mkfs.ocfs2/mkfs.ocfs2.8 mounted.ocfs2/mounted.ocfs2.8 fsck.ocfs2/fsck.ocfs2.8 fsck.ocfs2/fsck.ocfs2.checks.8 mount.ocfs2/mount.ocfs2.8 o2cb_ctl/o2cb_ctl.8 ocfs2_hb_ctl/ocfs2_hb_ctl.8 ocfs2console/ocfs2console.8 tunefs.ocfs2/tunefs.ocfs2.8 o2image/o2image.8 o2info/o2info.1 libo2cb/o2cb.7 vendor/common/ocfs2-tools.spec-generic" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # INIT-COMMANDS section. # ocfs2_SIZEOF_SHORT=$ac_cv_sizeof_short ocfs2_SIZEOF_INT=$ac_cv_sizeof_int ocfs2_SIZEOF_LONG=$ac_cv_sizeof_long ocfs2_SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Config.make" ) CONFIG_FILES="$CONFIG_FILES Config.make" ;; "o2cb.pc" ) CONFIG_FILES="$CONFIG_FILES o2cb.pc" ;; "o2dlm.pc" ) CONFIG_FILES="$CONFIG_FILES o2dlm.pc" ;; "ocfs2.pc" ) CONFIG_FILES="$CONFIG_FILES ocfs2.pc" ;; "ocfs2console/ocfs2interface/confdefs.py" ) CONFIG_FILES="$CONFIG_FILES ocfs2console/ocfs2interface/confdefs.py" ;; "debugfs.ocfs2/debugfs.ocfs2.8" ) CONFIG_FILES="$CONFIG_FILES debugfs.ocfs2/debugfs.ocfs2.8" ;; "mkfs.ocfs2/mkfs.ocfs2.8" ) CONFIG_FILES="$CONFIG_FILES mkfs.ocfs2/mkfs.ocfs2.8" ;; "mounted.ocfs2/mounted.ocfs2.8" ) CONFIG_FILES="$CONFIG_FILES mounted.ocfs2/mounted.ocfs2.8" ;; "fsck.ocfs2/fsck.ocfs2.8" ) CONFIG_FILES="$CONFIG_FILES fsck.ocfs2/fsck.ocfs2.8" ;; "fsck.ocfs2/fsck.ocfs2.checks.8" ) CONFIG_FILES="$CONFIG_FILES fsck.ocfs2/fsck.ocfs2.checks.8" ;; "mount.ocfs2/mount.ocfs2.8" ) CONFIG_FILES="$CONFIG_FILES mount.ocfs2/mount.ocfs2.8" ;; "o2cb_ctl/o2cb_ctl.8" ) CONFIG_FILES="$CONFIG_FILES o2cb_ctl/o2cb_ctl.8" ;; "ocfs2_hb_ctl/ocfs2_hb_ctl.8" ) CONFIG_FILES="$CONFIG_FILES ocfs2_hb_ctl/ocfs2_hb_ctl.8" ;; "ocfs2console/ocfs2console.8" ) CONFIG_FILES="$CONFIG_FILES ocfs2console/ocfs2console.8" ;; "tunefs.ocfs2/tunefs.ocfs2.8" ) CONFIG_FILES="$CONFIG_FILES tunefs.ocfs2/tunefs.ocfs2.8" ;; "o2image/o2image.8" ) CONFIG_FILES="$CONFIG_FILES o2image/o2image.8" ;; "o2info/o2info.1" ) CONFIG_FILES="$CONFIG_FILES o2info/o2info.1" ;; "libo2cb/o2cb.7" ) CONFIG_FILES="$CONFIG_FILES libo2cb/o2cb.7" ;; "vendor/common/ocfs2-tools.spec-generic" ) CONFIG_FILES="$CONFIG_FILES vendor/common/ocfs2-tools.spec-generic" ;; "ocfs2console/blkid/blkid_types.h" ) CONFIG_COMMANDS="$CONFIG_COMMANDS ocfs2console/blkid/blkid_types.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@PACKAGE@,$PACKAGE,;t t s,@MAJOR_VERSION@,$MAJOR_VERSION,;t t s,@MINOR_VERSION@,$MINOR_VERSION,;t t s,@MICRO_VERSION@,$MICRO_VERSION,;t t s,@EXTRA_VERSION@,$EXTRA_VERSION,;t t s,@DIST_VERSION@,$DIST_VERSION,;t t s,@VERSION@,$VERSION,;t t s,@build@,$build,;t t s,@build_cpu@,$build_cpu,;t t s,@build_vendor@,$build_vendor,;t t s,@build_os@,$build_os,;t t s,@host@,$host,;t t s,@host_cpu@,$host_cpu,;t t s,@host_vendor@,$host_vendor,;t t s,@host_os@,$host_os,;t t s,@OCFS2_DEBUG@,$OCFS2_DEBUG,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@CPP@,$CPP,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@LN_S@,$LN_S,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@AR@,$AR,;t t s,@EGREP@,$EGREP,;t t s,@VENDOR@,$VENDOR,;t t s,@root_prefix@,$root_prefix,;t t s,@root_bindir@,$root_bindir,;t t s,@root_sbindir@,$root_sbindir,;t t s,@root_sysconfdir@,$root_sysconfdir,;t t s,@PKG_CONFIG@,$PKG_CONFIG,;t t s,@COM_ERR_CFLAGS@,$COM_ERR_CFLAGS,;t t s,@COM_ERR_LIBS@,$COM_ERR_LIBS,;t t s,@UUID_LIBS@,$UUID_LIBS,;t t s,@NCURSES_LIBS@,$NCURSES_LIBS,;t t s,@READLINE_LIBS@,$READLINE_LIBS,;t t s,@OCFS2_DEBUG_EXE@,$OCFS2_DEBUG_EXE,;t t s,@GLIB_CFLAGS@,$GLIB_CFLAGS,;t t s,@GLIB_LIBS@,$GLIB_LIBS,;t t s,@GLIB_GENMARSHAL@,$GLIB_GENMARSHAL,;t t s,@GOBJECT_QUERY@,$GOBJECT_QUERY,;t t s,@GLIB_MKENUMS@,$GLIB_MKENUMS,;t t s,@OCFS2_DYNAMIC_FSCK@,$OCFS2_DYNAMIC_FSCK,;t t s,@OCFS2_DYNAMIC_CTL@,$OCFS2_DYNAMIC_CTL,;t t s,@BUILD_DEBUGOCFS2@,$BUILD_DEBUGOCFS2,;t t s,@HAVE_COROSYNC@,$HAVE_COROSYNC,;t t s,@CPG_LDFLAGS@,$CPG_LDFLAGS,;t t s,@AIS_LDFLAGS@,$AIS_LDFLAGS,;t t s,@LIBDLM_FOUND@,$LIBDLM_FOUND,;t t s,@BUILD_FSDLM_SUPPORT@,$BUILD_FSDLM_SUPPORT,;t t s,@DL_LIBS@,$DL_LIBS,;t t s,@BUILD_OCFS2_CONTROLD@,$BUILD_OCFS2_CONTROLD,;t t s,@BUILD_PCMK_SUPPORT@,$BUILD_PCMK_SUPPORT,;t t s,@BUILD_CMAN_SUPPORT@,$BUILD_CMAN_SUPPORT,;t t s,@PYTHON@,$PYTHON,;t t s,@PYTHON_VERSION@,$PYTHON_VERSION,;t t s,@PYTHON_PREFIX@,$PYTHON_PREFIX,;t t s,@PYTHON_EXEC_PREFIX@,$PYTHON_EXEC_PREFIX,;t t s,@PYTHON_PLATFORM@,$PYTHON_PLATFORM,;t t s,@pythondir@,$pythondir,;t t s,@pkgpythondir@,$pkgpythondir,;t t s,@pyexecdir@,$pyexecdir,;t t s,@pkgpyexecdir@,$pkgpyexecdir,;t t s,@PYTHON_INCLUDES@,$PYTHON_INCLUDES,;t t s,@BLKID_CFLAGS@,$BLKID_CFLAGS,;t t s,@BLKID_LIBS@,$BLKID_LIBS,;t t s,@HAVE_BLKID@,$HAVE_BLKID,;t t s,@BUILD_OCFS2CONSOLE@,$BUILD_OCFS2CONSOLE,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_COMMANDS section. # for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue ac_dest=`echo "$ac_file" | sed 's,:.*,,'` ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_dir=`(dirname "$ac_dest") 2>/dev/null || $as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_dest" : 'X\(//\)[^/]' \| \ X"$ac_dest" : 'X\(//\)$' \| \ X"$ac_dest" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_dest" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 echo "$as_me: executing $ac_dest commands" >&6;} case $ac_dest in ocfs2console/blkid/blkid_types.h ) outfile=ocfs2console/blkid/blkid_types.h-tmp cat > $outfile <<_______EOF /* * If linux/types.h is already been included, assume it has defined * everything we need. (cross fingers) Other header files may have * also defined the types that we need. */ #if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \\ !defined(_EXT2_TYPES_H)) #define _BLKID_TYPES_H typedef unsigned char __u8; typedef signed char __s8; #if ($ocfs2_SIZEOF_INT == 8) typedef int __s64; typedef unsigned int __u64; #else #if ($ocfs2_SIZEOF_LONG == 8) typedef long __s64; typedef unsigned long __u64; #else #if ($ocfs2_SIZEOF_LONG_LONG == 8) #if defined(__GNUC__) typedef __signed__ long long __s64; #else typedef signed long long __s64; #endif /* __GNUC__ */ typedef unsigned long long __u64; #endif /* SIZEOF_LONG_LONG == 8 */ #endif /* SIZEOF_LONG == 8 */ #endif /* SIZEOF_INT == 8 */ #if ($ocfs2_SIZEOF_INT == 2) typedef int __s16; typedef unsigned int __u16; #else #if ($ocfs2_SIZEOF_SHORT == 2) typedef short __s16; typedef unsigned short __u16; #else ?==error: undefined 16 bit type #endif /* SIZEOF_SHORT == 2 */ #endif /* SIZEOF_INT == 2 */ #if ($ocfs2_SIZEOF_INT == 4) typedef int __s32; typedef unsigned int __u32; #else #if ($ocfs2_SIZEOF_LONG == 4) typedef long __s32; typedef unsigned long __u32; #else #if ($ocfs2_SIZEOF_SHORT == 4) typedef short __s32; typedef unsigned short __u32; #else ?== error: undefined 32 bit type #endif /* SIZEOF_SHORT == 4 */ #endif /* SIZEOF_LONG == 4 */ #endif /* SIZEOF_INT == 4 */ #endif /* _*_TYPES_H */ _______EOF if cmp -s $outfile ocfs2console/blkid/blkid_types.h; then { echo "$as_me:$LINENO: ocfs2console/blkid/blkid_types.h is unchanged" >&5 echo "$as_me: ocfs2console/blkid/blkid_types.h is unchanged" >&6;} rm -f $outfile else mv $outfile ocfs2console/blkid/blkid_types.h fi ;; esac done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi ./ocfs2-tools-1.6.4/configure.in0000644000176100017610000003010011515637347013275 00000000000000AC_PREREQ(2.54) AC_INIT(libocfs2/bitmap.c) PACKAGE=ocfs2-tools AC_SUBST(PACKAGE) # Adjust these for the software version. MAJOR_VERSION=1 MINOR_VERSION=6 MICRO_VERSION=4 EXTRA_VERSION= DIST_VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION if test -z "$EXTRA_VERSION"; then VERSION=$DIST_VERSION else VERSION=$DIST_VERSION-$EXTRA_VERSION fi AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(MICRO_VERSION) AC_SUBST(EXTRA_VERSION) AC_SUBST(DIST_VERSION) AC_SUBST(VERSION) AC_CANONICAL_HOST case "$host" in *-*-linux*) ;; *) AC_MSG_ERROR([This filesystem will only work on Linux]) ;; esac # # If CFLAGS is non-empty, leave the debugging and optimization symobls # to the caller. Otherwise, set them according to --enable-debug. # OCFS2_DEBUG= AC_MSG_CHECKING(for debugging) if test "x$CFLAGS" = "x"; then AC_ARG_ENABLE(debug, [ --enable-debug=[yes/no] Turn on debugging [default=no]],,enable_debug=no) if test "x$enable_debug" = "xyes"; then OCFS2_DEBUG=yes CFLAGS="-g" else CFLAGS="-O2" fi AC_MSG_RESULT($enable_debug) else AC_MSG_RESULT([skipped, CFLAGS is set]) fi AC_SUBST(OCFS2_DEBUG) AC_PROG_CC AC_PROG_CPP # # If OCFS2_DEBUG was set, we know CFLAGS must be "-g". If we're using # GNU C, get extra debugging symbols. # if test "x$GCC" = "xyes" -a "x$OCFS2_DEBUG" = "xyes"; then CFLAGS="-ggdb" fi AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_RANLIB AC_PATH_PROG(AR, ar) AC_HEADER_STDC AC_C_CONST MB_VENDOR(VENDOR) if test "x$GCC" != "xyes"; then AC_MSG_ERROR(GCC is required) fi AC_ARG_WITH([root-prefix], [ --with-root-prefix=PREFIX override prefix variable for files to be placed in the root], root_prefix=$withval, root_prefix="") root_bindir='${root_prefix}/bin' root_sbindir='${root_prefix}/sbin' root_sysconfdir='${root_prefix}/etc' AC_SUBST(root_prefix) AC_SUBST(root_bindir) AC_SUBST(root_sbindir) AC_SUBST(root_sysconfdir) COM_ERR_LIBS= PKG_CHECK_MODULES(COM_ERR, com_err,, [ AC_CHECK_LIB(com_err, com_err, COM_ERR_LIBS=-lcom_err) if test "x$COM_ERR_LIBS" = "x"; then AC_MSG_ERROR([Unable to find com_err library]) fi AC_CHECK_HEADER(et/com_err.h, :, AC_MSG_ERROR([Unable to find com_err headers])) AC_SUBST(COM_ERR_LIBS) ]) UUID_LIBS= AC_CHECK_LIB(uuid, uuid_unparse, UUID_LIBS=-luuid) if test "x$UUID_LIBS" = "x"; then AC_MSG_ERROR([Unable to find uuid library]) fi AC_CHECK_HEADER(uuid/uuid.h, :, AC_MSG_ERROR([Unable to find uuid headers])) AC_SUBST(UUID_LIBS) NCURSES_LIBS= AC_CHECK_LIB(ncurses, tgetstr, NCURSES_LIBS=-lncurses) if test "x$NCURSES_LIBS" = "x"; then AC_MSG_ERROR([Unable to find ncurses library]) fi AC_SUBST(NCURSES_LIBS) saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -lncurses" READLINE_LIBS= AC_CHECK_LIB(readline, readline, READLINE_LIBS=-lreadline) if test "x$READLINE_LIBS" = "x"; then AC_MSG_ERROR([Unable to find readline library]) fi AC_CHECK_HEADER(readline/readline.h, :, AC_MSG_ERROR([Unable to find readline headers])) AC_SUBST(READLINE_LIBS) LDFLAGS="$saved_LDFLAGS" AC_MSG_CHECKING(for debug executables) AC_ARG_ENABLE(debugexe, [ --enable-debugexe=[yes/no] Enable debug executables for library source files [default=no]],,enable_debugexe=no) OCFS2_DEBUG_EXE= if test "x$enable_debugexe" = "xyes"; then OCFS2_DEBUG_EXE=yes fi AC_SUBST(OCFS2_DEBUG_EXE) AC_MSG_RESULT($enable_debugexe) GLIB_REQUIRED_VERSION=2.2.3 AM_PATH_GLIB_2_0($GLIB_REQUIRED_VERSION, have_glib=yes, AC_MSG_ERROR([GLib $GLIB_REQUIRED_VERSION or better is required])) # # Can we build statically? This is important # dyn_save_CFLAGS="$CFLAGS" dyn_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="-static $LIBS $GLIB_LIBS $COM_ERR_LIBS" AC_MSG_CHECKING(whether glib and com_err can be linked statically) AC_TRY_LINK([ #include #include #include ], [ char *e = error_message(-1); return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], [ static_lib_link=yes ], [ static_lib_link=no ]) AC_MSG_RESULT($static_lib_link) CFLAGS="$dyn_save_CFLAGS" LIBS="$dyn_save_LIBS" OCFS2_DYNAMIC_FSCK= AC_MSG_CHECKING(whether to build fsck dynamically) AC_ARG_ENABLE([dynamic-fsck], [ --enable-dynamic-fsck=[yes/no] Build fsck dynamically [default=no]],,enable_dynamic_fsck=detect) if test "x$enable_dynamic_fsck" = "xdetect"; then if test "x$static_lib_link" = "xyes"; then enable_dynamic_fsck=no else enable_dynamic_fsck=yes fi fi AC_MSG_RESULT($enable_dynamic_fsck) if test "x$static_lib_link" = "xno" -a "x$enable_dynamic_fsck" = "xno"; then AC_MSG_ERROR([Unable to statically link fsck.ocfs2]) fi if test "x$enable_dynamic_fsck" = "xyes"; then OCFS2_DYNAMIC_FSCK=yes fi AC_SUBST(OCFS2_DYNAMIC_FSCK) OCFS2_DYNAMIC_CTL= AC_MSG_CHECKING(whether to build cluster control tools dynamically) AC_ARG_ENABLE([dynamic-ctl], [ --enable-dynamic-ctl=[yes/no] Build cluster control tools dynamically [default=no]],,enable_dynamic_ctl=detect) if test "x$enable_dynamic_ctl" = "xdetect"; then if test "x$static_lib_link" = "xyes"; then enable_dynamic_ctl=no else enable_dynamic_ctl=yes fi fi AC_MSG_RESULT($enable_dynamic_ctl) if test "x$static_lib_link" = "xno" -a "x$enable_dynamic_ctl" = "xno"; then AC_MSG_ERROR([Unable to statically link cluster control tools]) fi if test "x$enable_dynamic_ctl" = "xyes"; then OCFS2_DYNAMIC_CTL=yes fi AC_SUBST(OCFS2_DYNAMIC_CTL) BUILD_DEBUGOCFS2= ocfs_tools_save_LIBS="$LIBS" LIBS="$LIBS -lncurses" AC_CHECK_LIB(readline, readline, [AC_CHECK_HEADER(readline/readline.h, BUILD_DEBUGOCFS2=yes, [AC_MSG_WARN([readline not found, debugfs.ocfs2 will not be built])])], [AC_MSG_WARN([readline not found, debugfs.ocfs2 will not be built])]) LIBS="$ocfs_tools_save_LIBS" AC_SUBST(BUILD_DEBUGOCFS2) pcmk_found= AC_CHECK_LIB(crmcluster, crm_get_peer, [AC_CHECK_HEADER(pacemaker/crm_config.h, pcmk_found=yes, [AC_MSG_WARN([Pacemaker headers not found, pacemaker support will not be built])])], [AC_MSG_WARN([libcrmcluster not found, pacemaker support will not be built])]) # We use cman_replyto_shutdown to insure a new enough libcman cman_found= AC_CHECK_LIB(cman, cman_replyto_shutdown, [AC_CHECK_HEADER(libcman.h, cman_found=yes, [AC_MSG_WARN([libcman.h not found, cman support will not be built])])], [AC_MSG_WARN([libcman not found, cman support will not be built])]) cpg_found= HAVE_COROSYNC= AC_CHECK_HEADER(corosync/cpg.h, [ cpg_found=yes HAVE_COROSYNC=yes ], [AC_CHECK_HEADER(openais/cpg.h, cpg_found=yes, [AC_MSG_WARN([openais/cpg.h not found, ocfs2_controld will not be built])])]) AC_SUBST(HAVE_COROSYNC) # # We can't use AC_CHECK_LIB on corosync or openais libraries, because they # are in ${libdir}/corosync or ${libdir}/openais, and we can't expand it in # configure.in. What we'll try instead is to search AIS_TRY_PATH for # -L/ -l. # NOTE that the initial colon ':' is *intentional*. We want the empty # string first in case the user passed LDFLAGS. # AIS_TRY_PATH=":/usr/lib64:/usr/lib:/usr/local/lib64:/usr/local/lib" CPG_LDFLAGS= if test "x$cpg_found" = "xyes"; then cpg_found= if test "x$HAVE_COROSYNC" = "xyes"; then cpg_package=corosync else cpg_package=openais fi TRY_PATH="$AIS_TRY_PATH" AC_MSG_CHECKING([for cpg_initialize in -lcpg]) while test "x$TRY_PATH" != "x"; do TRY="`echo $TRY_PATH | cut -f1 -d:`" NEW_TRY_PATH="`echo $TRY_PATH | cut -f2- -d:`" if test "x$NEW_TRY_PATH" != "x$TRY_PATH"; then TRY_PATH="$NEW_TRY_PATH" else TRY_PATH="" fi if test "x$TRY" != "x"; then TRY="-L${TRY}/${cpg_package}" fi # TRY="$TRY" saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $TRY -lcpg" AC_LINK_IFELSE([AC_LANG_CALL([], [cpg_initialize])], cpg_found=yes) LDFLAGS="$saved_LDFLAGS" if test "x$cpg_found" = "xyes"; then CPG_LDFLAGS="$TRY" break fi done fi if test "x$cpg_found" = "xyes"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) AC_MSG_WARN([libcpg not found, ocfs2_controld will not be built]) fi AC_SUBST(CPG_LDFLAGS) ckpt_found= AC_CHECK_HEADER(openais/saCkpt.h, ckpt_found=yes, [AC_MSG_WARN([openais/saCkpt.h not found, ocfs2_controld will not be built])], [#include ]) AIS_LDFLAGS= if test "x$ckpt_found" = "xyes"; then ckpt_found= TRY_PATH="$AIS_TRY_PATH" AC_MSG_CHECKING([for saCkptInitialize in -lSaCkpt]) while test "x$TRY_PATH" != "x"; do TRY="`echo $TRY_PATH | cut -f1 -d:`" NEW_TRY_PATH="`echo $TRY_PATH | cut -f2- -d:`" if test "x$NEW_TRY_PATH" != "x$TRY_PATH"; then TRY_PATH="$NEW_TRY_PATH" else TRY_PATH="" fi if test "x$TRY" != "x"; then TRY="-L${TRY}/openais" fi # TRY="$TRY" saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $TRY -lSaCkpt" AC_LINK_IFELSE([AC_LANG_CALL([], [saCkptInitialize])], ckpt_found=yes) LDFLAGS="$saved_LDFLAGS" if test "x$ckpt_found" = "xyes"; then AIS_LDFLAGS="$TRY" break fi done fi if test "x$ckpt_found" = "xyes"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) AC_MSG_WARN([libSaCkpt not found, ocfs2_controld will not be built]) fi AC_SUBST(AIS_LDFLAGS) libdlmcontrol_found= AC_CHECK_LIB(dlmcontrol, dlmc_fs_connect, [AC_CHECK_HEADER(libdlmcontrol.h, libdlmcontrol_found=yes, [AC_MSG_WARN([libdlmcontrol.h not found, ocfs2_controld will not be built])], [ #include #include #include ])], [AC_MSG_WARN([libdlmcontrol not found, ocfs2_controld will not be built])]) LIBDLM_FOUND= AC_CHECK_HEADER(libdlm.h, LIBDLM_FOUND=yes, [AC_MSG_WARN([libdlm.h not found, fsdlm support will not be built])]) AC_SUBST(LIBDLM_FOUND) fsdlm_found= if test "x$LIBDLM_FOUND" = "xyes"; then AC_CHECK_LIB(dlm_lt, dlm_create_lockspace, fsdlm_found=yes) if test "xfsdlm_found" = "xyes"; then AC_MSG_WARN([libdlm_lt not found, fsdlm support will not be built]) fi fi BUILD_FSDLM_SUPPORT= DL_LIBS= if test "x$fsdlm_found" = "xyes"; then BUILD_FSDLM_SUPPORT=yes DL_LIBS=-ldl fi AC_SUBST(BUILD_FSDLM_SUPPORT) AC_SUBST(DL_LIBS) BUILD_OCFS2_CONTROLD= if test "x$cpg_found" = "xyes" -a "x$ckpt_found" = "xyes" -a "x$libdlmcontrol_found" = "xyes"; then if test "x$fsdlm_found" = "xyes"; then BUILD_OCFS2_CONTROLD=yes else AC_MSG_WARN([fsdlm support is not available, ocfs2_controld will not be built]) fi fi AC_SUBST(BUILD_OCFS2_CONTROLD) BUILD_PCMK_SUPPORT= if test "x$pcmk_found" = "xyes" -a "x$BUILD_OCFS2_CONTROLD" = "xyes"; then BUILD_PCMK_SUPPORT=yes fi AC_SUBST(BUILD_PCMK_SUPPORT) BUILD_CMAN_SUPPORT= if test "x$cman_found" = "xyes" -a "x$BUILD_OCFS2_CONTROLD" = "xyes"; then BUILD_CMAN_SUPPORT=yes fi AC_SUBST(BUILD_CMAN_SUPPORT) BUILD_OCFS2CONSOLE= AC_ARG_ENABLE(ocfs2console, [ --enable-ocfs2console=[yes/no] Build GUI frontend [default=yes]],,enable_ocfs2console=yes) if test "x$enable_ocfs2console" = "xyes"; then dnl check for Python AM_PATH_PYTHON(2.3, have_python=yes, have_python=no) if test "x$have_python" = "xyes"; then AM_CHECK_PYTHON_HEADERS(have_pythondev=yes, have_pythondev=no) if test "x$have_pythondev" = "xyes"; then if $PYTHON -c 'import gobject' >/dev/null 2>&1; then BUILD_OCFS2CONSOLE=yes OCFS2_BLKID else AC_MSG_WARN([could not find PyGTK, ocfs2console will not be built]) fi else AC_MSG_WARN([could not find Python headers, ocfs2console will not be built]) fi else AC_MSG_WARN([could not find Python 2.3 or higher, ocfs2console will not be built]) fi fi AC_SUBST(BUILD_OCFS2CONSOLE) AC_CONFIG_FILES([ Config.make o2cb.pc o2dlm.pc ocfs2.pc ocfs2console/ocfs2interface/confdefs.py debugfs.ocfs2/debugfs.ocfs2.8 mkfs.ocfs2/mkfs.ocfs2.8 mounted.ocfs2/mounted.ocfs2.8 fsck.ocfs2/fsck.ocfs2.8 fsck.ocfs2/fsck.ocfs2.checks.8 mount.ocfs2/mount.ocfs2.8 o2cb_ctl/o2cb_ctl.8 ocfs2_hb_ctl/ocfs2_hb_ctl.8 ocfs2console/ocfs2console.8 tunefs.ocfs2/tunefs.ocfs2.8 o2image/o2image.8 o2info/o2info.1 libo2cb/o2cb.7 vendor/common/ocfs2-tools.spec-generic ]) AC_OUTPUT ./ocfs2-tools-1.6.4/install-sh0000775000176100017610000002143210673531132012767 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2004-01-12.10 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename= transform_arg= instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= usage="Usage: $0 [OPTION]... SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 -d DIRECTORIES... In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default. In the second, create the directory path DIR. Options: -b=TRANSFORMBASENAME -c copy source (using $cpprog) instead of moving (using $mvprog). -d create directories instead of installing files. -g GROUP $chgrp installed files to GROUP. -m MODE $chmod installed files to MODE. -o USER $chown installed files to USER. -s strip installed files (using $stripprog). -t=TRANSFORM --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; -c) instcmd=$cpprog shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit 0;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; --version) echo "$0 $scriptversion"; exit 0;; *) # When -d is used, all remaining arguments are directories to create. test -n "$dir_arg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then instcmd=: chmodcmd= else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift test -d "$pathcomp" || $mkdirprog "$pathcomp" pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $instcmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else # If we're going to rename the final executable, determine the name now. if test -z "$transformarg"; then dstfile=`basename "$dst"` else dstfile=`basename "$dst" $transformbasename \ | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename. test -z "$dstfile" && dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 trap '(exit $?); exit' 1 2 13 15 # Move or copy the file name to the temp name $doit $instcmd "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now remove or move aside any old file at destination location. We # try this two ways since rm can't unlink itself on some systems and # the destination file might be busy for other reasons. In this case, # the final cleanup might fail but the new file should still install # successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" fi || { (exit 1); exit; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ./ocfs2-tools-1.6.4/mkinstalldirs0000775000176100017610000000556111230177244013576 00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2003-11-08.23 # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit 0 ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit 0 ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac case $dirmode in '') if mkdir -p -- . 2>/dev/null; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. test -d ./-p && rmdir ./-p test -d ./-- && rmdir ./-- fi ;; *) if mkdir -m "$dirmode" -p -- . 2>/dev/null; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./-- "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ./ocfs2-tools-1.6.4/rpmarch.guess0000775000176100017610000000262210673531132013472 00000000000000#! /bin/sh mode="$1" srcdir="$2" host_cpu= QUERYFILE= if test -f /etc/redhat-release ; then QUERYFILE=/etc/redhat-release elif test -f /etc/SuSE-release ; then QUERYFILE=/etc/SuSE-release elif test -f /etc/UnitedLinux-release ; then QUERYFILE=/etc/UnitedLinux-release fi if test -n "$QUERYFILE"; then host_cpu="`rpm -qf $QUERYFILE --queryformat \"%{ARCH}\"`" fi if test -z "$host_cpu" -o "$host_cpu" = "noarch" ; then host_alias=`$srcdir/config.guess` host=`$srcdir/config.sub $host_alias` host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` fi case "$host_cpu" in x86_64|ia64|s390x) TOOLSARCH="" ;; i386|i486|i586|i686|i786|k6|k7) TOOLSARCH="i386" ;; ppc|ppc64|ppciseries|ppcpseries|ppc64iseries|ppc64pseries|powerpc|powerpc64) TOOLSARCH="ppc" ;; *) echo "rpmarch.guess: Warning: unknown RPM CPU architecture: $host_cpu" >&2 TOOLSARCH="" ;; esac # Only a few of these need to be overwritten from RPM's default case "$host_cpu" in i586) MODULEARCH="$host_cpu" ;; i386) MODULEARCH="i686" ;; *) MODULEARCH="" ;; esac case "$mode" in module) if [ -n "$MODULEARCH" ] ; then echo "--target $MODULEARCH" fi ;; tools) if [ -n "$TOOLSARCH" ] ; then echo "--target $TOOLSARCH" fi ;; *) echo "rpmarch.guess: Invalid mode: $mode" >&2 echo "error" exit 1 ;; esac exit 0 ./ocfs2-tools-1.6.4/svnrev.guess0000775000176100017610000001025610673531132013363 00000000000000#!/bin/sh # # This script creates a package version for packages. The package # version is the "release" or other version attached by the packaging # software (eg, RPM or Dpkg) after the upstream software version. # # This software must be invoked like so: # # svnrev.guess # # and it expects that release tags are of the form: # # /tags/- # # Note that release tag versioning expects a working connection to # the repository (for SVN log), but all other branches don't require it. # # If there is no .svn directory or it cannot discover the repository # version, the script sets a version of 0.local. # if [ $# -lt 1 ] then echo "Usage: svnrev.guess " >&2 exit 1 fi PACKAGE="$1" getstat() { if [ ! -d .svn ] then return fi svn stat -v | awk 'BEGIN{modified = "false";lastrev = 0} /Status against/{next} /^\?/{next} { col1=substr($0, 0, 1); if (col1 != " ") {modified = "true"} sub(/^......../, ""); if ($1 > lastrev) { lastrev=$1 } } END{print modified,lastrev}' } # # Branches that are not releases get a work-in-progress package version. # This is 0.[m]. The 0. ensures that an upcoming real # release, with an package version of 1, will supercede this package. # The "m" is added if the working tree has modifications to distinguish # it from a committed revision. # # If there is no repository or there is a problem getting the revision, # the package version is 0.local. # workingrev() { STATINFO="$(getstat)" MODIFIED=$(echo "$STATINFO" | cut -f1 -d" ") LASTREV=$(echo "$STATINFO" | cut -f2 -d" ") if [ -z "$LASTREV" ] then PKG_VERSION=0.local else PKG_VERSION=0.${LASTREV} if [ "$MODIFIED" = "true" ] then PKG_VERSION="${PKG_VERSION}m" fi fi echo "$PKG_VERSION" } # # If the branch is a tag (tags/project-x.y), it needs a release-based # package version (-1, -2, etc). Generally, it will be the tip of the # branch (package version 1). However, if there is a slight release # fixup, that warrants bumping the package version. # # The logic is pretty simple. Walk the history looking for the # creation of the tag (A /tags/project-x.y). For each revsion later # than the creation of the tag, bump the package version. # releaserev() { BRANCH="$1" BRANCH_SEARCH="`echo "$BRANCH" | sed -e 's/\//\\\\\//g'`" svn log -v 2>&1 | awk 'BEGIN{rev=0} /^r[0-9]+ \|/{rev += 1} /^ +A \/'"$BRANCH_SEARCH"'$/{exit} /^ +A \/'"$BRANCH_SEARCH"' (.*)$/{exit} END{print rev}' } # # Tag branches are releases, and need a release-style package version. # All other branches are non-release, and get an obviously # work-in-progress package version. # # guessbranch() expects the standard Subversion layout of # /trunk # /branches/ # /tags/ # guessbranch() { if [ ! -d .svn ] then return fi svn info | awk '/URL: .*\/trunk\/?$/{print "trunk"; exit 0} /URL: .*\/branches\/[^/]+\/?/{ gsub(/\/$/, "", $2); sub(/^.*\/branches\//, "", $2); print "branches/"$2; exit 0; } /URL: .*\/tags\/[^/]+\/?/{ gsub(/\/$/, "", $2); sub(/^.*\/tags\//, "", $2); print "tags/"$2; exit 0; }' } if ! which svn 1>/dev/null 2>&1 then echo "0.local" else BRANCH=$(guessbranch) case "$BRANCH" in tags/${PACKAGE}*) releaserev "$BRANCH" ;; *) workingrev ;; esac fi ./ocfs2-tools-1.6.4/Vendor.make0000664000176100017610000000034410673531131013055 00000000000000 # # This Makefile snippet is to be included in Makebo Makefiles that # use the mbvendor infrastructure # PKG_VERSION = $(shell $(TOPDIR)/svnrev.guess $(PACKAGE)) -include $(TOPDIR)/vendor/$(shell ./vendor.guess)/Vendor.make ./ocfs2-tools-1.6.4/vendor.guess0000775000176100017610000000104710673531132013333 00000000000000#!/bin/sh list_vendors() { ls -1 vendor | while read -r line do if [ "$line" = "common" ] then continue fi if [ ! -d "vendor/$line" ] then continue fi echo $line done # Make common last if [ -d "vendor/common" ] then echo "common" fi } list_vendors | while read -r v do if [ -x "vendor/${v}/vendor.guess" ] then if "vendor/${v}/vendor.guess" >/dev/null 2>&1 then echo "$v" fi fi done ./ocfs2-tools-1.6.4/o2cb.pc.in0000664000176100017610000000036510673531132012543 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: o2cb Description: Library for accessing the ocfs2 cluster base (o2cb) Version: @VERSION@ Requires: com_err Libs: -L${libdir} -lo2cb Cflags: -I${includedir} ./ocfs2-tools-1.6.4/o2dlm.pc.in0000644000176100017610000000036111115551036012722 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: o2dlm Description: Library for accessing the ocfs2 DLM Version: @VERSION@ Requires: com_err Libs: -L${libdir} -lo2dlm @DL_LIBS@ Cflags: -I${includedir} ./ocfs2-tools-1.6.4/ocfs2.pc.in0000664000176100017610000000034610673531132012731 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: ocfs2 Description: Userspace ocfs2 library Version: @VERSION@ Requires: o2dlm o2cb com_err Libs: -L${libdir} -locfs2 Cflags: -I${includedir} ./ocfs2-tools-1.6.4/include/0000775000176100017610000000000011515641640012466 500000000000000./ocfs2-tools-1.6.4/include/Makefile0000664000176100017610000000020711170734140014040 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make SUBDIRS = tools-internal ocfs2-kernel o2dlm o2cb ocfs2 include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/include/tools-internal/0000775000176100017610000000000011515641640015440 500000000000000./ocfs2-tools-1.6.4/include/tools-internal/Makefile0000664000176100017610000000021111506552637017021 00000000000000TOPDIR = ../.. include $(TOPDIR)/Preamble.make HFILES = verbose.h progress.h DIST_FILES = $(HFILES) include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/include/tools-internal/verbose.h0000664000176100017610000000456211170734140017200 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * verbose.h * * Internal verbose output functions. * * Copyright (C) 2008 Oracle. All rights reserved. * * 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. * * 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. */ #ifndef _INTERNAL_VERBOSE_H #define _INTERNAL_VERBOSE_H /* Verbosity levels for verbosef/errorf/tcom_err */ #define VL_FLAG_STDOUT 0x100 /* or'd with a level, output to stdout */ enum tools_verbosity_level { VL_CRIT = 0, /* Don't use this! I still haven't thought of anything so critical that -q should be ignored */ VL_ERR = 1, /* Error messages */ /* Regular output is the same level as errors */ #define VL_OUT (VL_ERR | VL_FLAG_STDOUT) VL_APP = 2, /* Verbose application status */ VL_LIB = 3, /* Status from shared code */ VL_DEBUG = 4, /* Debugging output */ }; /* Call this to set the program name */ void tools_setup_argv0(const char *argv0); /* Returns the program name from argv0 */ const char *tools_progname(void); /* Prints the tools version */ void tools_version(void); /* Increase and decrease the verbosity level */ void tools_verbose(void); void tools_quiet(void); /* Sets the process interactive */ void tools_interactive(void); /* Sets automatic answers for interactive questions */ void tools_interactive_yes(void); void tools_interactive_no(void); /* * Output that honors the verbosity level. tcom_err() is for errcode_t * errors. errorf() is for all other errors. verbosef() is for verbose * output. */ void verbosef(enum tools_verbosity_level level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); void errorf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void tcom_err(errcode_t code, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); int tools_interact(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int tools_interact_critical(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); #endif /* _INTERNAL_VERBOSE_H */ ./ocfs2-tools-1.6.4/include/tools-internal/progress.h0000664000176100017610000000606411170734140017376 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * progress.h * * Internal progress output functions. * * Copyright (C) 2008 Oracle. All rights reserved. * * 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. * * 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. */ #ifndef _INTERNAL_PROGRESS_H #define _INTERNAL_PROGRESS_H struct tools_progress; /* * Enables progress display. This is generally called when a program * is passed the '--progress' option. */ void tools_progress_enable(void); /* * Disable progress display. This is a true disable. Users do not need * to disable by hand when using verbosef() and friends for output. They * interact correctly with the progress display. */ void tools_progress_disable(void); /* * Callers should use the progress API unconditionally. If the progress * display is not enabled, the functions are no-ops. * * The progress bar can contain multiple progress displays. A toplevel * action may run a sub-action that takes time. Thus, the bar displays * both the progress state of the toplevel action and the sub-action. * * The sub-action can start its own progress display without knowledge * of the toplevel. The progress code understands how to handle it. */ /* * Start a new progress item. * * The long name should be no longer than 25 characters or so. The * short name really wants to be no more than 8. When displaying the * progress bar, the progress code sees if the long names of all * registered progress items can fit. If not, it will use the short * names, starting at the outermost progress item. If the short names * don't fit, it will truncate the short names. * * count is how many steps are required for completion of this progress * item. If count is non-zero, the progress bar will display a * completion percentage. If count is zero, the item is considered * unbounded, and the progress bar will display a simple spinner. * * A new progress item is returned. If NULL is returned, its because * there is no memory available. */ struct tools_progress *tools_progress_start(const char *long_name, const char *short_name, uint64_t count); /* * Increment the progress item. * * step is the number of steps to add to the completed count. This will * update the progress bar. As an optimization, the bar is changed at * most once every 1/8s. In addition, it will not be updated if the * completion percentage has not changed. */ void tools_progress_step(struct tools_progress *prog, unsigned int step); /* * Stop this progress item. This will free the item and remove it from the * progress bar. */ void tools_progress_stop(struct tools_progress *prog); #endif /* _INTERNAL_PROGRESS_H */ ./ocfs2-tools-1.6.4/include/ocfs2-kernel/0000775000176100017610000000000011515641640014760 500000000000000./ocfs2-tools-1.6.4/include/ocfs2-kernel/Makefile0000644000176100017610000000043311500500544016325 00000000000000TOPDIR = ../.. include $(TOPDIR)/Preamble.make HEADERS_SUBDIR = ocfs2-kernel HEADERS = \ kernel-list.h \ ocfs1_fs_compat.h \ ocfs2_fs.h \ ocfs2_ioctl.h \ ocfs2_lockid.h \ quota_tree.h \ sparse_endian_types.h DIST_FILES = $(HEADERS) include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/include/ocfs2-kernel/kernel-list.h0000644000176100017610000000514711115551035017301 00000000000000#ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = { &name, &name } #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) #if (!defined(__GNUC__) && !defined(__WATCOMC__)) #define __inline__ #endif /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_add(struct list_head * new, struct list_head * prev, struct list_head * next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /* * Insert a new entry after the specified head.. */ static __inline__ void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /* * Insert a new entry at the tail */ static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static __inline__ void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } static __inline__ int list_empty(struct list_head *head) { return head->next == head; } /* * Splice in "list" into "head" */ static __inline__ void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #endif ./ocfs2-tools-1.6.4/include/ocfs2-kernel/ocfs1_fs_compat.h0000644000176100017610000000565111115551035020116 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs1_fs_compat.h * * OCFS1 volume header definitions. OCFS2 creates valid but unmountable * OCFS1 volume headers on the first two sectors of an OCFS2 volume. * This allows an OCFS1 volume to see the partition and cleanly fail to * mount it. * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #ifndef _OCFS1_FS_COMPAT_H #define _OCFS1_FS_COMPAT_H #define OCFS1_MAX_VOL_SIGNATURE_LEN 128 #define OCFS1_MAX_MOUNT_POINT_LEN 128 #define OCFS1_MAX_VOL_ID_LENGTH 16 #define OCFS1_MAX_VOL_LABEL_LEN 64 #define OCFS1_MAX_CLUSTER_NAME_LEN 64 #define OCFS1_MAJOR_VERSION (2) #define OCFS1_MINOR_VERSION (0) #define OCFS1_VOLUME_SIGNATURE "OracleCFS" /* * OCFS1 superblock. Lives at sector 0. */ struct ocfs1_vol_disk_hdr { /*00*/ __u32 minor_version; __u32 major_version; /*08*/ __u8 signature[OCFS1_MAX_VOL_SIGNATURE_LEN]; /*88*/ __u8 mount_point[OCFS1_MAX_MOUNT_POINT_LEN]; /*108*/ __u64 serial_num; /*110*/ __u64 device_size; __u64 start_off; /*120*/ __u64 bitmap_off; __u64 publ_off; /*130*/ __u64 vote_off; __u64 root_bitmap_off; /*140*/ __u64 data_start_off; __u64 root_bitmap_size; /*150*/ __u64 root_off; __u64 root_size; /*160*/ __u64 cluster_size; __u64 num_nodes; /*170*/ __u64 num_clusters; __u64 dir_node_size; /*180*/ __u64 file_node_size; __u64 internal_off; /*190*/ __u64 node_cfg_off; __u64 node_cfg_size; /*1A0*/ __u64 new_cfg_off; __u32 prot_bits; __s32 excl_mount; /*1B0*/ }; struct ocfs1_disk_lock { /*00*/ __u32 curr_master; __u8 file_lock; __u8 compat_pad[3]; /* Not in orignal definition. Used to make the already existing alignment explicit */ __u64 last_write_time; /*10*/ __u64 last_read_time; __u32 writer_node_num; __u32 reader_node_num; /*20*/ __u64 oin_node_map; __u64 dlock_seq_num; /*30*/ }; /* * OCFS1 volume label. Lives at sector 1. */ struct ocfs1_vol_label { /*00*/ struct ocfs1_disk_lock disk_lock; /*30*/ __u8 label[OCFS1_MAX_VOL_LABEL_LEN]; /*70*/ __u16 label_len; /*72*/ __u8 vol_id[OCFS1_MAX_VOL_ID_LENGTH]; /*82*/ __u16 vol_id_len; /*84*/ __u8 cluster_name[OCFS1_MAX_CLUSTER_NAME_LEN]; /*A4*/ __u16 cluster_name_len; /*A6*/ }; #endif /* _OCFS1_FS_COMPAT_H */ ./ocfs2-tools-1.6.4/include/ocfs2-kernel/ocfs2_fs.h0000664000176100017610000014416111506552637016573 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2_fs.h * * On-disk structures for OCFS2. * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #ifndef _OCFS2_FS_H #define _OCFS2_FS_H /* Version */ #define OCFS2_MAJOR_REV_LEVEL 0 #define OCFS2_MINOR_REV_LEVEL 90 /* * An OCFS2 volume starts this way: * Sector 0: Valid ocfs1_vol_disk_hdr that cleanly fails to mount OCFS. * Sector 1: Valid ocfs1_vol_label that cleanly fails to mount OCFS. * Block OCFS2_SUPER_BLOCK_BLKNO: OCFS2 superblock. * * All other structures are found from the superblock information. * * OCFS2_SUPER_BLOCK_BLKNO is in blocks, not sectors. eg, for a * blocksize of 2K, it is 4096 bytes into disk. */ #define OCFS2_SUPER_BLOCK_BLKNO 2 /* * Cluster size limits. The maximum is kept arbitrarily at 1 MB, and could * grow if needed. */ #define OCFS2_MIN_CLUSTERSIZE 4096 #define OCFS2_MAX_CLUSTERSIZE 1048576 /* * Blocks cannot be bigger than clusters, so the maximum blocksize is the * minimum cluster size. */ #define OCFS2_MIN_BLOCKSIZE 512 #define OCFS2_MAX_BLOCKSIZE OCFS2_MIN_CLUSTERSIZE /* Filesystem magic number */ #define OCFS2_SUPER_MAGIC 0x7461636f /* Object signatures */ #define OCFS2_SUPER_BLOCK_SIGNATURE "OCFSV2" #define OCFS2_INODE_SIGNATURE "INODE01" #define OCFS2_EXTENT_BLOCK_SIGNATURE "EXBLK01" #define OCFS2_GROUP_DESC_SIGNATURE "GROUP01" #define OCFS2_XATTR_BLOCK_SIGNATURE "XATTR01" #define OCFS2_DIR_TRAILER_SIGNATURE "DIRTRL1" #define OCFS2_REFCOUNT_BLOCK_SIGNATURE "REFCNT1" #define OCFS2_DX_ROOT_SIGNATURE "DXDIR01" #define OCFS2_DX_LEAF_SIGNATURE "DXLEAF1" /* Compatibility flags */ #define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \ ( OCFS2_SB(sb)->s_feature_compat & (mask) ) #define OCFS2_HAS_RO_COMPAT_FEATURE(sb,mask) \ ( OCFS2_SB(sb)->s_feature_ro_compat & (mask) ) #define OCFS2_HAS_INCOMPAT_FEATURE(sb,mask) \ ( OCFS2_SB(sb)->s_feature_incompat & (mask) ) #define OCFS2_SET_COMPAT_FEATURE(sb,mask) \ OCFS2_SB(sb)->s_feature_compat |= (mask) #define OCFS2_SET_RO_COMPAT_FEATURE(sb,mask) \ OCFS2_SB(sb)->s_feature_ro_compat |= (mask) #define OCFS2_SET_INCOMPAT_FEATURE(sb,mask) \ OCFS2_SB(sb)->s_feature_incompat |= (mask) #define OCFS2_CLEAR_COMPAT_FEATURE(sb,mask) \ OCFS2_SB(sb)->s_feature_compat &= ~(mask) #define OCFS2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ OCFS2_SB(sb)->s_feature_ro_compat &= ~(mask) #define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ OCFS2_SB(sb)->s_feature_incompat &= ~(mask) #define OCFS2_FEATURE_COMPAT_SUPP (OCFS2_FEATURE_COMPAT_BACKUP_SB \ | OCFS2_FEATURE_COMPAT_JBD2_SB) #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \ | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \ | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ | OCFS2_FEATURE_INCOMPAT_META_ECC \ | OCFS2_FEATURE_INCOMPAT_XATTR \ | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \ | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \ | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG) #define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \ | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) /* * Heartbeat-only devices are missing journals and other files. The * filesystem driver can't load them, but the library can. Never put * this in OCFS2_FEATURE_INCOMPAT_SUPP, *ever*. */ #define OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV 0x0002 /* * tunefs sets this incompat flag before starting the resize and clears it * at the end. This flag protects users from inadvertently mounting the fs * after an aborted run without fsck-ing. */ #define OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG 0x0004 /* Used to denote a non-clustered volume */ #define OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT 0x0008 /* Support for sparse allocation in b-trees */ #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010 /* * Tunefs sets this incompat flag before starting an operation which * would require cleanup on abort. This is done to protect users from * inadvertently mounting the fs after an aborted run without * fsck-ing. * * s_tunefs_flags on the super block describes precisely which * operations were in progress. */ #define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG 0x0020 /* Support for data packed into inode blocks */ #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 /* * Support for alternate, userspace cluster stacks. If set, the superblock * field s_cluster_info contains a tag for the alternate stack in use as * well as the name of the cluster being joined. * mount.ocfs2 must pass in a matching stack name. * * If not set, the classic stack will be used. This is compatbile with * all older versions. */ #define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK 0x0080 /* Support for the extended slot map */ #define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100 /* Support for extended attributes */ #define OCFS2_FEATURE_INCOMPAT_XATTR 0x0200 /* Support for indexed directores */ #define OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS 0x0400 /* Metadata checksum and error correction */ #define OCFS2_FEATURE_INCOMPAT_META_ECC 0x0800 /* Refcount tree support */ #define OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE 0x1000 /* Discontigous block groups */ #define OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG 0x2000 /* * backup superblock flag is used to indicate that this volume * has backup superblocks. */ #define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001 /* * The filesystem will correctly handle journal feature bits. */ #define OCFS2_FEATURE_COMPAT_JBD2_SB 0x0002 /* * Unwritten extents support. */ #define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001 /* * Maintain quota information for this filesystem */ #define OCFS2_FEATURE_RO_COMPAT_USRQUOTA 0x0002 #define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA 0x0004 /* The byte offset of the first backup block will be 1G. * The following will be 4G, 16G, 64G, 256G and 1T. */ #define OCFS2_BACKUP_SB_START 1 << 30 /* the max backup superblock nums */ #define OCFS2_MAX_BACKUP_SUPERBLOCKS 6 /* * Flags on ocfs2_super_block.s_tunefs_flags */ #define OCFS2_TUNEFS_INPROG_REMOVE_SLOT 0x0001 /* Removing slots */ /* Adding directory block trailers */ #define OCFS2_TUNEFS_INPROG_DIR_TRAILER 0x0002 /* * Flags on ocfs2_dinode.i_flags */ #define OCFS2_VALID_FL (0x00000001) /* Inode is valid */ #define OCFS2_UNUSED2_FL (0x00000002) #define OCFS2_ORPHANED_FL (0x00000004) /* On the orphan list */ #define OCFS2_UNUSED3_FL (0x00000008) /* System inode flags */ #define OCFS2_SYSTEM_FL (0x00000010) /* System inode */ #define OCFS2_SUPER_BLOCK_FL (0x00000020) /* Super block */ #define OCFS2_LOCAL_ALLOC_FL (0x00000040) /* Slot local alloc bitmap */ #define OCFS2_BITMAP_FL (0x00000080) /* Allocation bitmap */ #define OCFS2_JOURNAL_FL (0x00000100) /* Slot local journal */ #define OCFS2_HEARTBEAT_FL (0x00000200) /* Heartbeat area */ #define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */ #define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */ #define OCFS2_QUOTA_FL (0x00001000) /* Quota file */ /* * Flags on ocfs2_dinode.i_dyn_features * * These can change much more often than i_flags. When adding flags, * keep in mind that i_dyn_features is only 16 bits wide. */ #define OCFS2_INLINE_DATA_FL (0x0001) /* Data stored in inode block */ #define OCFS2_HAS_XATTR_FL (0x0002) #define OCFS2_INLINE_XATTR_FL (0x0004) #define OCFS2_INDEXED_DIR_FL (0x0008) #define OCFS2_HAS_REFCOUNT_FL (0x0010) /* Inode attributes, keep in sync with EXT2 */ #define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ #define OCFS2_UNRM_FL (0x00000002) /* Undelete */ #define OCFS2_COMPR_FL (0x00000004) /* Compress file */ #define OCFS2_SYNC_FL (0x00000008) /* Synchronous updates */ #define OCFS2_IMMUTABLE_FL (0x00000010) /* Immutable file */ #define OCFS2_APPEND_FL (0x00000020) /* writes to file may only append */ #define OCFS2_NODUMP_FL (0x00000040) /* do not dump file */ #define OCFS2_NOATIME_FL (0x00000080) /* do not update atime */ #define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */ #define OCFS2_FL_VISIBLE (0x000100FF) /* User visible flags */ #define OCFS2_FL_MODIFIABLE (0x000100FF) /* User modifiable flags */ /* * Extent record flags (e_node.leaf.flags) */ #define OCFS2_EXT_UNWRITTEN (0x01) /* Extent is allocated but * unwritten */ #define OCFS2_EXT_REFCOUNTED (0x02) /* Extent is reference * counted in an associated * refcount tree */ /* * Journal Flags (ocfs2_dinode.id1.journal1.i_flags) */ #define OCFS2_JOURNAL_DIRTY_FL (0x00000001) /* Journal needs recovery */ /* * superblock s_state flags */ #define OCFS2_ERROR_FS (0x00000001) /* FS saw errors */ /* Limit of space in ocfs2_dir_entry */ #define OCFS2_MAX_FILENAME_LEN 255 /* Maximum slots on an ocfs2 file system */ #define OCFS2_MAX_SLOTS 255 /* Slot map indicator for an empty slot */ #define OCFS2_INVALID_SLOT -1 #define OCFS2_VOL_UUID_LEN 16 #define OCFS2_MAX_VOL_LABEL_LEN 64 /* The alternate, userspace stack fields */ #define OCFS2_STACK_LABEL_LEN 4 #define OCFS2_CLUSTER_NAME_LEN 16 /* Journal limits (in bytes) */ #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) /* * Default local alloc size (in megabytes) * * The value chosen should be such that most allocations, including new * block groups, use local alloc. */ #define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8 /* * Inline extended attribute size (in bytes) * The value chosen should be aligned to 16 byte boundaries. */ #define OCFS2_MIN_XATTR_INLINE_SIZE 256 struct ocfs2_system_inode_info { char *si_name; int si_iflags; int si_mode; }; /* System file index */ enum { BAD_BLOCK_SYSTEM_INODE = 0, GLOBAL_INODE_ALLOC_SYSTEM_INODE, SLOT_MAP_SYSTEM_INODE, #define OCFS2_FIRST_ONLINE_SYSTEM_INODE SLOT_MAP_SYSTEM_INODE HEARTBEAT_SYSTEM_INODE, GLOBAL_BITMAP_SYSTEM_INODE, USER_QUOTA_SYSTEM_INODE, GROUP_QUOTA_SYSTEM_INODE, #define OCFS2_LAST_GLOBAL_SYSTEM_INODE GROUP_QUOTA_SYSTEM_INODE ORPHAN_DIR_SYSTEM_INODE, EXTENT_ALLOC_SYSTEM_INODE, INODE_ALLOC_SYSTEM_INODE, JOURNAL_SYSTEM_INODE, LOCAL_ALLOC_SYSTEM_INODE, TRUNCATE_LOG_SYSTEM_INODE, LOCAL_USER_QUOTA_SYSTEM_INODE, LOCAL_GROUP_QUOTA_SYSTEM_INODE, NUM_SYSTEM_INODES }; static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = { /* Global system inodes (single copy) */ /* The first two are only used from userspace mfks/tunefs */ [BAD_BLOCK_SYSTEM_INODE] = { "bad_blocks", 0, S_IFREG | 0644 }, [GLOBAL_INODE_ALLOC_SYSTEM_INODE] = { "global_inode_alloc", OCFS2_BITMAP_FL | OCFS2_CHAIN_FL, S_IFREG | 0644 }, /* These are used by the running filesystem */ [SLOT_MAP_SYSTEM_INODE] = { "slot_map", 0, S_IFREG | 0644 }, [HEARTBEAT_SYSTEM_INODE] = { "heartbeat", OCFS2_HEARTBEAT_FL, S_IFREG | 0644 }, [GLOBAL_BITMAP_SYSTEM_INODE] = { "global_bitmap", 0, S_IFREG | 0644 }, [USER_QUOTA_SYSTEM_INODE] = { "aquota.user", OCFS2_QUOTA_FL, S_IFREG | 0644 }, [GROUP_QUOTA_SYSTEM_INODE] = { "aquota.group", OCFS2_QUOTA_FL, S_IFREG | 0644 }, /* Slot-specific system inodes (one copy per slot) */ [ORPHAN_DIR_SYSTEM_INODE] = { "orphan_dir:%04d", 0, S_IFDIR | 0755 }, [EXTENT_ALLOC_SYSTEM_INODE] = { "extent_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_CHAIN_FL, S_IFREG | 0644 }, [INODE_ALLOC_SYSTEM_INODE] = { "inode_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_CHAIN_FL, S_IFREG | 0644 }, [JOURNAL_SYSTEM_INODE] = { "journal:%04d", OCFS2_JOURNAL_FL, S_IFREG | 0644 }, [LOCAL_ALLOC_SYSTEM_INODE] = { "local_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_LOCAL_ALLOC_FL, S_IFREG | 0644 }, [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 }, [LOCAL_USER_QUOTA_SYSTEM_INODE] = { "aquota.user:%04d", OCFS2_QUOTA_FL, S_IFREG | 0644 }, [LOCAL_GROUP_QUOTA_SYSTEM_INODE] = { "aquota.group:%04d", OCFS2_QUOTA_FL, S_IFREG | 0644 }, }; /* Parameter passed from mount.ocfs2 to module */ #define OCFS2_HB_NONE "heartbeat=none" #define OCFS2_HB_LOCAL "heartbeat=local" /* * OCFS2 directory file types. Only the low 3 bits are used. The * other bits are reserved for now. */ #define OCFS2_FT_UNKNOWN 0 #define OCFS2_FT_REG_FILE 1 #define OCFS2_FT_DIR 2 #define OCFS2_FT_CHRDEV 3 #define OCFS2_FT_BLKDEV 4 #define OCFS2_FT_FIFO 5 #define OCFS2_FT_SOCK 6 #define OCFS2_FT_SYMLINK 7 #define OCFS2_FT_MAX 8 /* * OCFS2_DIR_PAD defines the directory entries boundaries * * NOTE: It must be a multiple of 4 */ #define OCFS2_DIR_PAD 4 #define OCFS2_DIR_ROUND (OCFS2_DIR_PAD - 1) #define OCFS2_DIR_MEMBER_LEN offsetof(struct ocfs2_dir_entry, name) #define OCFS2_DIR_REC_LEN(name_len) (((name_len) + OCFS2_DIR_MEMBER_LEN + \ OCFS2_DIR_ROUND) & \ ~OCFS2_DIR_ROUND) #define OCFS2_DIR_MIN_REC_LEN OCFS2_DIR_REC_LEN(1) #define OCFS2_LINK_MAX 32000 #define OCFS2_DX_LINK_MAX ((1U << 31) - 1U) #define OCFS2_LINKS_HI_SHIFT 16 #define S_SHIFT 12 static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = { [S_IFREG >> S_SHIFT] = OCFS2_FT_REG_FILE, [S_IFDIR >> S_SHIFT] = OCFS2_FT_DIR, [S_IFCHR >> S_SHIFT] = OCFS2_FT_CHRDEV, [S_IFBLK >> S_SHIFT] = OCFS2_FT_BLKDEV, [S_IFIFO >> S_SHIFT] = OCFS2_FT_FIFO, [S_IFSOCK >> S_SHIFT] = OCFS2_FT_SOCK, [S_IFLNK >> S_SHIFT] = OCFS2_FT_SYMLINK, }; /* * Convenience casts */ #define OCFS2_RAW_SB(dinode) (&((dinode)->id2.i_super)) /* * Block checking structure. This is used in metadata to validate the * contents. If OCFS2_FEATURE_INCOMPAT_META_ECC is not set, it is all * zeros. */ struct ocfs2_block_check { /*00*/ __le32 bc_crc32e; /* 802.3 Ethernet II CRC32 */ __le16 bc_ecc; /* Single-error-correction parity vector. This is a simple Hamming code dependant on the blocksize. OCFS2's maximum blocksize, 4K, requires 16 parity bits, so we fit in __le16. */ __le16 bc_reserved1; /*08*/ }; /* * On disk extent record for OCFS2 * It describes a range of clusters on disk. * * Length fields are divided into interior and leaf node versions. * This leaves room for a flags field (OCFS2_EXT_*) in the leaf nodes. */ struct ocfs2_extent_rec { /*00*/ __le32 e_cpos; /* Offset into the file, in clusters */ union { __le32 e_int_clusters; /* Clusters covered by all children */ struct { __le16 e_leaf_clusters; /* Clusters covered by this extent */ __u8 e_reserved1; __u8 e_flags; /* Extent flags */ }; }; __le64 e_blkno; /* Physical disk offset, in blocks */ /*10*/ }; struct ocfs2_chain_rec { __le32 c_free; /* Number of free bits in this chain. */ __le32 c_total; /* Number of total bits in this chain */ __le64 c_blkno; /* Physical disk offset (blocks) of 1st group */ }; struct ocfs2_truncate_rec { __le32 t_start; /* 1st cluster in this log */ __le32 t_clusters; /* Number of total clusters covered */ }; /* * On disk extent list for OCFS2 (node in the tree). Note that this * is contained inside ocfs2_dinode or ocfs2_extent_block, so the * offsets are relative to ocfs2_dinode.id2.i_list or * ocfs2_extent_block.h_list, respectively. */ struct ocfs2_extent_list { /*00*/ __le16 l_tree_depth; /* Extent tree depth from this point. 0 means data extents hang directly off this header (a leaf) NOTE: The high 8 bits cannot be used - tree_depth is never that big. */ __le16 l_count; /* Number of extent records */ __le16 l_next_free_rec; /* Next unused extent slot */ __le16 l_reserved1; __le64 l_reserved2; /* Pad to sizeof(ocfs2_extent_rec) */ /*10*/ struct ocfs2_extent_rec l_recs[0]; /* Extent records */ }; /* * On disk allocation chain list for OCFS2. Note that this is * contained inside ocfs2_dinode, so the offsets are relative to * ocfs2_dinode.id2.i_chain. */ struct ocfs2_chain_list { /*00*/ __le16 cl_cpg; /* Clusters per Block Group */ __le16 cl_bpc; /* Bits per cluster */ __le16 cl_count; /* Total chains in this list */ __le16 cl_next_free_rec; /* Next unused chain slot */ __le64 cl_reserved1; /*10*/ struct ocfs2_chain_rec cl_recs[0]; /* Chain records */ }; /* * On disk deallocation log for OCFS2. Note that this is * contained inside ocfs2_dinode, so the offsets are relative to * ocfs2_dinode.id2.i_dealloc. */ struct ocfs2_truncate_log { /*00*/ __le16 tl_count; /* Total records in this log */ __le16 tl_used; /* Number of records in use */ __le32 tl_reserved1; /*08*/ struct ocfs2_truncate_rec tl_recs[0]; /* Truncate records */ }; /* * On disk extent block (indirect block) for OCFS2 */ struct ocfs2_extent_block { /*00*/ __u8 h_signature[8]; /* Signature for verification */ struct ocfs2_block_check h_check; /* Error checking */ /*10*/ __le16 h_suballoc_slot; /* Slot suballocator this extent_header belongs to */ __le16 h_suballoc_bit; /* Bit offset in suballocator block group */ __le32 h_fs_generation; /* Must match super block */ __le64 h_blkno; /* Offset on disk, in blocks */ /*20*/ __le64 h_suballoc_loc; /* Suballocator block group this eb belongs to. Only valid if allocated from a discontiguous block group */ __le64 h_next_leaf_blk; /* Offset on disk, in blocks, of next leaf header pointing to data */ /*30*/ struct ocfs2_extent_list h_list; /* Extent record list */ /* Actual on-disk size is one block */ }; /* * On disk slot map for OCFS2. This defines the contents of the "slot_map" * system file. A slot is valid if it contains a node number >= 0. The * value -1 (0xFFFF) is OCFS2_INVALID_SLOT. This marks a slot empty. */ struct ocfs2_slot_map { /*00*/ __le16 sm_slots[0]; /* * Actual on-disk size is one block. OCFS2_MAX_SLOTS is 255, * 255 * sizeof(__le16) == 512B, within the 512B block minimum blocksize. */ }; struct ocfs2_extended_slot { /*00*/ __u8 es_valid; __u8 es_reserved1[3]; __le32 es_node_num; /*10*/ }; /* * The extended slot map, used when OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP * is set. It separates out the valid marker from the node number, and * has room to grow. Unlike the old slot map, this format is defined by * i_size. */ struct ocfs2_slot_map_extended { /*00*/ struct ocfs2_extended_slot se_slots[0]; /* * Actual size is i_size of the slot_map system file. It should * match s_max_slots * sizeof(struct ocfs2_extended_slot) */ }; struct ocfs2_cluster_info { /*00*/ __u8 ci_stack[OCFS2_STACK_LABEL_LEN]; __le32 ci_reserved; /*08*/ __u8 ci_cluster[OCFS2_CLUSTER_NAME_LEN]; /*18*/ }; /* * On disk superblock for OCFS2 * Note that it is contained inside an ocfs2_dinode, so all offsets * are relative to the start of ocfs2_dinode.id2. */ struct ocfs2_super_block { /*00*/ __le16 s_major_rev_level; __le16 s_minor_rev_level; __le16 s_mnt_count; __le16 s_max_mnt_count; __le16 s_state; /* File system state */ __le16 s_errors; /* Behaviour when detecting errors */ __le32 s_checkinterval; /* Max time between checks */ /*10*/ __le64 s_lastcheck; /* Time of last check */ __le32 s_creator_os; /* OS */ __le32 s_feature_compat; /* Compatible feature set */ /*20*/ __le32 s_feature_incompat; /* Incompatible feature set */ __le32 s_feature_ro_compat; /* Readonly-compatible feature set */ __le64 s_root_blkno; /* Offset, in blocks, of root directory dinode */ /*30*/ __le64 s_system_dir_blkno; /* Offset, in blocks, of system directory dinode */ __le32 s_blocksize_bits; /* Blocksize for this fs */ __le32 s_clustersize_bits; /* Clustersize for this fs */ /*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts before tunefs required */ __le16 s_tunefs_flag; __le32 s_uuid_hash; /* hash value of uuid */ __le64 s_first_cluster_group; /* Block offset of 1st cluster * group header */ /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ /*90*/ __u8 s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */ /*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Selected userspace stack. Only valid with INCOMPAT flag. */ /*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size for this fs*/ __le16 s_reserved0; __le32 s_dx_seed[3]; /* seed[0-2] for dx dir hash. * s_uuid_hash serves as seed[3]. */ /*C0*/ __le64 s_reserved2[15]; /* Fill out superblock */ /*140*/ /* * NOTE: As stated above, all offsets are relative to * ocfs2_dinode.id2, which is at 0xC0 in the inode. * 0xC0 + 0x140 = 0x200 or 512 bytes. A superblock must fit within * our smallest blocksize, which is 512 bytes. To ensure this, * we reserve the space in s_reserved2. Anything past s_reserved2 * will not be available on the smallest blocksize. */ }; /* * Local allocation bitmap for OCFS2 slots * Note that it exists inside an ocfs2_dinode, so all offsets are * relative to the start of ocfs2_dinode.id2. */ struct ocfs2_local_alloc { /*00*/ __le32 la_bm_off; /* Starting bit offset in main bitmap */ __le16 la_size; /* Size of included bitmap, in bytes */ __le16 la_reserved1; __le64 la_reserved2; /*10*/ __u8 la_bitmap[0]; }; /* * Data-in-inode header. This is only used if i_dyn_features has * OCFS2_INLINE_DATA_FL set. */ struct ocfs2_inline_data { /*00*/ __le16 id_count; /* Number of bytes that can be used * for data, starting at id_data */ __le16 id_reserved0; __le32 id_reserved1; __u8 id_data[0]; /* Start of user data */ }; /* * On disk inode for OCFS2 */ struct ocfs2_dinode { /*00*/ __u8 i_signature[8]; /* Signature for validation */ __le32 i_generation; /* Generation number */ __le16 i_suballoc_slot; /* Slot suballocator this inode belongs to */ __le16 i_suballoc_bit; /* Bit offset in suballocator block group */ /*10*/ __le16 i_links_count_hi; /* High 16 bits of links count */ __le16 i_xattr_inline_size; __le32 i_clusters; /* Cluster count */ __le32 i_uid; /* Owner UID */ __le32 i_gid; /* Owning GID */ /*20*/ __le64 i_size; /* Size in bytes */ __le16 i_mode; /* File mode */ __le16 i_links_count; /* Links count */ __le32 i_flags; /* File flags */ /*30*/ __le64 i_atime; /* Access time */ __le64 i_ctime; /* Creation time */ /*40*/ __le64 i_mtime; /* Modification time */ __le64 i_dtime; /* Deletion time */ /*50*/ __le64 i_blkno; /* Offset on disk, in blocks */ __le64 i_last_eb_blk; /* Pointer to last extent block */ /*60*/ __le32 i_fs_generation; /* Generation per fs-instance */ __le32 i_atime_nsec; __le32 i_ctime_nsec; __le32 i_mtime_nsec; /*70*/ __le32 i_attr; __le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL was set in i_flags */ __le16 i_dyn_features; __le64 i_xattr_loc; /*80*/ struct ocfs2_block_check i_check; /* Error checking */ __le64 i_dx_root; /*90*/ __le64 i_refcount_loc; __le64 i_suballoc_loc; /* Suballocator block group this inode belongs to. Only valid if allocated from a discontiguous block group */ /*A0*/ __le64 i_reserved2[3]; /*B8*/ union { __le64 i_pad1; /* Generic way to refer to this 64bit union */ struct { __le64 i_rdev; /* Device number */ } dev1; struct { /* Info for bitmap system inodes */ __le32 i_used; /* Bits (ie, clusters) used */ __le32 i_total; /* Total bits (clusters) available */ } bitmap1; struct { /* Info for journal system inodes */ __le32 ij_flags; /* Mounted, version, etc. */ __le32 ij_recovery_generation; /* Incremented when the journal is recovered after an unclean shutdown */ } journal1; } id1; /* Inode type dependant 1 */ /*C0*/ union { struct ocfs2_super_block i_super; struct ocfs2_local_alloc i_lab; struct ocfs2_chain_list i_chain; struct ocfs2_extent_list i_list; struct ocfs2_truncate_log i_dealloc; struct ocfs2_inline_data i_data; __u8 i_symlink[0]; } id2; /* Actual on-disk size is one block */ }; /* * On-disk directory entry structure for OCFS2 * * Packed as this structure could be accessed unaligned on 64-bit platforms */ struct ocfs2_dir_entry { /*00*/ __le64 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __u8 name_len; /* Name length */ __u8 file_type; /*0C*/ char name[OCFS2_MAX_FILENAME_LEN]; /* File name */ /* Actual on-disk length specified by rec_len */ } __attribute__ ((packed)); /* * Per-block record for the unindexed directory btree. This is carefully * crafted so that the rec_len and name_len records of an ocfs2_dir_entry are * mirrored. That way, the directory manipulation code needs a minimal amount * of update. * * NOTE: Keep this structure aligned to a multiple of 4 bytes. */ struct ocfs2_dir_block_trailer { /*00*/ __le64 db_compat_inode; /* Always zero. Was inode */ __le16 db_compat_rec_len; /* Backwards compatible with * ocfs2_dir_entry. */ __u8 db_compat_name_len; /* Always zero. Was name_len */ __u8 db_reserved0; __le16 db_reserved1; __le16 db_free_rec_len; /* Size of largest empty hole * in this block. (unused) */ /*10*/ __u8 db_signature[8]; /* Signature for verification */ __le64 db_reserved2; __le64 db_free_next; /* Next block in list (unused) */ /*20*/ __le64 db_blkno; /* Offset on disk, in blocks */ __le64 db_parent_dinode; /* dinode which owns me, in blocks */ /*30*/ struct ocfs2_block_check db_check; /* Error checking */ /*40*/ }; /* * A directory entry in the indexed tree. We don't store the full name here, * but instead provide a pointer to the full dirent in the unindexed tree. * * We also store name_len here so as to reduce the number of leaf blocks we * need to search in case of collisions. */ struct ocfs2_dx_entry { __le32 dx_major_hash; /* Used to find logical * cluster in index */ __le32 dx_minor_hash; /* Lower bits used to find * block in cluster */ __le64 dx_dirent_blk; /* Physical block in unindexed * tree holding this dirent. */ }; struct ocfs2_dx_entry_list { __le32 de_reserved; __le16 de_count; /* Maximum number of entries * possible in de_entries */ __le16 de_num_used; /* Current number of * de_entries entries */ struct ocfs2_dx_entry de_entries[0]; /* Indexed dir entries * in a packed array of * length de_num_used */ }; #define OCFS2_DX_FLAG_INLINE 0x01 /* * A directory indexing block. Each indexed directory has one of these, * pointed to by ocfs2_dinode. * * This block stores an indexed btree root, and a set of free space * start-of-list pointers. */ struct ocfs2_dx_root_block { __u8 dr_signature[8]; /* Signature for verification */ struct ocfs2_block_check dr_check; /* Error checking */ __le16 dr_suballoc_slot; /* Slot suballocator this * block belongs to. */ __le16 dr_suballoc_bit; /* Bit offset in suballocator * block group */ __le32 dr_fs_generation; /* Must match super block */ __le64 dr_blkno; /* Offset on disk, in blocks */ __le64 dr_last_eb_blk; /* Pointer to last * extent block */ __le32 dr_clusters; /* Clusters allocated * to the indexed tree. */ __u8 dr_flags; /* OCFS2_DX_FLAG_* flags */ __u8 dr_reserved0; __le16 dr_reserved1; __le64 dr_dir_blkno; /* Pointer to parent inode */ __le32 dr_num_entries; /* Total number of * names stored in * this directory.*/ __le32 dr_reserved2; __le64 dr_free_blk; /* Pointer to head of free * unindexed block list. */ __le64 dr_suballoc_loc; /* Suballocator block group * this root belongs to. * Only valid if allocated * from a discontiguous * block group. */ __le64 dr_reserved3[14]; union { struct ocfs2_extent_list dr_list; /* Keep this aligned to 128 * bits for maximum space * efficiency. */ struct ocfs2_dx_entry_list dr_entries; /* In-root-block list of * entries. We grow out * to extents if this * gets too big. */ }; }; /* * The header of a leaf block in the indexed tree. */ struct ocfs2_dx_leaf { __u8 dl_signature[8];/* Signature for verification */ struct ocfs2_block_check dl_check; /* Error checking */ __le64 dl_blkno; /* Offset on disk, in blocks */ __le32 dl_fs_generation;/* Must match super block */ __le32 dl_reserved0; __le64 dl_reserved1; struct ocfs2_dx_entry_list dl_list; }; /* * Largest bitmap for a block (suballocator) group in bytes. This limit * does not affect cluster groups (global allocator). Cluster group * bitmaps run to the end of the block. */ #define OCFS2_MAX_BG_BITMAP_SIZE 256 /* * On disk allocator group structure for OCFS2 */ struct ocfs2_group_desc { /*00*/ __u8 bg_signature[8]; /* Signature for validation */ __le16 bg_size; /* Size of included bitmap in bytes. */ __le16 bg_bits; /* Bits represented by this group. */ __le16 bg_free_bits_count; /* Free bits count */ __le16 bg_chain; /* What chain I am in. */ /*10*/ __le32 bg_generation; __le32 bg_reserved1; __le64 bg_next_group; /* Next group in my list, in blocks */ /*20*/ __le64 bg_parent_dinode; /* dinode which owns me, in blocks */ __le64 bg_blkno; /* Offset on disk, in blocks */ /*30*/ struct ocfs2_block_check bg_check; /* Error checking */ __le64 bg_reserved2; /*40*/ union { __u8 bg_bitmap[0]; struct { /* * Block groups may be discontiguous when * OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG is set. * The extents of a discontigous block group are * stored in bg_list. It is a flat list. * l_tree_depth must always be zero. A * discontiguous group is signified by a non-zero * bg_list->l_next_free_rec. Only block groups * can be discontiguous; Cluster groups cannot. * We've never made a block group with more than * 2048 blocks (256 bytes of bg_bitmap). This * codifies that limit so that we can fit bg_list. * bg_size of a discontiguous block group will * be 256 to match bg_bitmap_filler. */ __u8 bg_bitmap_filler[OCFS2_MAX_BG_BITMAP_SIZE]; /*140*/ struct ocfs2_extent_list bg_list; }; }; /* Actual on-disk size is one block */ }; struct ocfs2_refcount_rec { /*00*/ __le64 r_cpos; /* Physical offset, in clusters */ __le32 r_clusters; /* Clusters covered by this extent */ __le32 r_refcount; /* Reference count of this extent */ /*10*/ }; #define OCFS2_32BIT_POS_MASK (0xffffffffULL) #define OCFS2_REFCOUNT_LEAF_FL (0x00000001) #define OCFS2_REFCOUNT_TREE_FL (0x00000002) struct ocfs2_refcount_list { /*00*/ __le16 rl_count; /* Maximum number of entries possible in rl_records */ __le16 rl_used; /* Current number of used records */ __le32 rl_reserved2; __le64 rl_reserved1; /* Pad to sizeof(ocfs2_refcount_record) */ /*10*/ struct ocfs2_refcount_rec rl_recs[0]; /* Refcount records */ }; struct ocfs2_refcount_block { /*00*/ __u8 rf_signature[8]; /* Signature for verification */ __le16 rf_suballoc_slot; /* Slot suballocator this block belongs to */ __le16 rf_suballoc_bit; /* Bit offset in suballocator block group */ __le32 rf_fs_generation; /* Must match superblock */ /*10*/ __le64 rf_blkno; /* Offset on disk, in blocks */ __le64 rf_parent; /* Parent block, only valid if OCFS2_REFCOUNT_LEAF_FL is set in rf_flags */ /*20*/ struct ocfs2_block_check rf_check; /* Error checking */ __le64 rf_last_eb_blk; /* Pointer to last extent block */ /*30*/ __le32 rf_count; /* Number of inodes sharing this refcount tree */ __le32 rf_flags; /* See the flags above */ __le32 rf_clusters; /* clusters covered by refcount tree. */ __le32 rf_cpos; /* cluster offset in refcount tree.*/ /*40*/ __le32 rf_generation; /* generation number. all be the same * for the same refcount tree. */ __le32 rf_reserved0; __le64 rf_suballoc_loc; /* Suballocator block group this refcount block belongs to. Only valid if allocated from a discontiguous block group */ /*50*/ __le64 rf_reserved1[6]; /*80*/ union { struct ocfs2_refcount_list rf_records; /* List of refcount records */ struct ocfs2_extent_list rf_list; /* Extent record list, only valid if OCFS2_REFCOUNT_TREE_FL is set in rf_flags */ }; /* Actual on-disk size is one block */ }; /* * On disk extended attribute structure for OCFS2. */ /* * ocfs2_xattr_entry indicates one extend attribute. * * Note that it can be stored in inode, one block or one xattr bucket. */ struct ocfs2_xattr_entry { __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */ __le16 xe_name_offset; /* byte offset from the 1st entry in the local xattr storage(inode, xattr block or xattr bucket). */ __u8 xe_name_len; /* xattr name len, does't include prefix. */ __u8 xe_type; /* the low 7 bits indicate the name prefix * type and the highest bit indicates whether * the EA is stored in the local storage. */ __le64 xe_value_size; /* real xattr value length. */ }; /* * On disk structure for xattr header. * * One ocfs2_xattr_header describes how many ocfs2_xattr_entry records in * the local xattr storage. */ struct ocfs2_xattr_header { __le16 xh_count; /* contains the count of how many records are in the local xattr storage. */ __le16 xh_free_start; /* current offset for storing xattr. */ __le16 xh_name_value_len; /* total length of name/value length in this bucket. */ __le16 xh_num_buckets; /* Number of xattr buckets in this extent record, only valid in the first bucket. */ struct ocfs2_block_check xh_check; /* Error checking (Note, this is only used for xattr buckets. A block uses xb_check and sets this field to zero.) */ struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */ }; /* * On disk structure for xattr value root. * * When an xattr's value is large enough, it is stored in an external * b-tree like file data. The xattr value root points to this structure. */ struct ocfs2_xattr_value_root { /*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */ __le32 xr_reserved0; __le64 xr_last_eb_blk; /* Pointer to last extent block */ /*10*/ struct ocfs2_extent_list xr_list; /* Extent record list */ }; /* * On disk structure for xattr tree root. * * It is used when there are too many extended attributes for one file. These * attributes will be organized and stored in an indexed-btree. */ struct ocfs2_xattr_tree_root { /*00*/ __le32 xt_clusters; /* clusters covered by xattr. */ __le32 xt_reserved0; __le64 xt_last_eb_blk; /* Pointer to last extent block */ /*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */ }; #define OCFS2_XATTR_INDEXED 0x1 #define OCFS2_HASH_SHIFT 5 #define OCFS2_XATTR_ROUND 3 #define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \ ~(OCFS2_XATTR_ROUND)) #define OCFS2_XATTR_INLINE_SIZE 80 #define OCFS2_XATTR_BUCKET_SIZE 4096 #define OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET (OCFS2_XATTR_BUCKET_SIZE \ / OCFS2_MIN_BLOCKSIZE) /* * On disk structure for xattr block. */ struct ocfs2_xattr_block { /*00*/ __u8 xb_signature[8]; /* Signature for verification */ __le16 xb_suballoc_slot; /* Slot suballocator this block belongs to. */ __le16 xb_suballoc_bit; /* Bit offset in suballocator block group */ __le32 xb_fs_generation; /* Must match super block */ /*10*/ __le64 xb_blkno; /* Offset on disk, in blocks */ struct ocfs2_block_check xb_check; /* Error checking */ /*20*/ __le16 xb_flags; /* Indicates whether this block contains real xattr or a xattr tree. */ __le16 xb_reserved0; __le32 xb_reserved1; __le64 xb_suballoc_loc; /* Suballocator block group this xattr block belongs to. Only valid if allocated from a discontiguous block group */ /*30*/ union { struct ocfs2_xattr_header xb_header; /* xattr header if this block contains xattr */ struct ocfs2_xattr_tree_root xb_root;/* xattr tree root if this block cotains xattr tree. */ } xb_attrs; }; #define OCFS2_XATTR_ENTRY_LOCAL 0x80 #define OCFS2_XATTR_TYPE_MASK 0x7F static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe, int local) { if (local) xe->xe_type |= OCFS2_XATTR_ENTRY_LOCAL; else xe->xe_type &= ~OCFS2_XATTR_ENTRY_LOCAL; } static inline int ocfs2_xattr_is_local(struct ocfs2_xattr_entry *xe) { return xe->xe_type & OCFS2_XATTR_ENTRY_LOCAL; } static inline void ocfs2_xattr_set_type(struct ocfs2_xattr_entry *xe, int type) { xe->xe_type |= type & OCFS2_XATTR_TYPE_MASK; } static inline int ocfs2_xattr_get_type(struct ocfs2_xattr_entry *xe) { return xe->xe_type & OCFS2_XATTR_TYPE_MASK; } /* * On disk structures for global quota file */ /* Magic numbers and known versions for global quota files */ #define OCFS2_GLOBAL_QMAGICS {\ 0x0cf52470, /* USRQUOTA */ \ 0x0cf52471 /* GRPQUOTA */ \ } #define OCFS2_GLOBAL_QVERSIONS {\ 0, \ 0, \ } /* Each block of each quota file has a certain fixed number of bytes reserved * for OCFS2 internal use at its end. OCFS2 can use it for things like * checksums, etc. */ #define OCFS2_QBLK_RESERVED_SPACE 8 /* Generic header of all quota files */ struct ocfs2_disk_dqheader { __le32 dqh_magic; /* Magic number identifying file */ __le32 dqh_version; /* Quota format version */ }; #define OCFS2_GLOBAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader)) /* Information header of global quota file (immediately follows the generic * header) */ struct ocfs2_global_disk_dqinfo { /*00*/ __le32 dqi_bgrace; /* Grace time for space softlimit excess */ __le32 dqi_igrace; /* Grace time for inode softlimit excess */ __le32 dqi_syncms; /* Time after which we sync local changes to * global quota file */ __le32 dqi_blocks; /* Number of blocks in quota file */ /*10*/ __le32 dqi_free_blk; /* First free block in quota file */ __le32 dqi_free_entry; /* First block with free dquot entry in quota * file */ }; /* Structure with global user / group information. We reserve some space * for future use. */ struct ocfs2_global_disk_dqblk { /*00*/ __le32 dqb_id; /* ID the structure belongs to */ __le32 dqb_use_count; /* Number of nodes having reference to this structure */ __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ /*10*/ __le64 dqb_isoftlimit; /* preferred inode limit */ __le64 dqb_curinodes; /* current # allocated inodes */ /*20*/ __le64 dqb_bhardlimit; /* absolute limit on disk space */ __le64 dqb_bsoftlimit; /* preferred limit on disk space */ /*30*/ __le64 dqb_curspace; /* current space occupied */ __le64 dqb_btime; /* time limit for excessive disk use */ /*40*/ __le64 dqb_itime; /* time limit for excessive inode use */ __le64 dqb_pad1; /*50*/ __le64 dqb_pad2; }; /* * On-disk structures for local quota file */ /* Magic numbers and known versions for local quota files */ #define OCFS2_LOCAL_QMAGICS {\ 0x0cf524c0, /* USRQUOTA */ \ 0x0cf524c1 /* GRPQUOTA */ \ } #define OCFS2_LOCAL_QVERSIONS {\ 0, \ 0, \ } /* Quota flags in dqinfo header */ #define OLQF_CLEAN 0x0001 /* Quota file is empty (this should be after\ * quota has been cleanly turned off) */ #define OCFS2_LOCAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader)) /* Information header of local quota file (immediately follows the generic * header) */ struct ocfs2_local_disk_dqinfo { __le32 dqi_flags; /* Flags for quota file */ __le32 dqi_chunks; /* Number of chunks of quota structures * with a bitmap */ __le32 dqi_blocks; /* Number of blocks allocated for quota file */ }; /* Header of one chunk of a quota file */ struct ocfs2_local_disk_chunk { __le32 dqc_free; /* Number of free entries in the bitmap */ __u8 dqc_bitmap[0]; /* Bitmap of entries in the corresponding * chunk of quota file */ }; /* One entry in local quota file */ struct ocfs2_local_disk_dqblk { /*00*/ __le64 dqb_id; /* id this quota applies to */ __le64 dqb_spacemod; /* Change in the amount of used space */ /*10*/ __le64 dqb_inodemod; /* Change in the amount of used inodes */ }; /* * The quota trailer lives at the end of each quota block. */ struct ocfs2_disk_dqtrailer { /*00*/ struct ocfs2_block_check dq_check; /* Error checking */ /*08*/ /* Cannot be larger than OCFS2_QBLK_RESERVED_SPACE */ }; static inline struct ocfs2_disk_dqtrailer *ocfs2_block_dqtrailer(int blocksize, void *buf) { char *ptr = buf; ptr += blocksize - OCFS2_QBLK_RESERVED_SPACE; return (struct ocfs2_disk_dqtrailer *)ptr; } #ifdef __KERNEL__ static inline int ocfs2_fast_symlink_chars(struct super_block *sb) { return sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink); } static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb, struct ocfs2_dinode *di) { unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size); if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL) return sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data) - xattrsize; else return sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data); } static inline int ocfs2_extent_recs_per_inode(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_extent_recs_per_inode_with_xattr( struct super_block *sb, struct ocfs2_dinode *di) { int size; unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size); if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL) size = sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_list.l_recs) - xattrsize; else size = sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_extent_recs_per_dx_root(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_dx_root_block, dr_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_chain_recs_per_inode(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_chain.cl_recs); return size / sizeof(struct ocfs2_chain_rec); } static inline u16 ocfs2_extent_recs_per_eb(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_extent_block, h_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline u16 ocfs2_extent_recs_per_gd(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_group_desc, bg_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_dx_entries_per_leaf(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_dx_leaf, dl_list.de_entries); return size / sizeof(struct ocfs2_dx_entry); } static inline int ocfs2_dx_entries_per_root(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_dx_root_block, dr_entries.de_entries); return size / sizeof(struct ocfs2_dx_entry); } static inline u16 ocfs2_local_alloc_size(struct super_block *sb) { u16 size; size = sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); return size; } static inline int ocfs2_group_bitmap_size(struct super_block *sb, int suballocator, u32 feature_incompat) { int size = sb->s_blocksize - offsetof(struct ocfs2_group_desc, bg_bitmap); /* * The cluster allocator uses the entire block. Suballocators have * never used more than OCFS2_MAX_BG_BITMAP_SIZE. Unfortunately, older * code expects bg_size set to the maximum. Thus we must keep * bg_size as-is unless discontig_bg is enabled. */ if (suballocator && (feature_incompat & OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG)) size = OCFS2_MAX_BG_BITMAP_SIZE; return size; } static inline int ocfs2_truncate_recs_per_inode(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_dinode, id2.i_dealloc.tl_recs); return size / sizeof(struct ocfs2_truncate_rec); } static inline u64 ocfs2_backup_super_blkno(struct super_block *sb, int index) { u64 offset = OCFS2_BACKUP_SB_START; if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) { offset <<= (2 * index); offset >>= sb->s_blocksize_bits; return offset; } return 0; } static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_xattr_block, xb_attrs.xb_root.xt_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline u16 ocfs2_extent_recs_per_rb(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_refcount_block, rf_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline u16 ocfs2_refcount_recs_per_rb(struct super_block *sb) { int size; size = sb->s_blocksize - offsetof(struct ocfs2_refcount_block, rf_records.rl_recs); return size / sizeof(struct ocfs2_refcount_rec); } static inline u32 ocfs2_get_ref_rec_low_cpos(const struct ocfs2_refcount_rec *rec) { return le64_to_cpu(rec->r_cpos) & OCFS2_32BIT_POS_MASK; } #else static inline int ocfs2_fast_symlink_chars(int blocksize) { return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink); } static inline int ocfs2_max_inline_data_with_xattr(int blocksize, struct ocfs2_dinode *di) { if (di && (di->i_dyn_features & OCFS2_INLINE_XATTR_FL)) return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data) - di->i_xattr_inline_size; else return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data); } static inline int ocfs2_extent_recs_per_inode(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dinode, id2.i_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_chain_recs_per_inode(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dinode, id2.i_chain.cl_recs); return size / sizeof(struct ocfs2_chain_rec); } static inline int ocfs2_extent_recs_per_eb(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_extent_block, h_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_extent_recs_per_gd(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_group_desc, bg_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_dx_entries_per_leaf(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dx_leaf, dl_list.de_entries); return size / sizeof(struct ocfs2_dx_entry); } static inline int ocfs2_dx_entries_per_root(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dx_root_block, dr_entries.de_entries); return size / sizeof(struct ocfs2_dx_entry); } static inline int ocfs2_extent_recs_per_dx_root(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dx_root_block, dr_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_local_alloc_size(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); return size; } static inline int ocfs2_group_bitmap_size(int blocksize, int suballocator, uint32_t feature_incompat) { int size = blocksize - offsetof(struct ocfs2_group_desc, bg_bitmap); /* * The cluster allocator uses the entire block. Suballocators have * never used more than OCFS2_MAX_BG_BITMAP_SIZE. Unfortunately, older * code expects bg_size set to the maximum. Thus we must keep * bg_size as-is unless discontig_bg is enabled. */ if (suballocator && (feature_incompat & OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG)) size = OCFS2_MAX_BG_BITMAP_SIZE; return size; } static inline int ocfs2_truncate_recs_per_inode(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_dinode, id2.i_dealloc.tl_recs); return size / sizeof(struct ocfs2_truncate_rec); } static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index) { uint64_t offset = OCFS2_BACKUP_SB_START; if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) { offset <<= (2 * index); offset /= blocksize; return offset; } return 0; } static inline int ocfs2_xattr_recs_per_xb(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_xattr_block, xb_attrs.xb_root.xt_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_extent_recs_per_rb(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_refcount_block, rf_list.l_recs); return size / sizeof(struct ocfs2_extent_rec); } static inline int ocfs2_refcount_recs_per_rb(int blocksize) { int size; size = blocksize - offsetof(struct ocfs2_refcount_block, rf_records.rl_recs); return size / sizeof(struct ocfs2_refcount_rec); } static inline uint32_t ocfs2_get_ref_rec_low_cpos(const struct ocfs2_refcount_rec *rec) { return rec->r_cpos & OCFS2_32BIT_POS_MASK; } #endif /* __KERNEL__ */ static inline int ocfs2_system_inode_is_global(int type) { return ((type >= 0) && (type <= OCFS2_LAST_GLOBAL_SYSTEM_INODE)); } static inline int ocfs2_sprintf_system_inode_name(char *buf, int len, int type, int slot) { int chars; /* * Global system inodes can only have one copy. Everything * after OCFS2_LAST_GLOBAL_SYSTEM_INODE in the system inode * list has a copy per slot. */ if (type <= OCFS2_LAST_GLOBAL_SYSTEM_INODE) chars = snprintf(buf, len, "%s", ocfs2_system_inodes[type].si_name); else chars = snprintf(buf, len, ocfs2_system_inodes[type].si_name, slot); return chars; } static inline void ocfs2_set_de_type(struct ocfs2_dir_entry *de, umode_t mode) { de->file_type = ocfs2_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; } static inline int ocfs2_gd_is_discontig(struct ocfs2_group_desc *gd) { if ((offsetof(struct ocfs2_group_desc, bg_bitmap) + gd->bg_size) != offsetof(struct ocfs2_group_desc, bg_list)) return 0; /* * Only valid to check l_next_free_rec if * bg_bitmap + bg_size == bg_list */ if (!gd->bg_list.l_next_free_rec) return 0; return 1; } #endif /* _OCFS2_FS_H */ ./ocfs2-tools-1.6.4/include/ocfs2-kernel/ocfs2_ioctl.h0000644000176100017610000001166311500500544017253 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2_ioctl.h * * Defines OCFS2 ioctls. * * Copyright (C) 2010 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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. */ #ifndef OCFS2_IOCTL_H #define OCFS2_IOCTL_H /* * ioctl commands */ #define OCFS2_IOC_GETFLAGS _IOR('f', 1, long) #define OCFS2_IOC_SETFLAGS _IOW('f', 2, long) #define OCFS2_IOC32_GETFLAGS _IOR('f', 1, int) #define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int) /* * Space reservation / allocation / free ioctls and argument structure * are designed to be compatible with XFS. * * ALLOCSP* and FREESP* are not and will never be supported, but are * included here for completeness. */ struct ocfs2_space_resv { __s16 l_type; __s16 l_whence; __s64 l_start; __s64 l_len; /* len == 0 means until end of file */ __s32 l_sysid; __u32 l_pid; __s32 l_pad[4]; /* reserve area */ }; #define OCFS2_IOC_ALLOCSP _IOW ('X', 10, struct ocfs2_space_resv) #define OCFS2_IOC_FREESP _IOW ('X', 11, struct ocfs2_space_resv) #define OCFS2_IOC_RESVSP _IOW ('X', 40, struct ocfs2_space_resv) #define OCFS2_IOC_UNRESVSP _IOW ('X', 41, struct ocfs2_space_resv) #define OCFS2_IOC_ALLOCSP64 _IOW ('X', 36, struct ocfs2_space_resv) #define OCFS2_IOC_FREESP64 _IOW ('X', 37, struct ocfs2_space_resv) #define OCFS2_IOC_RESVSP64 _IOW ('X', 42, struct ocfs2_space_resv) #define OCFS2_IOC_UNRESVSP64 _IOW ('X', 43, struct ocfs2_space_resv) /* Used to pass group descriptor data when online resize is done */ struct ocfs2_new_group_input { __u64 group; /* Group descriptor's blkno. */ __u32 clusters; /* Total number of clusters in this group */ __u32 frees; /* Total free clusters in this group */ __u16 chain; /* Chain for this group */ __u16 reserved1; __u32 reserved2; }; #define OCFS2_IOC_GROUP_EXTEND _IOW('o', 1, int) #define OCFS2_IOC_GROUP_ADD _IOW('o', 2,struct ocfs2_new_group_input) #define OCFS2_IOC_GROUP_ADD64 _IOW('o', 3,struct ocfs2_new_group_input) /* Used to pass 2 file names to reflink. */ struct reflink_arguments { __u64 old_path; __u64 new_path; __u64 preserve; }; #define OCFS2_IOC_REFLINK _IOW('o', 4, struct reflink_arguments) /* Following definitions dedicated for ocfs2_info_request ioctls. */ #define OCFS2_INFO_MAX_REQUEST (50) #define OCFS2_TEXT_UUID_LEN (OCFS2_VOL_UUID_LEN * 2) /* Magic number of all requests */ #define OCFS2_INFO_MAGIC (0x4F32494E) /* * Always try to separate info request into small pieces to * guarantee the backward&forward compatibility. */ struct ocfs2_info { __u64 oi_requests; /* Array of __u64 pointers to requests */ __u32 oi_count; /* Number of requests in info_requests */ __u32 oi_pad; }; struct ocfs2_info_request { /*00*/ __u32 ir_magic; /* Magic number */ __u32 ir_code; /* Info request code */ __u32 ir_size; /* Size of request */ __u32 ir_flags; /* Request flags */ /*10*/ /* Request specific fields */ }; struct ocfs2_info_clustersize { struct ocfs2_info_request ic_req; __u32 ic_clustersize; __u32 ic_pad; }; struct ocfs2_info_blocksize { struct ocfs2_info_request ib_req; __u32 ib_blocksize; __u32 ib_pad; }; struct ocfs2_info_maxslots { struct ocfs2_info_request im_req; __u32 im_max_slots; __u32 im_pad; }; struct ocfs2_info_label { struct ocfs2_info_request il_req; __u8 il_label[OCFS2_MAX_VOL_LABEL_LEN]; } __attribute__ ((packed)); struct ocfs2_info_uuid { struct ocfs2_info_request iu_req; __u8 iu_uuid_str[OCFS2_TEXT_UUID_LEN + 1]; } __attribute__ ((packed)); struct ocfs2_info_fs_features { struct ocfs2_info_request if_req; __u32 if_compat_features; __u32 if_incompat_features; __u32 if_ro_compat_features; __u32 if_pad; }; struct ocfs2_info_journal_size { struct ocfs2_info_request ij_req; __u64 ij_journal_size; }; /* Codes for ocfs2_info_request */ enum ocfs2_info_type { OCFS2_INFO_CLUSTERSIZE = 1, OCFS2_INFO_BLOCKSIZE, OCFS2_INFO_MAXSLOTS, OCFS2_INFO_LABEL, OCFS2_INFO_UUID, OCFS2_INFO_FS_FEATURES, OCFS2_INFO_JOURNAL_SIZE, OCFS2_INFO_NUM_TYPES }; /* Flags for struct ocfs2_info_request */ /* Filled by the caller */ #define OCFS2_INFO_FL_NON_COHERENT (0x00000001) /* Cluster coherency not required. This is a hint. It is up to ocfs2 whether the request can be fulfilled without locking. */ /* Filled by ocfs2 */ #define OCFS2_INFO_FL_FILLED (0x40000000) /* Filesystem understood this request and filled in the answer */ #define OCFS2_INFO_FL_ERROR (0x80000000) /* Error happened during request handling. */ #define OCFS2_IOC_INFO _IOR('o', 5, struct ocfs2_info) #endif /* OCFS2_IOCTL_H */ ./ocfs2-tools-1.6.4/include/ocfs2-kernel/ocfs2_lockid.h0000664000176100017610000000534711170734140017416 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2_lockid.h * * Defines OCFS2 lockid bits. * * Copyright (C) 2002, 2005 Oracle. All rights reserved. * * 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 021110-1307, USA. */ #ifndef OCFS2_LOCKID_H #define OCFS2_LOCKID_H /* lock ids are made up in the following manner: * name[0] --> type * name[1-6] --> 6 pad characters, reserved for now * name[7-22] --> block number, expressed in hex as 16 chars * name[23-30] --> i_generation, expressed in hex 8 chars * name[31] --> '\0' */ #define OCFS2_LOCK_ID_MAX_LEN 32 #define OCFS2_LOCK_ID_PAD "000000" #define OCFS2_DENTRY_LOCK_INO_START 18 enum ocfs2_lock_type { OCFS2_LOCK_TYPE_META = 0, OCFS2_LOCK_TYPE_DATA, OCFS2_LOCK_TYPE_SUPER, OCFS2_LOCK_TYPE_RENAME, OCFS2_LOCK_TYPE_RW, OCFS2_LOCK_TYPE_DENTRY, OCFS2_LOCK_TYPE_OPEN, OCFS2_LOCK_TYPE_FLOCK, OCFS2_NUM_LOCK_TYPES }; static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) { char c; switch (type) { case OCFS2_LOCK_TYPE_META: c = 'M'; break; case OCFS2_LOCK_TYPE_DATA: c = 'D'; break; case OCFS2_LOCK_TYPE_SUPER: c = 'S'; break; case OCFS2_LOCK_TYPE_RENAME: c = 'R'; break; case OCFS2_LOCK_TYPE_RW: c = 'W'; break; case OCFS2_LOCK_TYPE_DENTRY: c = 'N'; break; case OCFS2_LOCK_TYPE_OPEN: c = 'O'; break; case OCFS2_LOCK_TYPE_FLOCK: c = 'F'; break; default: c = '\0'; } return c; } static char *ocfs2_lock_type_strings[] = { [OCFS2_LOCK_TYPE_META] = "Meta", [OCFS2_LOCK_TYPE_DATA] = "Data", [OCFS2_LOCK_TYPE_SUPER] = "Super", [OCFS2_LOCK_TYPE_RENAME] = "Rename", /* Need to differntiate from [R]ename.. serializing writes is the * important job it does, anyway. */ [OCFS2_LOCK_TYPE_RW] = "Write/Read", [OCFS2_LOCK_TYPE_DENTRY] = "Dentry", [OCFS2_LOCK_TYPE_OPEN] = "Open", [OCFS2_LOCK_TYPE_FLOCK] = "Flock", }; static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) { #ifdef __KERNEL__ BUG_ON(type >= OCFS2_NUM_LOCK_TYPES); #endif return ocfs2_lock_type_strings[type]; } #endif /* OCFS2_LOCKID_H */ ./ocfs2-tools-1.6.4/include/ocfs2-kernel/quota_tree.h0000644000176100017610000000056711453177334017234 00000000000000#ifndef _QUOTA_TREE_H #define _QUOTA_TREE_H #define QT_TREEOFF 1 /* Header of leaf tree block */ struct qt_disk_dqdbheader { __le32 dqdh_next_free; /* Number of next block with free entry */ __le32 dqdh_prev_free; /* Number of previous block with free entry */ __le16 dqdh_entries; /* Number of valid entries in block */ __le16 dqdh_pad1; __le32 dqdh_pad2; }; #endif ./ocfs2-tools-1.6.4/include/ocfs2-kernel/sparse_endian_types.h0000644000176100017610000000041611115551035021101 00000000000000#ifndef O2CB_SPARSE_ENDIAN_TYPES_H #define O2CB_SPARSE_ENDIAN_TYPES_H #include typedef __u16 __le16; typedef __u16 __be16; typedef __u32 __le32; typedef __u32 __be32; typedef __u64 __le64; typedef __u64 __be64; #endif /* O2CB_SPARSE_ENDIAN_TYPES_H */ ./ocfs2-tools-1.6.4/include/o2dlm/0000775000176100017610000000000011515641640013503 500000000000000./ocfs2-tools-1.6.4/include/o2dlm/Makefile0000644000176100017610000000063411115551035015056 00000000000000TOPDIR = ../.. include $(TOPDIR)/Preamble.make HFILES_GEN = o2dlm_err.h all: $(HFILES_GEN) HFILES = o2dlm.h HEADERS_SUBDIR = o2dlm HEADERS = $(HFILES) $(HFILES_GEN) o2dlm_err.h: $(TOPDIR)/libo2dlm/o2dlm_err.h cp $< $@ $(TOPDIR)/libo2dlm/o2dlm_err.h: make -C $(TOPDIR)/libo2dlm o2dlm_err.h DIST_FILES = $(HFILES) CLEAN_RULES = clean-err clean-err: rm -f o2dlm_err.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/include/o2dlm/o2dlm.h0000644000176100017610000000741511500500544014605 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2dlm.h * * Defines the userspace locking api * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Mark Fasheh */ #ifndef _O2DLM_H_ #define _O2DLM_H_ #include #include #include #include #include #include #include #define O2DLM_LOCK_ID_MAX_LEN 32 #define O2DLM_DOMAIN_MAX_LEN 255 /* + null pointer */ #define O2DLM_MAX_FULL_DOMAIN_PATH (PATH_MAX + 1) /* valid lock flags */ #define O2DLM_TRYLOCK 0x01 #define O2DLM_VALID_FLAGS (O2DLM_TRYLOCK) /* Forward declarations */ struct o2dlm_ctxt; /* valid lock levels */ enum o2dlm_lock_level { O2DLM_LEVEL_PRMODE, O2DLM_LEVEL_EXMODE }; /* Expects to be given a path to the root of a valid ocfs2_dlmfs file * system and a domain identifier of length <= 255 characters including * the '\0' */ errcode_t o2dlm_initialize(const char *dlmfs_path, const char *domain_name, struct o2dlm_ctxt **ctxt); /* * lock_name, is a valid lock name -- 32 bytes long including the null * character * * Returns: 0 if we got the lock we wanted */ errcode_t o2dlm_lock(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level); /* * Like o2dlm_lock, but also registers a BAST function for this lock. This * returns a file descriptor in poll_fd that can be fed to select(2) or * poll(2). When there is POLLIN on the descriptor, call o2dlm_process_bast(). */ errcode_t o2dlm_lock_with_bast(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level, void (*bast_func)(void *bast_arg), void *bast_arg, int *poll_fd); /* returns 0 on success */ errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt, const char *lockid); /* Remove an unlocked lock from the domain */ errcode_t o2dlm_drop_lock(struct o2dlm_ctxt *ctxt, const char *lockid); /* Read the LVB out of a lock. * 'len' is the amount to read into 'lvb' * * We can only read LVB_MAX bytes out of the lock, even if you * specificy a len larger than that. For classic o2dlm, LVB_MAX is * 64 bytes. For fsdlm, it is 32 bytes. * * If you want to know how much was read, then pass 'bytes_read' */ errcode_t o2dlm_read_lvb(struct o2dlm_ctxt *ctxt, char *lockid, char *lvb, unsigned int len, unsigned int *bytes_read); errcode_t o2dlm_write_lvb(struct o2dlm_ctxt *ctxt, char *lockid, const char *lvb, unsigned int len, unsigned int *bytes_written); /* * Call this when select(2) or poll(2) says there is data on poll_fd. It * will fire off the BAST associated with poll_fd. */ void o2dlm_process_bast(struct o2dlm_ctxt *ctxt, int poll_fd); /* * Unlocks all pending locks and frees the lock context. */ errcode_t o2dlm_destroy(struct o2dlm_ctxt *ctxt); /* * Optional features that libo2dlm and dlmfs can support. */ errcode_t o2dlm_supports_bast(int *supports); errcode_t o2dlm_supports_stackglue(int *supports); #endif /* _O2DLM_H_ */ ./ocfs2-tools-1.6.4/include/o2cb/0000775000176100017610000000000011515641640013313 500000000000000./ocfs2-tools-1.6.4/include/o2cb/Makefile0000644000176100017610000000071311115551035014664 00000000000000TOPDIR = ../.. include $(TOPDIR)/Preamble.make HFILES_GEN = o2cb_err.h all: $(HFILES_GEN) HFILES = o2cb.h ocfs2_nodemanager.h ocfs2_heartbeat.h o2cb_client_proto.h HEADERS_SUBDIR = o2cb HEADERS = $(HFILES) $(HFILES_GEN) o2cb_err.h: $(TOPDIR)/libo2cb/o2cb_err.h cp $< $@ $(TOPDIR)/libo2cb/o2cb_err.h: make -C $(TOPDIR)/libo2cb o2cb_err.h DIST_FILES = $(HFILES) CLEAN_RULES = clean-err clean-err: rm -f o2cb_err.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/include/o2cb/o2cb.h0000664000176100017610000001011511506552637014236 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2cb.h * * Routines for accessing the o2cb configuration. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #ifndef _O2CB_H #define _O2CB_H #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 #endif #ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #define OCFS2_FS_NAME "ocfs2" errcode_t o2cb_init(void); errcode_t o2cb_get_stack_name(const char **name); errcode_t o2cb_create_cluster(const char *cluster_name); errcode_t o2cb_remove_cluster(const char *cluster_name); errcode_t o2cb_add_node(const char *cluster_name, const char *node_name, const char *node_num, const char *ip_address, const char *ip_port, const char *local); errcode_t o2cb_del_node(const char *cluster_name, const char *node_name); errcode_t o2cb_list_clusters(char ***clusters); void o2cb_free_cluster_list(char **clusters); errcode_t o2cb_list_nodes(char *cluster_name, char ***nodes); void o2cb_free_nodes_list(char **nodes); errcode_t o2cb_control_daemon_debug(char **debug); struct o2cb_cluster_desc { char *c_stack; /* The cluster stack, NULL for classic */ char *c_cluster; /* The name of the cluster, NULL for the default cluster, which is only valid in the classic stack. */ }; struct o2cb_region_desc { char *r_name; /* The uuid of the region */ char *r_device_name; /* The device the region is on */ char *r_service; /* A program or mountpoint */ int r_block_bytes; uint64_t r_start_block; uint64_t r_blocks; int r_persist; /* Persist past process exit */ }; /* Expected use case for the region descriptor is to allocate it on * the stack and completely fill it before calling * begin_group_join(). Regular programs (not mount.ocfs2) should provide * a mountpoint that does not begin with a '/'. Eg, fsck could use "fsck" */ errcode_t o2cb_begin_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); errcode_t o2cb_complete_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result); errcode_t o2cb_group_leave(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); errcode_t o2cb_get_hb_thread_pid (const char *cluster_name, const char *region_name, pid_t *pid); errcode_t o2cb_get_region_ref(const char *region_name, int undo); errcode_t o2cb_put_region_ref(const char *region_name, int undo); errcode_t o2cb_num_region_refs(const char *region_name, int *num_refs); errcode_t o2cb_get_node_num(const char *cluster_name, const char *node_name, uint16_t *node_num); void o2cb_free_cluster_desc(struct o2cb_cluster_desc *cluster); errcode_t o2cb_running_cluster_desc(struct o2cb_cluster_desc *cluster); struct ocfs2_protocol_version { uint8_t pv_major; uint8_t pv_minor; }; errcode_t o2cb_get_max_locking_protocol(struct ocfs2_protocol_version *proto); errcode_t o2cb_control_open(unsigned int this_node, struct ocfs2_protocol_version *proto); void o2cb_control_close(void); errcode_t o2cb_control_node_down(const char *uuid, unsigned int nodeid); errcode_t o2cb_get_hb_ctl_path(char *buf, int count); #endif /* _O2CB_H */ ./ocfs2-tools-1.6.4/include/o2cb/ocfs2_nodemanager.h0000644000176100017610000000242011115551035016746 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2_nodemanager.h * * Header describing the interface between userspace and the kernel * for the ocfs2_nodemanager module. * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * 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 021110-1307, USA. * */ #ifndef _OCFS2_NODEMANAGER_H #define _OCFS2_NODEMANAGER_H #define O2NM_API_VERSION 5 #define O2NM_MAX_NODES 255 #define O2NM_INVALID_NODE_NUM 255 /* host name, group name, cluster name all 64 bytes */ #define O2NM_MAX_NAME_LEN 64 // __NEW_UTS_LEN #endif /* _OCFS2_NODEMANAGER_H */ ./ocfs2-tools-1.6.4/include/o2cb/ocfs2_heartbeat.h0000644000176100017610000000217611115551035016435 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2_heartbeat.h * * On-disk structures for ocfs2_heartbeat * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * 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 021110-1307, USA. */ #ifndef _OCFS2_HEARTBEAT_H #define _OCFS2_HEARTBEAT_H struct o2hb_disk_heartbeat_block { __le64 hb_seq; __u8 hb_node; __u8 hb_pad1[3]; __le32 hb_cksum; __le64 hb_generation; }; #endif /* _OCFS2_HEARTBEAT_H */ ./ocfs2-tools-1.6.4/include/o2cb/o2cb_client_proto.h0000664000176100017610000000413111170734140017004 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: */ /****************************************************************************** ******************************************************************************* ** ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions ** of the GNU General Public License v.2. ** ******************************************************************************* ******************************************************************************/ /* * Copyright (C) 2007 Oracle. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. */ #ifndef __O2CB_CLIENT_PROTO_H #define __O2CB_CLIENT_PROTO_H /* Basic communication properties */ #define OCFS2_CONTROLD_MAXLINE 256 #define OCFS2_CONTROLD_MAXARGS 16 #define OCFS2_CONTROLD_SOCK_PATH "ocfs2_controld_sock" #define O2CB_CONTROLD_SOCK_PATH "o2cb_controld_sock" /* Client messages */ typedef enum { CM_MOUNT, CM_MRESULT, CM_UNMOUNT, CM_STATUS, CM_LISTFS, CM_LISTMOUNTS, CM_LISTCLUSTERS, CM_ITEMCOUNT, CM_ITEM, CM_DUMP, } client_message; int client_listen(const char *path); int client_connect(const char *path); static inline int ocfs2_client_listen(void) { return client_listen(OCFS2_CONTROLD_SOCK_PATH); } static inline int ocfs2_client_connect(void) { return client_connect(OCFS2_CONTROLD_SOCK_PATH); } const char *message_to_string(client_message message); int send_message(int fd, client_message message, ...); int receive_message(int fd, char *buf, client_message *message, char **argv); int receive_message_full(int fd, char *buf, client_message *message, char **argv, char **rest); void free_received_list(char **list); int receive_list(int fd, char *buf, char ***ret_list); int parse_status(char **args, int *error, char **error_msg); #endif /* __O2CB_CLIENT_PROTO_H */ ./ocfs2-tools-1.6.4/include/ocfs2/0000775000176100017610000000000011515641640013502 500000000000000./ocfs2-tools-1.6.4/include/ocfs2/Makefile0000664000176100017610000000072011170734140015054 00000000000000TOPDIR = ../.. include $(TOPDIR)/Preamble.make HFILES_GEN = ocfs2_err.h all: $(HFILES_GEN) HFILES = ocfs2.h jbd2.h bitops.h byteorder.h kernel-rbtree.h image.h HEADERS_SUBDIR = ocfs2 HEADERS = $(HFILES) $(HFILES_GEN) ocfs2_err.h: $(TOPDIR)/libocfs2/ocfs2_err.h cp $< $@ $(TOPDIR)/libocfs2/ocfs2_err.h: make -C $(TOPDIR)/libocfs2 ocfs2_err.h DIST_FILES = $(HFILES) CLEAN_RULES = clean-err clean-err: rm -f ocfs2_err.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/include/ocfs2/ocfs2.h0000644000176100017610000015404211515637015014614 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2.h * * Filesystem object routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker */ #ifndef _FILESYS_H #define _FILESYS_H #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 #endif #ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OCFS2_LIB_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_SUPP | \ OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV | \ OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG | \ OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT | \ OCFS2_FEATURE_INCOMPAT_INLINE_DATA | \ OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG) #define OCFS2_LIB_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_SUPP #define OCFS2_LIB_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_SUPP #define OCFS2_LIB_ABORTED_TUNEFS_SUPP OCFS2_TUNEFS_INPROG_REMOVE_SLOT /* define OCFS2_SB for ocfs2-tools */ #define OCFS2_SB(sb) (sb) /* Flags for the ocfs2_filesys structure */ #define OCFS2_FLAG_RO 0x00 #define OCFS2_FLAG_RW 0x01 #define OCFS2_FLAG_CHANGED 0x02 #define OCFS2_FLAG_DIRTY 0x04 #define OCFS2_FLAG_SWAP_BYTES 0x08 #define OCFS2_FLAG_BUFFERED 0x10 #define OCFS2_FLAG_NO_REV_CHECK 0x20 /* Do not check the OCFS vol_header structure for revision info */ #define OCFS2_FLAG_HEARTBEAT_DEV_OK 0x40 #define OCFS2_FLAG_STRICT_COMPAT_CHECK 0x80 #define OCFS2_FLAG_IMAGE_FILE 0x0100 #define OCFS2_FLAG_NO_ECC_CHECKS 0x0200 /* Do not validate metaecc * information on block * reads. */ /* Return flags for the directory iterator functions */ #define OCFS2_DIRENT_CHANGED 0x01 #define OCFS2_DIRENT_ABORT 0x02 #define OCFS2_DIRENT_ERROR 0x04 /* Directory iterator flags */ #define OCFS2_DIRENT_FLAG_INCLUDE_EMPTY 0x01 #define OCFS2_DIRENT_FLAG_INCLUDE_REMOVED 0x02 #define OCFS2_DIRENT_FLAG_EXCLUDE_DOTS 0x04 #define OCFS2_DIRENT_FLAG_INCLUDE_TRAILER 0x08 /* Return flags for the chain iterator functions */ #define OCFS2_CHAIN_CHANGED 0x01 #define OCFS2_CHAIN_ABORT 0x02 #define OCFS2_CHAIN_ERROR 0x04 /* Directory constants */ #define OCFS2_DIRENT_DOT_FILE 1 #define OCFS2_DIRENT_DOT_DOT_FILE 2 #define OCFS2_DIRENT_OTHER_FILE 3 #define OCFS2_DIRENT_DELETED_FILE 4 /* Directory scan flags */ #define OCFS2_DIR_SCAN_FLAG_EXCLUDE_DOTS 0x01 /* Check if mounted flags */ #define OCFS2_MF_MOUNTED 1 #define OCFS2_MF_ISROOT 2 #define OCFS2_MF_READONLY 4 #define OCFS2_MF_SWAP 8 #define OCFS2_MF_BUSY 16 #define OCFS2_MF_MOUNTED_CLUSTER 32 /* check_heartbeats progress states */ #define OCFS2_CHB_START 1 #define OCFS2_CHB_WAITING 2 #define OCFS2_CHB_COMPLETE 3 /* Flags for global quotafile info */ #define OCFS2_QF_INFO_DIRTY 1 #define OCFS2_QF_INFO_LOADED 2 typedef void (*ocfs2_chb_notify)(int state, char *progress, void *data); typedef struct _ocfs2_filesys ocfs2_filesys; typedef struct _ocfs2_cached_inode ocfs2_cached_inode; typedef struct _ocfs2_cached_dquot ocfs2_cached_dquot; typedef struct _io_channel io_channel; typedef struct _ocfs2_inode_scan ocfs2_inode_scan; typedef struct _ocfs2_dir_scan ocfs2_dir_scan; typedef struct _ocfs2_bitmap ocfs2_bitmap; typedef struct _ocfs2_devices ocfs2_devices; #define MAXQUOTAS 2 #define USRQUOTA 0 #define GRPQUOTA 1 #define OCFS2_DEF_BLOCK_GRACE 604800 /* 1 week */ #define OCFS2_DEF_INODE_GRACE 604800 /* 1 week */ #define OCFS2_DEF_QUOTA_SYNC 10000 /* 10 seconds */ struct _ocfs2_quota_info { ocfs2_cached_inode *qi_inode; int flags; struct ocfs2_global_disk_dqinfo qi_info; }; typedef struct _ocfs2_quota_info ocfs2_quota_info; struct _ocfs2_filesys { char *fs_devname; uint32_t fs_flags; io_channel *fs_io; struct ocfs2_dinode *fs_super; struct ocfs2_dinode *fs_orig_super; unsigned int fs_blocksize; unsigned int fs_clustersize; uint32_t fs_clusters; uint64_t fs_blocks; uint32_t fs_umask; uint64_t fs_root_blkno; uint64_t fs_sysdir_blkno; uint64_t fs_first_cg_blkno; char uuid_str[OCFS2_VOL_UUID_LEN * 2 + 1]; /* Allocators */ ocfs2_cached_inode *fs_cluster_alloc; ocfs2_cached_inode **fs_inode_allocs; ocfs2_cached_inode *fs_system_inode_alloc; ocfs2_cached_inode **fs_eb_allocs; ocfs2_cached_inode *fs_system_eb_alloc; struct o2dlm_ctxt *fs_dlm_ctxt; struct ocfs2_image_state *ost; ocfs2_quota_info qinfo[MAXQUOTAS]; /* Reserved for the use of the calling application. */ void *fs_private; }; struct _ocfs2_cached_inode { struct _ocfs2_filesys *ci_fs; uint64_t ci_blkno; struct ocfs2_dinode *ci_inode; ocfs2_bitmap *ci_chains; }; typedef unsigned int qid_t; struct _ocfs2_cached_dquot { loff_t d_off; /* Offset of structure in the file */ struct _ocfs2_cached_dquot *d_next; /* Next entry in hashchain */ struct _ocfs2_cached_dquot **d_pprev; /* Previous pointer in hashchain */ struct ocfs2_global_disk_dqblk d_ddquot; /* Quota entry */ }; struct ocfs2_slot_data { int sd_valid; unsigned int sd_node_num; }; struct ocfs2_slot_map_data { int md_num_slots; struct ocfs2_slot_data *md_slots; }; struct _ocfs2_devices { struct list_head list; char dev_name[PATH_MAX]; uint8_t label[64]; uint8_t uuid[16]; int mount_flags; int fs_type; /* 0=unknown, 1=ocfs, 2=ocfs2 */ int hb_dev; char stack[8]; /* Local, O2CB, CMAN, PCMK */ uint32_t maj_num; /* major number of the device */ uint32_t min_num; /* minor number of the device */ errcode_t errcode; /* error encountered reading device */ void *private; struct ocfs2_slot_map_data *map; /* Mounted nodes, must be freed */ }; typedef struct _ocfs2_fs_options ocfs2_fs_options; struct _ocfs2_fs_options { uint32_t opt_compat; uint32_t opt_incompat; uint32_t opt_ro_compat; }; enum ocfs2_mkfs_types { OCFS2_MKFSTYPE_DEFAULT, OCFS2_MKFSTYPE_DATAFILES, OCFS2_MKFSTYPE_MAIL, OCFS2_MKFSTYPE_VMSTORE, }; struct _ocfs2_quota_hash { int alloc_entries; int used_entries; ocfs2_cached_dquot **hash; }; struct ocfs2_dx_hinfo { uint32_t major_hash; uint32_t minor_hash; }; struct ocfs2_dir_lookup_result { struct ocfs2_dx_hinfo dl_hinfo; /* name hash results */ char * dl_leaf; /* unindexed block buffer */ uint64_t dl_leaf_blkno; /* blk number of dl_leaf */ struct ocfs2_dir_entry * dl_entry; /* dirent pointed into dl_leaf */ struct ocfs2_dx_leaf * dl_dx_leaf; /* indexed block buffer */ uint64_t dl_dx_leaf_blkno; /* blk number of dl_dx_leaf */ struct ocfs2_dx_entry * dl_dx_entry; /* indexed entry pointed to dl_dx_leaf */ int dl_dx_entry_idx; /* index of dl_dx_entry in entries list */ }; typedef struct _ocfs2_quota_hash ocfs2_quota_hash; errcode_t ocfs2_malloc(unsigned long size, void *ptr); errcode_t ocfs2_malloc0(unsigned long size, void *ptr); errcode_t ocfs2_free(void *ptr); errcode_t ocfs2_realloc(unsigned long size, void *ptr); errcode_t ocfs2_realloc0(unsigned long size, void *ptr, unsigned long old_size); errcode_t ocfs2_malloc_blocks(io_channel *channel, int num_blocks, void *ptr); errcode_t ocfs2_malloc_block(io_channel *channel, void *ptr); errcode_t io_open(const char *name, int flags, io_channel **channel); errcode_t io_close(io_channel *channel); int io_get_error(io_channel *channel); errcode_t io_set_blksize(io_channel *channel, int blksize); int io_get_blksize(io_channel *channel); int io_get_fd(io_channel *channel); /* * Raw I/O functions. They will use the I/O cache if available. The * _nocache version will not add a block to the cache, but if the block is * already in the cache it will be moved to the end of the LRU and kept * in a good state. * * Use ocfs2_read_blocks() if your application might handle o2image file. * * If a channel is set to 'nocache' via io_set_nocache(), it will use * the _nocache() functions even if called via the regular functions. * This allows control of naive code that we don't want to have to carry * nocache parameters around. Smarter code can ignore this function and * use the _nocache() functions directly. */ errcode_t io_read_block(io_channel *channel, int64_t blkno, int count, char *data); errcode_t io_read_block_nocache(io_channel *channel, int64_t blkno, int count, char *data); errcode_t io_write_block(io_channel *channel, int64_t blkno, int count, const char *data); errcode_t io_write_block_nocache(io_channel *channel, int64_t blkno, int count, const char *data); errcode_t io_init_cache(io_channel *channel, size_t nr_blocks); void io_set_nocache(io_channel *channel, bool nocache); errcode_t io_init_cache_size(io_channel *channel, size_t bytes); errcode_t io_share_cache(io_channel *from, io_channel *to); errcode_t io_mlock_cache(io_channel *channel); void io_destroy_cache(io_channel *channel); errcode_t ocfs2_read_super(ocfs2_filesys *fs, uint64_t superblock, char *sb); /* Writes the main superblock at OCFS2_SUPER_BLOCK_BLKNO */ errcode_t ocfs2_write_primary_super(ocfs2_filesys *fs); /* Writes the primary and backups if enabled */ errcode_t ocfs2_write_super(ocfs2_filesys *fs); /* * ocfs2_read_blocks() is a wraper around io_read_block. If device is an * image file it translates disk offset to image offset. * ocfs2_read_blocks_nocache() calls io_read_block_nocache(). */ errcode_t ocfs2_read_blocks(ocfs2_filesys *fs, int64_t blkno, int count, char *data); errcode_t ocfs2_read_blocks_nocache(ocfs2_filesys *fs, int64_t blkno, int count, char *data); int ocfs2_mount_local(ocfs2_filesys *fs); errcode_t ocfs2_open(const char *name, int flags, unsigned int superblock, unsigned int blksize, ocfs2_filesys **ret_fs); errcode_t ocfs2_flush(ocfs2_filesys *fs); errcode_t ocfs2_close(ocfs2_filesys *fs); void ocfs2_freefs(ocfs2_filesys *fs); void ocfs2_swap_inode_from_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di); void ocfs2_swap_inode_to_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di); errcode_t ocfs2_read_inode(ocfs2_filesys *fs, uint64_t blkno, char *inode_buf); errcode_t ocfs2_write_inode(ocfs2_filesys *fs, uint64_t blkno, char *inode_buf); errcode_t ocfs2_check_directory(ocfs2_filesys *fs, uint64_t dir); int ocfs2_check_dir_entry(ocfs2_filesys *fs, struct ocfs2_dir_entry *de, char *dir_buf, unsigned int offset); errcode_t ocfs2_read_cached_inode(ocfs2_filesys *fs, uint64_t blkno, ocfs2_cached_inode **ret_ci); errcode_t ocfs2_write_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *cinode); errcode_t ocfs2_free_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *cinode); errcode_t ocfs2_refresh_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *cinode); /* * obj is the object containing the extent list. eg, if you are swapping * an inode's extent list, you're passing 'di' for the obj and * '&di->id2.i_list' for the el. obj is needed to make sure the * byte swapping code doesn't walk off the end of the buffer in the * presence of corruption. */ void ocfs2_swap_extent_list_from_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_extent_list *el); void ocfs2_swap_extent_list_to_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_extent_list *el); errcode_t ocfs2_extent_map_get_blocks(ocfs2_cached_inode *cinode, uint64_t v_blkno, int count, uint64_t *p_blkno, uint64_t *ret_count, uint16_t *extent_flags); errcode_t ocfs2_get_clusters(ocfs2_cached_inode *cinode, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags); errcode_t ocfs2_xattr_get_clusters(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t el_blkno, char *el_blk, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags); int ocfs2_find_leaf(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t cpos, char **leaf_buf); int ocfs2_search_extent_list(struct ocfs2_extent_list *el, uint32_t v_cluster); void ocfs2_swap_journal_superblock(journal_superblock_t *jsb); errcode_t ocfs2_init_journal_superblock(ocfs2_filesys *fs, char *buf, int buflen, uint32_t jrnl_size); errcode_t ocfs2_read_journal_superblock(ocfs2_filesys *fs, uint64_t blkno, char *jsb_buf); errcode_t ocfs2_write_journal_superblock(ocfs2_filesys *fs, uint64_t blkno, char *jsb_buf); errcode_t ocfs2_make_journal(ocfs2_filesys *fs, uint64_t blkno, uint32_t clusters, ocfs2_fs_options *features); errcode_t ocfs2_journal_clear_features(journal_superblock_t *jsb, ocfs2_fs_options *features); errcode_t ocfs2_journal_set_features(journal_superblock_t *jsb, ocfs2_fs_options *features); extern size_t ocfs2_journal_tag_bytes(journal_superblock_t *jsb); extern uint64_t ocfs2_journal_tag_block(journal_block_tag_t *tag, size_t tag_bytes); void ocfs2_swap_extent_block_to_cpu(ocfs2_filesys *fs, struct ocfs2_extent_block *eb); void ocfs2_swap_extent_block_from_cpu(ocfs2_filesys *fs, struct ocfs2_extent_block *eb); errcode_t ocfs2_read_extent_block(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf); errcode_t ocfs2_read_extent_block_nocheck(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf); errcode_t ocfs2_write_extent_block(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf); void ocfs2_swap_refcount_list_to_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_refcount_list *rl); void ocfs2_swap_refcount_list_from_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_refcount_list *rl); void ocfs2_swap_refcount_block_to_cpu(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb); void ocfs2_swap_refcount_block_from_cpu(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb); errcode_t ocfs2_read_refcount_block(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf); errcode_t ocfs2_read_refcount_block_nocheck(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf); errcode_t ocfs2_write_refcount_block(ocfs2_filesys *fs, uint64_t blkno, char *rb_buf); errcode_t ocfs2_delete_refcount_block(ocfs2_filesys *fs, uint64_t blkno); errcode_t ocfs2_new_refcount_block(ocfs2_filesys *fs, uint64_t *blkno, uint64_t root_blkno, uint32_t rf_generation); errcode_t ocfs2_increase_refcount(ocfs2_filesys *fs, uint64_t ino, uint64_t cpos, uint32_t len); errcode_t ocfs2_decrease_refcount(ocfs2_filesys *fs, uint64_t ino, uint32_t cpos, uint32_t len, int delete); errcode_t ocfs2_refcount_cow(ocfs2_cached_inode *cinode, uint32_t cpos, uint32_t write_len, uint32_t max_cpos); errcode_t ocfs2_refcount_cow_xattr(ocfs2_cached_inode *ci, char *xe_buf, uint64_t xe_blkno, char *value_buf, uint64_t value_blkno, struct ocfs2_xattr_value_root *xv, uint32_t cpos, uint32_t write_len); errcode_t ocfs2_change_refcount_flag(ocfs2_filesys *fs, uint64_t i_blkno, uint32_t v_cpos, uint32_t clusters, uint64_t p_cpos, int new_flags, int clear_flags); errcode_t ocfs2_refcount_tree_get_rec(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb, uint32_t phys_cpos, uint64_t *p_blkno, uint32_t *e_cpos, uint32_t *num_clusters); errcode_t ocfs2_refcount_punch_hole(ocfs2_filesys *fs, uint64_t rf_blkno, uint64_t p_start, uint32_t len); errcode_t ocfs2_change_refcount(ocfs2_filesys *fs, uint64_t rf_blkno, uint64_t p_start, uint32_t len, uint32_t refcount); int ocfs2_get_refcount_rec(ocfs2_filesys *fs, char *ref_root_buf, uint64_t cpos, unsigned int len, struct ocfs2_refcount_rec *ret_rec, int *index, char *ret_buf); errcode_t ocfs2_create_refcount_tree(ocfs2_filesys *fs, uint64_t *refcount_loc); errcode_t ocfs2_attach_refcount_tree(ocfs2_filesys *fs, uint64_t ino, uint64_t refcount_loc); errcode_t ocfs2_swap_dir_entries_from_cpu(void *buf, uint64_t bytes); errcode_t ocfs2_swap_dir_entries_to_cpu(void *buf, uint64_t bytes); void ocfs2_swap_dir_trailer(struct ocfs2_dir_block_trailer *trailer); errcode_t ocfs2_read_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t block, void *buf); errcode_t ocfs2_write_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t block, void *buf); unsigned int ocfs2_dir_trailer_blk_off(ocfs2_filesys *fs); struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_block(ocfs2_filesys *fs, void *data); int ocfs2_supports_dir_trailer(ocfs2_filesys *fs); int ocfs2_dir_has_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di); int ocfs2_skip_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct ocfs2_dir_entry *de, unsigned long offset); void ocfs2_init_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t blkno, void *buf); errcode_t ocfs2_read_dx_root(ocfs2_filesys *fs, uint64_t block, void *buf); errcode_t ocfs2_read_dx_leaf(ocfs2_filesys *fs, uint64_t block, void *buf); int ocfs2_dir_indexed(struct ocfs2_dinode *di); errcode_t ocfs2_dx_dir_truncate(ocfs2_filesys *fs, uint64_t dir); errcode_t ocfs2_dir_iterate2(ocfs2_filesys *fs, uint64_t dir, int flags, char *block_buf, int (*func)(uint64_t dir, int entry, struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data), void *priv_data); extern errcode_t ocfs2_dir_iterate(ocfs2_filesys *fs, uint64_t dir, int flags, char *block_buf, int (*func)(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data), void *priv_data); extern errcode_t ocfs2_dx_entries_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *dir, int flags, int (*func)(ocfs2_filesys *fs, struct ocfs2_dx_entry_list *entry_list, struct ocfs2_dx_root_block *dx_root, struct ocfs2_dx_leaf *dx_leaf, void *priv_data), void *priv_data); extern errcode_t ocfs2_dx_frees_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *dir, struct ocfs2_dx_root_block *dx_root, int flags, int (*func)(ocfs2_filesys *fs, uint64_t blkno, struct ocfs2_dir_block_trailer *trailer, char *dirblock, void *priv_data), void *priv_data); errcode_t ocfs2_lookup(ocfs2_filesys *fs, uint64_t dir, const char *name, int namelen, char *buf, uint64_t *inode); errcode_t ocfs2_lookup_system_inode(ocfs2_filesys *fs, int type, int slot_num, uint64_t *blkno); errcode_t ocfs2_link(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, int flags); errcode_t ocfs2_unlink(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, int flags); errcode_t ocfs2_open_inode_scan(ocfs2_filesys *fs, ocfs2_inode_scan **ret_scan); void ocfs2_close_inode_scan(ocfs2_inode_scan *scan); errcode_t ocfs2_get_next_inode(ocfs2_inode_scan *scan, uint64_t *blkno, char *inode); errcode_t ocfs2_open_dir_scan(ocfs2_filesys *fs, uint64_t dir, int flags, ocfs2_dir_scan **ret_scan); void ocfs2_close_dir_scan(ocfs2_dir_scan *scan); errcode_t ocfs2_get_next_dir_entry(ocfs2_dir_scan *scan, struct ocfs2_dir_entry *dirent); errcode_t ocfs2_cluster_bitmap_new(ocfs2_filesys *fs, const char *description, ocfs2_bitmap **ret_bitmap); errcode_t ocfs2_block_bitmap_new(ocfs2_filesys *fs, const char *description, ocfs2_bitmap **ret_bitmap); void ocfs2_bitmap_free(ocfs2_bitmap *bitmap); errcode_t ocfs2_bitmap_set(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval); errcode_t ocfs2_bitmap_clear(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval); errcode_t ocfs2_bitmap_test(ocfs2_bitmap *bitmap, uint64_t bitno, int *val); errcode_t ocfs2_bitmap_find_next_set(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); errcode_t ocfs2_bitmap_find_next_clear(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); errcode_t ocfs2_bitmap_read(ocfs2_bitmap *bitmap); errcode_t ocfs2_bitmap_write(ocfs2_bitmap *bitmap); uint64_t ocfs2_bitmap_get_set_bits(ocfs2_bitmap *bitmap); errcode_t ocfs2_bitmap_alloc_range(ocfs2_bitmap *bitmap, uint64_t min, uint64_t len, uint64_t *first_bit, uint64_t *bits_found); errcode_t ocfs2_bitmap_clear_range(ocfs2_bitmap *bitmap, uint64_t len, uint64_t first_bit); errcode_t ocfs2_get_device_size(const char *file, int blocksize, uint64_t *retblocks); errcode_t ocfs2_get_device_sectsize(const char *file, int *sectsize); errcode_t ocfs2_check_if_mounted(const char *file, int *mount_flags); errcode_t ocfs2_check_mount_point(const char *device, int *mount_flags, char *mtpt, int mtlen); errcode_t ocfs2_read_whole_file(ocfs2_filesys *fs, uint64_t blkno, char **buf, int *len); void ocfs2_swap_disk_heartbeat_block(struct o2hb_disk_heartbeat_block *hb); errcode_t ocfs2_check_heartbeat(char *device, int *mount_flags, struct list_head *nodes_list); errcode_t ocfs2_check_heartbeats(struct list_head *dev_list, int ignore_local); errcode_t ocfs2_get_ocfs1_label(char *device, uint8_t *label, uint16_t label_len, uint8_t *uuid, uint16_t uuid_len); void ocfs2_swap_group_desc_from_cpu(ocfs2_filesys *fs, struct ocfs2_group_desc *gd); void ocfs2_swap_group_desc_to_cpu(ocfs2_filesys *fs, struct ocfs2_group_desc *gd); errcode_t ocfs2_read_group_desc(ocfs2_filesys *fs, uint64_t blkno, char *gd_buf); errcode_t ocfs2_write_group_desc(ocfs2_filesys *fs, uint64_t blkno, char *gd_buf); uint64_t ocfs2_get_block_from_group(ocfs2_filesys *fs, struct ocfs2_group_desc *grp, int bpc, int bit_offset); errcode_t ocfs2_chain_iterate(ocfs2_filesys *fs, uint64_t blkno, int (*func)(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data), void *priv_data); errcode_t ocfs2_load_chain_allocator(ocfs2_filesys *fs, ocfs2_cached_inode *cinode); errcode_t ocfs2_write_chain_allocator(ocfs2_filesys *fs, ocfs2_cached_inode *cinode); errcode_t ocfs2_chain_alloc(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t *gd_blkno, uint16_t *suballoc_bit, uint64_t *bitno); errcode_t ocfs2_chain_free(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno); errcode_t ocfs2_chain_alloc_range(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t min, uint64_t requested, uint64_t *start_bit, uint64_t *bits_found); errcode_t ocfs2_chain_free_range(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t len, uint64_t start_bit); errcode_t ocfs2_chain_test(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno, int *oldval); errcode_t ocfs2_chain_force_val(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t blkno, int newval, int *oldval); errcode_t ocfs2_chain_add_group(ocfs2_filesys *fs, ocfs2_cached_inode *cinode); errcode_t ocfs2_init_dir(ocfs2_filesys *fs, uint64_t dir, uint64_t parent_dir); errcode_t ocfs2_expand_dir(ocfs2_filesys *fs, uint64_t dir); errcode_t ocfs2_test_inode_allocated(ocfs2_filesys *fs, uint64_t blkno, int *is_allocated); void ocfs2_init_group_desc(ocfs2_filesys *fs, struct ocfs2_group_desc *gd, uint64_t blkno, uint32_t generation, uint64_t parent_inode, uint16_t bits, uint16_t chain, int suballoc); errcode_t ocfs2_new_dir_block(ocfs2_filesys *fs, uint64_t dir_ino, uint64_t parent_ino, char **block); errcode_t ocfs2_inode_insert_extent(ocfs2_filesys *fs, uint64_t ino, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag); errcode_t ocfs2_cached_inode_insert_extent(ocfs2_cached_inode *ci, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag); void ocfs2_dinode_new_extent_list(ocfs2_filesys *fs, struct ocfs2_dinode *di); void ocfs2_set_inode_data_inline(ocfs2_filesys *fs, struct ocfs2_dinode *di); errcode_t ocfs2_convert_inline_data_to_extents(ocfs2_cached_inode *ci); errcode_t ocfs2_new_inode(ocfs2_filesys *fs, uint64_t *ino, int mode); errcode_t ocfs2_new_system_inode(ocfs2_filesys *fs, uint64_t *ino, int mode, int flags); errcode_t ocfs2_delete_inode(ocfs2_filesys *fs, uint64_t ino); errcode_t ocfs2_new_extent_block(ocfs2_filesys *fs, uint64_t *blkno); errcode_t ocfs2_new_dx_root(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t *dr_blkno); errcode_t ocfs2_delete_extent_block(ocfs2_filesys *fs, uint64_t blkno); errcode_t ocfs2_delete_dx_root(ocfs2_filesys *fs, uint64_t dr_blkno); /* * Allocate the blocks and insert them to the file. * only i_clusters of dinode will be updated accordingly, i_size not changed. */ errcode_t ocfs2_extend_allocation(ocfs2_filesys *fs, uint64_t ino, uint32_t new_clusters); /* Ditto for cached inode */ errcode_t ocfs2_cached_inode_extend_allocation(ocfs2_cached_inode *ci, uint32_t new_clusters); /* Extend the file to the new size. No clusters will be allocated. */ errcode_t ocfs2_extend_file(ocfs2_filesys *fs, uint64_t ino, uint64_t new_size); int ocfs2_mark_extent_written(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t cpos, uint32_t len, uint64_t p_blkno); /* Reserve spaces at "offset" with a "len" in the files. */ errcode_t ocfs2_allocate_unwritten_extents(ocfs2_filesys *fs, uint64_t ino, uint64_t offset, uint64_t len); errcode_t ocfs2_truncate(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size); errcode_t ocfs2_truncate_inline(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size); errcode_t ocfs2_truncate_full(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size, errcode_t (*free_clusters)(ocfs2_filesys *fs, uint32_t len, uint64_t start, void *free_data), void *free_data); errcode_t ocfs2_zero_tail_and_truncate(ocfs2_filesys *fs, ocfs2_cached_inode *ci, uint64_t new_size, uint32_t *new_clusters); errcode_t ocfs2_grow_chain_allocator(ocfs2_filesys *fs, int type, int slot_num, uint32_t num_clusters); errcode_t ocfs2_new_clusters(ocfs2_filesys *fs, uint32_t min, uint32_t requested, uint64_t *start_blkno, uint32_t *clusters_found); errcode_t ocfs2_test_cluster_allocated(ocfs2_filesys *fs, uint32_t cpos, int *is_allocated); errcode_t ocfs2_new_specific_cluster(ocfs2_filesys *fs, uint32_t cpos); errcode_t ocfs2_free_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno); errcode_t ocfs2_test_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno, int test, int *matches); errcode_t ocfs2_lookup(ocfs2_filesys *fs, uint64_t dir, const char *name, int namelen, char *buf, uint64_t *inode); errcode_t ocfs2_namei(ocfs2_filesys *fs, uint64_t root, uint64_t cwd, const char *name, uint64_t *inode); errcode_t ocfs2_namei_follow(ocfs2_filesys *fs, uint64_t root, uint64_t cwd, const char *name, uint64_t *inode); errcode_t ocfs2_follow_link(ocfs2_filesys *fs, uint64_t root, uint64_t cwd, uint64_t inode, uint64_t *res_inode); errcode_t ocfs2_file_read(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset, uint32_t *got); errcode_t ocfs2_file_write(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset, uint32_t *wrote); errcode_t ocfs2_fill_cluster_desc(ocfs2_filesys *fs, struct o2cb_cluster_desc *desc); errcode_t ocfs2_set_cluster_desc(ocfs2_filesys *fs, struct o2cb_cluster_desc *desc); errcode_t ocfs2_fill_heartbeat_desc(ocfs2_filesys *fs, struct o2cb_region_desc *desc); errcode_t ocfs2_lock_down_cluster(ocfs2_filesys *fs); errcode_t ocfs2_release_cluster(ocfs2_filesys *fs); errcode_t ocfs2_initialize_dlm(ocfs2_filesys *fs, const char *service); errcode_t ocfs2_shutdown_dlm(ocfs2_filesys *fs, const char *service); errcode_t ocfs2_super_lock(ocfs2_filesys *fs); errcode_t ocfs2_super_unlock(ocfs2_filesys *fs); errcode_t ocfs2_meta_lock(ocfs2_filesys *fs, ocfs2_cached_inode *inode, enum o2dlm_lock_level level, int flags); errcode_t ocfs2_meta_unlock(ocfs2_filesys *fs, ocfs2_cached_inode *ci); /* Quota operations */ static inline int ocfs2_global_dqstr_in_blk(int blocksize) { return (blocksize - OCFS2_QBLK_RESERVED_SPACE - sizeof(struct qt_disk_dqdbheader)) / sizeof(struct ocfs2_global_disk_dqblk); } void ocfs2_swap_quota_header(struct ocfs2_disk_dqheader *header); void ocfs2_swap_quota_local_info(struct ocfs2_local_disk_dqinfo *info); void ocfs2_swap_quota_chunk_header(struct ocfs2_local_disk_chunk *chunk); void ocfs2_swap_quota_global_info(struct ocfs2_global_disk_dqinfo *info); void ocfs2_swap_quota_global_dqblk(struct ocfs2_global_disk_dqblk *dqblk); void ocfs2_swap_quota_leaf_block_header(struct qt_disk_dqdbheader *bheader); errcode_t ocfs2_init_local_quota_file(ocfs2_filesys *fs, int type, uint64_t blkno); errcode_t ocfs2_init_local_quota_files(ocfs2_filesys *fs, int type); int ocfs2_qtree_depth(int blocksize); int ocfs2_qtree_entry_unused(struct ocfs2_global_disk_dqblk *ddquot); errcode_t ocfs2_init_global_quota_file(ocfs2_filesys *fs, int type); errcode_t ocfs2_init_fs_quota_info(ocfs2_filesys *fs, int type); errcode_t ocfs2_read_global_quota_info(ocfs2_filesys *fs, int type); errcode_t ocfs2_load_fs_quota_info(ocfs2_filesys *fs); errcode_t ocfs2_write_global_quota_info(ocfs2_filesys *fs, int type); errcode_t ocfs2_write_dquot(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot); errcode_t ocfs2_delete_dquot(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot); errcode_t ocfs2_read_dquot(ocfs2_filesys *fs, int type, qid_t id, ocfs2_cached_dquot **ret_dquot); errcode_t ocfs2_new_quota_hash(ocfs2_quota_hash **hashp); errcode_t ocfs2_free_quota_hash(ocfs2_quota_hash *hash); errcode_t ocfs2_insert_quota_hash(ocfs2_quota_hash *hash, ocfs2_cached_dquot *dquot); errcode_t ocfs2_remove_quota_hash(ocfs2_quota_hash *hash, ocfs2_cached_dquot *dquot); errcode_t ocfs2_find_quota_hash(ocfs2_quota_hash *hash, qid_t id, ocfs2_cached_dquot **dquotp); errcode_t ocfs2_find_create_quota_hash(ocfs2_quota_hash *hash, qid_t id, ocfs2_cached_dquot **dquotp); errcode_t ocfs2_find_read_quota_hash(ocfs2_filesys *fs, ocfs2_quota_hash *hash, int type, qid_t id, ocfs2_cached_dquot **dquotp); errcode_t ocfs2_compute_quota_usage(ocfs2_filesys *fs, ocfs2_quota_hash *usr_hash, ocfs2_quota_hash *grp_hash); errcode_t ocfs2_init_quota_change(ocfs2_filesys *fs, ocfs2_quota_hash **usrhash, ocfs2_quota_hash **grphash); errcode_t ocfs2_finish_quota_change(ocfs2_filesys *fs, ocfs2_quota_hash *usrhash, ocfs2_quota_hash *grphash); errcode_t ocfs2_apply_quota_change(ocfs2_filesys *fs, ocfs2_quota_hash *usrhash, ocfs2_quota_hash *grphash, uid_t uid, gid_t gid, int64_t space_change, int64_t inode_change); errcode_t ocfs2_iterate_quota_hash(ocfs2_quota_hash *hash, errcode_t (*f)(ocfs2_cached_dquot *, void *), void *data); errcode_t ocfs2_write_release_dquots(ocfs2_filesys *fs, int type, ocfs2_quota_hash *hash); /* Low level */ void ocfs2_swap_slot_map(struct ocfs2_slot_map *sm, int num_slots); void ocfs2_swap_slot_map_extended(struct ocfs2_slot_map_extended *se, int num_slots); errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map **map_ret); errcode_t ocfs2_read_slot_map_extended(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map_extended **map_ret); errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map *sm); errcode_t ocfs2_write_slot_map_extended(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map_extended *se); /* High level functions for metadata ecc */ void ocfs2_compute_meta_ecc(ocfs2_filesys *fs, void *data, struct ocfs2_block_check *bc); errcode_t ocfs2_validate_meta_ecc(ocfs2_filesys *fs, void *data, struct ocfs2_block_check *bc); /* Low level checksum compute functions. Use the high-level ones. */ extern void ocfs2_block_check_compute(void *data, size_t blocksize, struct ocfs2_block_check *bc); extern errcode_t ocfs2_block_check_validate(void *data, size_t blocksize, struct ocfs2_block_check *bc); /* High level */ errcode_t ocfs2_format_slot_map(ocfs2_filesys *fs); errcode_t ocfs2_load_slot_map(ocfs2_filesys *fs, struct ocfs2_slot_map_data **data_ret); errcode_t ocfs2_store_slot_map(ocfs2_filesys *fs, struct ocfs2_slot_map_data *md); enum ocfs2_lock_type ocfs2_get_lock_type(char c); char *ocfs2_get_lock_type_string(enum ocfs2_lock_type type); errcode_t ocfs2_encode_lockres(enum ocfs2_lock_type type, uint64_t blkno, uint32_t generation, uint64_t parent, char *lockres); errcode_t ocfs2_decode_lockres(char *lockres, enum ocfs2_lock_type *type, uint64_t *blkno, uint32_t *generation, uint64_t *parent); errcode_t ocfs2_printable_lockres(char *lockres, char *name, int len); /* write the superblock at the specific block. */ errcode_t ocfs2_write_backup_super(ocfs2_filesys *fs, uint64_t blkno); /* Get the blkno according to the file system info. * The unused ones, depending on the volume size, are zeroed. * Return the length of the block array. */ int ocfs2_get_backup_super_offsets(ocfs2_filesys *fs, uint64_t *blocks, size_t len); /* This function will get the superblock pointed to by fs and copy it to * the blocks. But first it will ensure all the appropriate clusters are free. * If not, it will error out with ENOSPC. If free, it will set bits for all * the clusters, zero the clusters and write the backup sb. * In case of updating, it will override the backup blocks with the newest * superblock information. */ errcode_t ocfs2_set_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len); /* Conversely, this clears all the allocator bits associated with the * specified backup superblocks */ errcode_t ocfs2_clear_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len); /* Refresh the backup superblock information */ errcode_t ocfs2_refresh_backup_supers(ocfs2_filesys *fs); /* Refresh a specific list of backup superblocks */ errcode_t ocfs2_refresh_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len); errcode_t ocfs2_read_backup_super(ocfs2_filesys *fs, int backup, char *sbbuf); /* get the virtual offset of the last allocated cluster. */ errcode_t ocfs2_get_last_cluster_offset(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t *v_cluster); /* Filesystem features */ enum ocfs2_feature_levels { OCFS2_FEATURE_LEVEL_DEFAULT = 0, OCFS2_FEATURE_LEVEL_MAX_COMPAT, OCFS2_FEATURE_LEVEL_MAX_FEATURES, }; errcode_t ocfs2_snprint_feature_flags(char *str, size_t size, ocfs2_fs_options *flags); errcode_t ocfs2_snprint_tunefs_flags(char *str, size_t size, uint16_t flags); errcode_t ocfs2_snprint_extent_flags(char *str, size_t size, uint8_t flags); errcode_t ocfs2_snprint_refcount_flags(char *str, size_t size, uint8_t flags); errcode_t ocfs2_parse_feature(const char *opts, ocfs2_fs_options *feature_flags, ocfs2_fs_options *reverse_flags); errcode_t ocfs2_parse_feature_level(const char *typestr, enum ocfs2_feature_levels *level); errcode_t ocfs2_merge_feature_flags_with_level(ocfs2_fs_options *dest, enum ocfs2_mkfs_types fstype, int level, ocfs2_fs_options *feature_set, ocfs2_fs_options *reverse_set); /* * Get a callback with each feature in feature_set in order. This will * calculate the dependencies of each feature in feature_set, then call func * once per feature, with only that feature passed to func. */ void ocfs2_feature_foreach(ocfs2_fs_options *feature_set, int (*func)(ocfs2_fs_options *feature, void *user_data), void *user_data); /* The reverse function. It will call the features in reverse order. */ void ocfs2_feature_reverse_foreach(ocfs2_fs_options *reverse_set, int (*func)(ocfs2_fs_options *feature, void *user_data), void *user_data); /* These are deprecated names - don't use them */ int ocfs2_get_backup_super_offset(ocfs2_filesys *fs, uint64_t *blocks, size_t len); errcode_t ocfs2_refresh_backup_super(ocfs2_filesys *fs, uint64_t *blocks, size_t len); errcode_t ocfs2_set_backup_super(ocfs2_filesys *fs, uint64_t *blocks, size_t len); /* * ${foo}_to_${bar} is a floor function. blocks_to_clusters will * returns the cluster that contains a block, not the number of clusters * that hold a given number of blocks. * * ${foo}_in_${bar} is a ceiling function. clusters_in_blocks will give * the number of clusters needed to hold a given number of blocks. * * These functions return UINTxx_MAX when they overflow, but UINTxx_MAX * cannot be used to check overflow. UINTxx_MAX is a valid value in much * of ocfs2. The caller is responsible for preventing overflow before * using these functions. */ static inline uint64_t ocfs2_clusters_to_blocks(ocfs2_filesys *fs, uint32_t clusters) { int c_to_b_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits - OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; return (uint64_t)clusters << c_to_b_bits; } static inline uint32_t ocfs2_blocks_to_clusters(ocfs2_filesys *fs, uint64_t blocks) { int b_to_c_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits - OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; uint64_t ret = blocks >> b_to_c_bits; if (ret > UINT32_MAX) ret = UINT32_MAX; return (uint32_t)ret; } static inline uint64_t ocfs2_clusters_to_bytes(ocfs2_filesys *fs, uint32_t clusters) { uint64_t ret = clusters; ret = ret << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; if (ret < clusters) ret = UINT64_MAX; return ret; } static inline uint32_t ocfs2_bytes_to_clusters(ocfs2_filesys *fs, uint64_t bytes) { uint64_t ret = bytes >> OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; if (ret > UINT32_MAX) ret = UINT32_MAX; return (uint32_t)ret; } static inline uint64_t ocfs2_block_to_cluster_start(ocfs2_filesys *fs, uint64_t blocks) { int c_to_b_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits - OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; uint32_t clusters; clusters = ocfs2_blocks_to_clusters(fs, blocks); return (uint64_t)clusters << c_to_b_bits; } static inline uint64_t ocfs2_blocks_to_bytes(ocfs2_filesys *fs, uint64_t blocks) { uint64_t ret = blocks << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; if (ret < blocks) ret = UINT64_MAX; return ret; } static inline uint64_t ocfs2_bytes_to_blocks(ocfs2_filesys *fs, uint64_t bytes) { return bytes >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; } static inline uint32_t ocfs2_clusters_in_blocks(ocfs2_filesys *fs, uint64_t blocks) { int c_to_b_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits - OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; uint64_t ret = blocks + ((1 << c_to_b_bits) - 1); if (ret < blocks) /* deal with wrapping */ ret = UINT64_MAX; ret = ret >> c_to_b_bits; if (ret > UINT32_MAX) ret = UINT32_MAX; return (uint32_t)ret; } static inline uint32_t ocfs2_clusters_in_bytes(ocfs2_filesys *fs, uint64_t bytes) { uint64_t ret = bytes + fs->fs_clustersize - 1; if (ret < bytes) /* deal with wrapping */ ret = UINT64_MAX; ret = ret >> OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; if (ret > UINT32_MAX) ret = UINT32_MAX; return (uint32_t)ret; } static inline uint64_t ocfs2_blocks_in_bytes(ocfs2_filesys *fs, uint64_t bytes) { uint64_t ret = bytes + fs->fs_blocksize - 1; if (ret < bytes) /* deal with wrapping */ return UINT64_MAX; return ret >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; } static inline uint64_t ocfs2_align_bytes_to_clusters(ocfs2_filesys *fs, uint64_t bytes) { uint32_t clusters; clusters = ocfs2_clusters_in_bytes(fs, bytes); return (uint64_t)clusters << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; } static inline uint64_t ocfs2_align_bytes_to_blocks(ocfs2_filesys *fs, uint64_t bytes) { uint64_t blocks; blocks = ocfs2_blocks_in_bytes(fs, bytes); return blocks << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; } /* given a cluster offset, calculate which block group it belongs to * and return that block offset. */ static inline uint64_t ocfs2_which_cluster_group(ocfs2_filesys *fs, uint16_t cpg, uint32_t cluster) { struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super); uint32_t group_no; group_no = cluster / cpg; if (!group_no) return sb->s_first_cluster_group; return ocfs2_clusters_to_blocks(fs, group_no * cpg); } static inline int ocfs2_block_out_of_range(ocfs2_filesys *fs, uint64_t block) { return (block < OCFS2_SUPER_BLOCK_BLKNO) || (block > fs->fs_blocks); } struct ocfs2_cluster_group_sizes { uint16_t cgs_cpg; uint16_t cgs_tail_group_bits; uint32_t cgs_cluster_groups; }; static inline void ocfs2_calc_cluster_groups(uint64_t clusters, uint64_t blocksize, struct ocfs2_cluster_group_sizes *cgs) { uint16_t max_bits = 8 * ocfs2_group_bitmap_size(blocksize, 0, 0); cgs->cgs_cpg = max_bits; if (max_bits > clusters) cgs->cgs_cpg = clusters; cgs->cgs_cluster_groups = (clusters + cgs->cgs_cpg - 1) / cgs->cgs_cpg; cgs->cgs_tail_group_bits = clusters % cgs->cgs_cpg; if (cgs->cgs_tail_group_bits == 0) cgs->cgs_tail_group_bits = cgs->cgs_cpg; } /* * This is only valid for leaf nodes, which are the only ones that can * have empty extents anyway. */ static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec) { return !rec->e_leaf_clusters; } /* * Helper function to look at the # of clusters in an extent record. */ static inline uint32_t ocfs2_rec_clusters(uint16_t tree_depth, struct ocfs2_extent_rec *rec) { /* * Cluster count in extent records is slightly different * between interior nodes and leaf nodes. This is to support * unwritten extents which need a flags field in leaf node * records, thus shrinking the available space for a clusters * field. */ if (tree_depth) return rec->e_int_clusters; else return rec->e_leaf_clusters; } static inline void ocfs2_set_rec_clusters(uint16_t tree_depth, struct ocfs2_extent_rec *rec, uint32_t clusters) { if (tree_depth) rec->e_int_clusters = clusters; else rec->e_leaf_clusters = clusters; } static inline int ocfs2_sparse_alloc(struct ocfs2_super_block *osb) { if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) return 1; return 0; } static inline int ocfs2_userspace_stack(struct ocfs2_super_block *osb) { if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK) return 1; return 0; } static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super_block *osb) { /* * Support for sparse files is a pre-requisite */ if (!ocfs2_sparse_alloc(osb)) return 0; if (osb->s_feature_ro_compat & OCFS2_FEATURE_RO_COMPAT_UNWRITTEN) return 1; return 0; } static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super_block *osb) { if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP) return 1; return 0; } static inline int ocfs2_support_inline_data(struct ocfs2_super_block *osb) { if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA) return 1; return 0; } static inline int ocfs2_meta_ecc(struct ocfs2_super_block *osb) { if (OCFS2_HAS_INCOMPAT_FEATURE(osb, OCFS2_FEATURE_INCOMPAT_META_ECC)) return 1; return 0; } static inline int ocfs2_support_xattr(struct ocfs2_super_block *osb) { if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR) return 1; return 0; } static inline int ocfs2_supports_indexed_dirs(struct ocfs2_super_block *osb) { if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS) return 1; return 0; } /* * When we're swapping some of our disk structures, a garbage count * can send us past the edge of a block buffer. This function guards * against that. It returns true if the element would walk off then end * of the block buffer. */ static inline int ocfs2_swap_barrier(ocfs2_filesys *fs, void *block_buffer, void *element, size_t element_size) { char *limit, *end; limit = block_buffer; limit += fs->fs_blocksize; end = element; end += element_size; return end > limit; } static inline int ocfs2_refcount_tree(struct ocfs2_super_block *osb) { if (OCFS2_HAS_INCOMPAT_FEATURE(osb, OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE)) return 1; return 0; } static inline int ocfs2_supports_discontig_bg(struct ocfs2_super_block *osb) { if (OCFS2_HAS_INCOMPAT_FEATURE(osb, OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG)) return 1; return 0; } /* * shamelessly lifted from the kernel * * min()/max() macros that also do * strict type-checking.. See the * "unnecessary" pointer comparison. */ #define ocfs2_min(x,y) ({ \ const typeof(x) _x = (x); \ const typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) #define ocfs2_max(x,y) ({ \ const typeof(x) _x = (x); \ const typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) /* lifted from the kernel. include/linux/kernel.h */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* * DEPRECATED: Extent/block iterate functions. * * Do not use these for reading/writing regular files - they don't properly * handle holes or inline data. */ /* Return flags for the extent iterator functions */ #define OCFS2_EXTENT_CHANGED 0x01 #define OCFS2_EXTENT_ABORT 0x02 #define OCFS2_EXTENT_ERROR 0x04 /* * Extent iterate flags * * OCFS2_EXTENT_FLAG_APPEND indicates that the iterator function should * be called on extents past the leaf next_free_rec. This is used by * ocfs2_expand_dir() to add a new extent to a directory (via * OCFS2_BLOCK_FLAG_APPEND and the block iteration functions). * * OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE indicates that the iterator * function for tree_depth > 0 records (ocfs2_extent_blocks, iow) * should be called after all of the extents contained in the * extent_block are processed. This is useful if you are going to be * deallocating extents. * * OCFS2_EXTENT_FLAG_DATA_ONLY indicates that the iterator function * should be called for data extents (depth == 0) only. */ #define OCFS2_EXTENT_FLAG_APPEND 0x01 #define OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE 0x02 #define OCFS2_EXTENT_FLAG_DATA_ONLY 0x04 /* Return flags for the block iterator functions */ #define OCFS2_BLOCK_CHANGED 0x01 #define OCFS2_BLOCK_ABORT 0x02 #define OCFS2_BLOCK_ERROR 0x04 #define OCFS2_IS_VALID_DX_ROOT(ptr) \ (!strcmp((char *)(ptr)->dr_signature, OCFS2_DX_ROOT_SIGNATURE)) /* * Block iterate flags * * In OCFS2, block iteration runs through the blocks contained in an * inode's data extents. As such, "DATA_ONLY" and "DEPTH_TRAVERSE" * can't really apply. * * OCFS2_BLOCK_FLAG_APPEND is as OCFS2_EXTENT_FLAG_APPEND, except on a * blocksize basis. This may mean that the underlying extent already * contains the space for a new block, and i_size is updated * accordingly. */ #define OCFS2_BLOCK_FLAG_APPEND 0x01 errcode_t ocfs2_extent_iterate(ocfs2_filesys *fs, uint64_t blkno, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data); errcode_t ocfs2_extent_iterate_inode(ocfs2_filesys *fs, struct ocfs2_dinode *inode, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data); errcode_t ocfs2_extent_iterate_dx_root(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data); errcode_t ocfs2_block_iterate(ocfs2_filesys *fs, uint64_t blkno, int flags, int (*func)(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data), void *priv_data); errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs, struct ocfs2_dinode *inode, int flags, int (*func)(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data), void *priv_data); #define OCFS2_XATTR_ABORT 0x01 #define OCFS2_XATTR_ERROR 0x02 errcode_t ocfs2_xattr_iterate(ocfs2_cached_inode *ci, int (*func)(ocfs2_cached_inode *ci, char *xe_buf, uint64_t xe_blkno, struct ocfs2_xattr_entry *xe, char *value_buf, uint64_t value_blkno, void *value, int in_bucket, void *priv_data), void *priv_data); uint32_t ocfs2_xattr_uuid_hash(unsigned char *uuid); uint32_t ocfs2_xattr_name_hash(uint32_t uuid_hash, const char *name, int name_len); int ocfs2_tree_find_leaf(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t el_blkno, char *el_blk, uint32_t cpos, char **leaf_buf); uint16_t ocfs2_xattr_buckets_per_cluster(ocfs2_filesys *fs); uint16_t ocfs2_blocks_per_xattr_bucket(ocfs2_filesys *fs); /* See ocfs2_swap_extent_list() for a discussion of obj */ void ocfs2_swap_xattrs_to_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_xattr_header *xh); void ocfs2_swap_xattrs_from_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_xattr_header *xh); void ocfs2_swap_xattr_block_to_cpu(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb); void ocfs2_swap_xattr_block_from_cpu(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb); errcode_t ocfs2_read_xattr_block(ocfs2_filesys *fs, uint64_t blkno, char *xb_buf); errcode_t ocfs2_write_xattr_block(ocfs2_filesys *fs, uint64_t blkno, char *xb_buf); errcode_t ocfs2_xattr_get_rec(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb, uint32_t name_hash, uint64_t *p_blkno, uint32_t *e_cpos, uint32_t *num_clusters); uint16_t ocfs2_xattr_value_real_size(uint16_t name_len, uint16_t value_len); uint16_t ocfs2_xattr_min_offset(struct ocfs2_xattr_header *xh, uint16_t size); uint16_t ocfs2_xattr_name_value_len(struct ocfs2_xattr_header *xh); errcode_t ocfs2_read_xattr_bucket(ocfs2_filesys *fs, uint64_t blkno, char *bucket_buf); errcode_t ocfs2_write_xattr_bucket(ocfs2_filesys *fs, uint64_t blkno, char *bucket_buf); errcode_t ocfs2_xattr_value_truncate(ocfs2_filesys *fs, uint64_t ino, struct ocfs2_xattr_value_root *xv); errcode_t ocfs2_xattr_tree_truncate(ocfs2_filesys *fs, struct ocfs2_xattr_tree_root *xt); errcode_t ocfs2_extent_iterate_xattr(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t last_eb_blk, int flags, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data, int *changed); errcode_t ocfs2_delete_xattr_block(ocfs2_filesys *fs, uint64_t blkno); errcode_t ocfs2_dir_indexed_tree_truncate(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root); errcode_t ocfs2_write_dx_root(ocfs2_filesys *fs, uint64_t block, char *buf); errcode_t ocfs2_write_dx_leaf(ocfs2_filesys *fs, uint64_t block, void *buf); errcode_t ocfs2_dx_dir_build(ocfs2_filesys *fs, uint64_t dir); errcode_t ocfs2_dx_dir_insert_entry(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, uint64_t blkno); int ocfs2_search_dirblock(ocfs2_filesys *fs, char *dir_buf, const char *name, int namelen, unsigned int bytes, struct ocfs2_dir_entry **res_dir); void ocfs2_dx_dir_name_hash(ocfs2_filesys *fs, const char *name, int len, struct ocfs2_dx_hinfo *hinfo); errcode_t ocfs2_dx_dir_lookup(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, struct ocfs2_extent_list *el, struct ocfs2_dx_hinfo *hinfo, uint32_t *ret_cpos, uint64_t *ret_phys_blkno); errcode_t ocfs2_dx_dir_search(ocfs2_filesys *fs, const char *name, int namelen, struct ocfs2_dx_root_block *dx_root, struct ocfs2_dir_lookup_result *res); void release_lookup_res(struct ocfs2_dir_lookup_result *res); int ocfs2_find_max_rec_len(ocfs2_filesys *fs, char *buf); void ocfs2_dx_list_remove_entry(struct ocfs2_dx_entry_list *entry_list, int index); int ocfs2_is_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, unsigned long de_off); /* routines for block check */ uint32_t ocfs2_hamming_encode(uint32_t parity, void *data, unsigned int d, unsigned int nr); uint32_t ocfs2_hamming_encode_block(void *data, unsigned int d); void ocfs2_hamming_fix(void *data, unsigned int d, unsigned int nr, unsigned int fix); void ocfs2_hamming_fix_block(void *data, unsigned int d, unsigned int fix); uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len); #endif /* _FILESYS_H */ ./ocfs2-tools-1.6.4/include/ocfs2/jbd2.h0000664000176100017610000001205311170734140014410 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * jbd2.h * * header file extracted from linux/include/linux/jbd2.h * * Originally written by Stephen C. Tweedie * * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * Definitions for transaction data structures for the buffer cache * filesystem journaling support. */ #ifndef _JBD2_H_ #define _JBD2_H_ /* * Internal structures used by the logging mechanism: */ #define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ /* * On-disk structures */ /* * Descriptor block types: */ #define JBD2_DESCRIPTOR_BLOCK 1 #define JBD2_COMMIT_BLOCK 2 #define JBD2_SUPERBLOCK_V1 3 #define JBD2_SUPERBLOCK_V2 4 #define JBD2_REVOKE_BLOCK 5 /* * Standard header for all descriptor blocks: */ typedef struct journal_header_s { __be32 h_magic; __be32 h_blocktype; __be32 h_sequence; } journal_header_t; /* * Checksum types. */ #define JBD2_CRC32_CHKSUM 1 #define JBD2_MD5_CHKSUM 2 #define JBD2_SHA2_CHKSUM 3 #define JBD2_CRC32_CHKSUM_SIZE 4 #define JBD2_CHECKSUM_BYTES (32 / sizeof(uint32_t)) /* * Commit block header for storing transactional checksums: */ struct commit_header { __be32 h_magic; __be32 h_blocktype; __be32 h_sequence; unsigned char h_chksum_type; unsigned char h_chksum_size; unsigned char h_padding[2]; __be32 h_chksum[JBD2_CHECKSUM_BYTES]; __be64 h_commit_sec; __be32 h_commit_nsec; }; /* * The block tag: used to describe a single buffer in the journal. * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this * raw struct shouldn't be used for pointer math or sizeof() - use * journal_tag_bytes(journal) instead to compute this. */ typedef struct journal_block_tag_s { __be32 t_blocknr; /* The on-disk block number */ __be32 t_flags; /* See below */ __be32 t_blocknr_high; /* most-significant high 32bits. */ } journal_block_tag_t; #define JBD2_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high)) #define JBD2_TAG_SIZE64 (sizeof(journal_block_tag_t)) /* * The revoke descriptor: used on disk to describe a series of blocks to * be revoked from the log */ typedef struct journal_revoke_header_s { journal_header_t r_header; int r_count; /* Count of bytes used in the block */ } journal_revoke_header_t; /* Definitions for the journal tag flags word: */ #define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */ #define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */ #define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */ #define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ /* * The journal superblock. All fields are in big-endian byte order. */ typedef struct journal_superblock_s { /* 0x0000 */ journal_header_t s_header; /* 0x000C */ /* Static information describing the journal */ __be32 s_blocksize; /* journal device blocksize */ __be32 s_maxlen; /* total blocks in journal file */ __be32 s_first; /* first block of log information */ /* 0x0018 */ /* Dynamic information describing the current state of the log */ __be32 s_sequence; /* first commit ID expected in log */ __be32 s_start; /* blocknr of start of log */ /* 0x0020 */ /* Error value, as set by jbd2_journal_abort(). */ __be32 s_errno; /* 0x0024 */ /* Remaining fields are only valid in a version-2 superblock */ __be32 s_feature_compat; /* compatible feature set */ __be32 s_feature_incompat; /* incompatible feature set */ __be32 s_feature_ro_compat; /* readonly-compatible feature set */ /* 0x0030 */ __u8 s_uuid[16]; /* 128-bit uuid for journal */ /* 0x0040 */ __be32 s_nr_users; /* Nr of filesystems sharing log */ __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ /* 0x0048 */ __be32 s_max_transaction; /* Limit of journal blocks per trans.*/ __be32 s_max_trans_data; /* Limit of data blocks per trans. */ /* 0x0050 */ __be32 s_padding[44]; /* 0x0100 */ __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ /* 0x0400 */ } journal_superblock_t; #define JBD2_HAS_COMPAT_FEATURE(jsb,mask) \ (((jsb)->s_header.h_blocktype == JBD2_SUPERBLOCK_V2) && \ ((jsb)->s_feature_compat & mask)) #define JBD2_HAS_RO_COMPAT_FEATURE(jsb,mask) \ (((jsb)->s_header.h_blocktype == JBD2_SUPERBLOCK_V2) && \ ((jsb)->s_feature_ro_compat & mask)) #define JBD2_HAS_INCOMPAT_FEATURE(jsb,mask) \ (((jsb)->s_header.h_blocktype == JBD2_SUPERBLOCK_V2) && \ ((jsb)->s_feature_incompat & mask)) #define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001 #define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 #define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 #define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 /* Features known to this kernel version: */ #define JBD2_KNOWN_COMPAT_FEATURES 0 #define JBD2_KNOWN_ROCOMPAT_FEATURES 0 #define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE \ | JBD2_FEATURE_INCOMPAT_64BIT) #endif /* _JBD2_H_ */ ./ocfs2-tools-1.6.4/include/ocfs2/bitops.h0000644000176100017610000000300511500500544015056 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * bitops.h * * Bitmap frobbing routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker * * This code is a port of e2fsprogs/lib/ext2fs/bitops.h * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #ifndef _BITOPS_H #define _BITOPS_H extern int ocfs2_set_bit(int nr,void * addr); extern int ocfs2_clear_bit(int nr, void * addr); extern int ocfs2_test_bit(int nr, const void * addr); extern int ocfs2_find_first_bit_set(void *addr, int size); extern int ocfs2_find_first_bit_clear(void *addr, int size); extern int ocfs2_find_next_bit_set(void *addr, int size, int offset); extern int ocfs2_find_next_bit_clear(void *addr, int size, int offset); extern int ocfs2_get_bits_set(void *addr, int size, int offset); #endif ./ocfs2-tools-1.6.4/include/ocfs2/byteorder.h0000644000176100017610000000612211115551035015563 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * byteorder.h * * Byteswapping! * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker */ #ifndef _BYTEORDER_H #define _BYTEORDER_H #include #include #include /* * All OCFS2 on-disk values are in little endian, except for jbd's journal * fields which it takes care of itself. */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_is_little_endian 1 # ifndef cpu_to_le16 # define cpu_to_le16(x) ((uint16_t)(x)) # endif # ifndef le16_to_cpu # define le16_to_cpu(x) ((uint16_t)(x)) # endif # ifndef cpu_to_le32 # define cpu_to_le32(x) ((uint32_t)(x)) # endif # ifndef le32_to_cpu # define le32_to_cpu(x) ((uint32_t)(x)) # endif # ifndef cpu_to_le64 # define cpu_to_le64(x) ((uint64_t)(x)) # endif # ifndef le64_to_cpu # define le64_to_cpu(x) ((uint64_t)(x)) # endif # ifndef cpu_to_be16 # define cpu_to_be16(x) ((uint16_t)bswap_16(x)) # endif # ifndef be16_to_cpu # define be16_to_cpu(x) ((uint16_t)bswap_16(x)) # endif # ifndef cpu_to_be32 # define cpu_to_be32(x) ((uint32_t)bswap_32(x)) # endif # ifndef be32_to_cpu # define be32_to_cpu(x) ((uint32_t)bswap_32(x)) # endif # ifndef cpu_to_be64 # define cpu_to_be64(x) ((uint64_t)bswap_64(x)) # endif # ifndef be64_to_cpu # define be64_to_cpu(x) ((uint64_t)bswap_64(x)) # endif #elif __BYTE_ORDER == __BIG_ENDIAN #define cpu_is_little_endian 0 # ifndef cpu_to_le16 # define cpu_to_le16(x) ((uint16_t)bswap_16(x)) # endif # ifndef le16_to_cpu # define le16_to_cpu(x) ((uint16_t)bswap_16(x)) # endif # ifndef cpu_to_le32 # define cpu_to_le32(x) ((uint32_t)bswap_32(x)) # endif # ifndef le32_to_cpu # define le32_to_cpu(x) ((uint32_t)bswap_32(x)) # endif # ifndef cpu_to_le64 # define cpu_to_le64(x) ((uint64_t)bswap_64(x)) # endif # ifndef le64_to_cpu # define le64_to_cpu(x) ((uint64_t)bswap_64(x)) # endif # ifndef cpu_to_be16 # define cpu_to_be16(x) ((uint16_t)(x)) # endif # ifndef be16_to_cpu # define be16_to_cpu(x) ((uint16_t)(x)) # endif # ifndef cpu_to_be32 # define cpu_to_be32(x) ((uint32_t)(x)) # endif # ifndef be32_to_cpu # define be32_to_cpu(x) ((uint32_t)(x)) # endif # ifndef cpu_to_be64 # define cpu_to_be64(x) ((uint64_t)(x)) # endif # ifndef be64_to_cpu # define be64_to_cpu(x) ((uint64_t)(x)) # endif #else # error Invalid byte order __BYTE_ORDER #endif /* __BYTE_ORDER */ #define cpu_is_big_endian (!cpu_is_little_endian) #endif /* _BYTEORDER_H */ ./ocfs2-tools-1.6.4/include/ocfs2/kernel-rbtree.h0000644000176100017610000000770011115551035016330 00000000000000/* Red Black Trees (C) 1999 Andrea Arcangeli 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 rbtree.h To use rbtrees you'll have to implement your own insert and search cores. This will avoid us to use callbacks and to drop drammatically performances. I know it's not the cleaner way, but in C (not in C++) to get performances and genericity... Some example of insert and search follows here. The search is a plain normal search over an ordered tree. The insert instead must be implemented int two steps: as first thing the code must insert the element in order as a red leaf in the tree, then the support library function rb_insert_color() must be called. Such function will do the not trivial work to rebalance the rbtree if necessary. ----------------------------------------------------------------------- static inline struct page * rb_search_page_cache(struct inode * inode, unsigned long offset) { struct rb_node * n = inode->i_rb_page_cache.rb_node; struct page * page; while (n) { page = rb_entry(n, struct page, rb_page_cache); if (offset < page->offset) n = n->rb_left; else if (offset > page->offset) n = n->rb_right; else return page; } return NULL; } static inline struct page * __rb_insert_page_cache(struct inode * inode, unsigned long offset, struct rb_node * node) { struct rb_node ** p = &inode->i_rb_page_cache.rb_node; struct rb_node * parent = NULL; struct page * page; while (*p) { parent = *p; page = rb_entry(parent, struct page, rb_page_cache); if (offset < page->offset) p = &(*p)->rb_left; else if (offset > page->offset) p = &(*p)->rb_right; else return page; } rb_link_node(node, parent, p); return NULL; } static inline struct page * rb_insert_page_cache(struct inode * inode, unsigned long offset, struct rb_node * node) { struct page * ret; if ((ret = __rb_insert_page_cache(inode, offset, node))) goto out; rb_insert_color(node, &inode->i_rb_page_cache); out: return ret; } ----------------------------------------------------------------------- */ #ifndef _LINUX_RBTREE_H #define _LINUX_RBTREE_H #include struct rb_node { struct rb_node *rb_parent; int rb_color; #define RB_RED 0 #define RB_BLACK 1 struct rb_node *rb_right; struct rb_node *rb_left; }; struct rb_root { struct rb_node *rb_node; }; #define RB_ROOT (struct rb_root) { NULL, } #define rb_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) extern void rb_insert_color(struct rb_node *, struct rb_root *); extern void rb_erase(struct rb_node *, struct rb_root *); /* Find logical next and previous nodes in a tree */ extern struct rb_node *rb_next(struct rb_node *); extern struct rb_node *rb_prev(struct rb_node *); extern struct rb_node *rb_first(struct rb_root *); extern struct rb_node *rb_last(struct rb_root *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, struct rb_node ** rb_link) { node->rb_parent = parent; node->rb_color = RB_RED; node->rb_left = node->rb_right = NULL; *rb_link = node; } #endif /* _LINUX_RBTREE_H */ ./ocfs2-tools-1.6.4/include/ocfs2/image.h0000644000176100017610000001036711115551035014654 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * image.h * * Header file describing image disk/memory structures for ocfs2 image * * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ /* * o2image is an ocfs2 tool to save critical ocfs2 filesystem metadata to a * specified image-file. Image-file may be examined using debugfs.ocfs2 or * may be used to restore using o2image. Image-file can be of two formats: * * 1. Packed - This format(default) contains a ocfs2 image header, packed * metadata blocks and a bitmap. * 2. raw - A raw image is a sparse file containing the metadata blocks. * * Usage: o2image [-rI] * * Packed format contains bitmap towards the end of the image-file. Each bit in * the bitmap represents a block in the filesystem. * * When the packed image is opened using o2image or debugfs.ocfs2, bitmap is * loaded into memory and used to map disk blocks to image blocks. * * Raw image is a sparse file containing metadata blocks at the same offset as * the filesystem. * * debugfs.ocfs2 is modified to detect image-file when the image-file is * specified with -i option. */ #define OCFS2_IMAGE_MAGIC 0x72a3d45f #define OCFS2_IMAGE_DESC "OCFS2 IMAGE" #define OCFS2_IMAGE_VERSION 1 #define OCFS2_IMAGE_READ_CHAIN_NO 0 #define OCFS2_IMAGE_READ_INODE_NO 1 #define OCFS2_IMAGE_READ_INODE_YES 2 #define OCFS2_IMAGE_BITMAP_BLOCKSIZE 4096 #define OCFS2_IMAGE_BITS_IN_BLOCK (OCFS2_IMAGE_BITMAP_BLOCKSIZE * 8) /* on disk ocfs2 image header format */ struct ocfs2_image_hdr { __le32 hdr_magic; __le32 hdr_timestamp; /* Time of image creation */ __u8 hdr_magic_desc[16]; /* "OCFS2 IMAGE" */ __le64 hdr_version; /* ocfs2 image version */ __le64 hdr_fsblkcnt; /* blocks in filesystem */ __le64 hdr_fsblksz; /* Filesystem block size */ __le64 hdr_imgblkcnt; /* Filesystem blocks in image */ __le64 hdr_bmpblksz; /* bitmap block size */ __le64 hdr_superblkcnt; /* number of super blocks */ __le64 hdr_superblocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; }; /* * array to hold pointers to bitmap blocks. arr_set_bit_cnt holds cumulative * count of bits used previous to the current block. arr_self will be pointing * to the memory chunks allocated. arr_map will be pointing to bitmap blocks * of size OCFS2_IMAGE_BITMAP_BLOCKSIZE. Each block maps to * OCFS2_IMAGE_BITS_IN_BLOCK number of filesystem blocks. */ struct _ocfs2_image_bitmap_arr { uint64_t arr_set_bit_cnt; char *arr_self; char *arr_map; }; typedef struct _ocfs2_image_bitmap_arr ocfs2_image_bitmap_arr; /* ocfs2 image state holds runtime values */ struct ocfs2_image_state { uint64_t ost_fsblksz; uint64_t ost_fsblkcnt; uint64_t ost_imgblkcnt; /* filesystem blocks in image */ uint64_t ost_glbl_bitmap_inode; uint64_t ost_glbl_inode_alloc; uint64_t *ost_inode_allocs; /* holds inode_alloc inodes */ uint64_t ost_bmpblks; /* blocks that store bitmaps */ uint64_t ost_bmpblksz; /* size of each bitmap blk */ uint64_t ost_superblocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; int ost_glbl_inode_traversed; int ost_bpc; /* blocks per cluster */ int ost_superblkcnt; /* number of super blocks */ ocfs2_image_bitmap_arr *ost_bmparr; /* points to bitmap blocks */ }; errcode_t ocfs2_image_load_bitmap(ocfs2_filesys *ofs); errcode_t ocfs2_image_free_bitmap(ocfs2_filesys *ofs); errcode_t ocfs2_image_alloc_bitmap(ocfs2_filesys *ofs); void ocfs2_image_mark_bitmap(ocfs2_filesys *ofs, uint64_t blkno); int ocfs2_image_test_bit(ocfs2_filesys *ofs, uint64_t blkno); uint64_t ocfs2_image_get_blockno(ocfs2_filesys *ofs, uint64_t blkno); void ocfs2_image_swap_header(struct ocfs2_image_hdr *hdr); ./ocfs2-tools-1.6.4/libtools-internal/0000775000176100017610000000000011515641640014504 500000000000000./ocfs2-tools-1.6.4/libtools-internal/Makefile0000664000176100017610000000160111506552637016071 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make INCLUDES = -I. -I$(TOPDIR)/include UNINST_LIBRARIES = libtools-internal.a CFLAGS += -fPIC DEFINES += -DVERSION=\"$(VERSION)\" ifneq ($(OCFS2_DEBUG_EXE),) DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES)) DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES))) .SECONDARY: UNINST_PROGRAMS += $(DEBUG_EXE_PROGRAMS) debug_%.o : %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) \ $(INCLUDES) $(DEFINES) \ -DDEBUG_EXE -o $@ -c $< debug_%: debug_%.o $(LINK) $(COM_ERR_LIBS) endif CFILES = verbose.c progress.c HFILES = libtools-internal.h OBJS = $(subst .c,.o,$(CFILES)) $(OBJS): $(HFILES) $(HFILES_GEN) libtools-internal.a: $(OBJS) rm -f $@ $(AR) r $@ $^ $(RANLIB) $@ DIST_FILES = $(CFILES) $(HFILES) include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/libtools-internal/verbose.c0000664000176100017610000001043511170734140016233 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * verbose.c * * Internal routines for verbose output. * * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #define _LARGEFILE64_SOURCE #define _GNU_SOURCE /* for getopt_long and O_DIRECT */ #include #include #include #include #include #include #include #include "tools-internal/verbose.h" #include "tools-internal/progress.h" #include "libtools-internal.h" static char progname[PATH_MAX] = "(Unknown)"; static int verbosity = 1; static int interactive = 0; static int interactive_answer = 0; void tools_setup_argv0(const char *argv0) { char *pname; char pathtmp[PATH_MAX]; /* This shouldn't care which basename(3) we get */ snprintf(pathtmp, PATH_MAX, "%s", argv0); pname = basename(pathtmp); snprintf(progname, PATH_MAX, "%s", pname); } /* If all verbosity is turned off, make sure com_err() prints nothing. */ static void quiet_com_err(const char *prog, long errcode, const char *fmt, va_list args) { return; } void tools_verbose(void) { verbosity++; if (verbosity == 1) reset_com_err_hook(); } void tools_quiet(void) { if (verbosity == 1) set_com_err_hook(quiet_com_err); verbosity--; } int tools_verbosity(void) { return verbosity; } static void vfverbosef(FILE *f, int level, const char *fmt, va_list args) { if (level <= verbosity) { tools_progress_clear(); vfprintf(f, fmt, args); tools_progress_restore(); } } static void fverbosef(FILE *f, int level, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); static void fverbosef(FILE *f, int level, const char *fmt, ...) { va_list args; va_start(args, fmt); vfverbosef(f, level, fmt, args); va_end(args); } void verbosef(enum tools_verbosity_level level, const char *fmt, ...) { va_list args; FILE *f = stderr; if (level & VL_FLAG_STDOUT) { f = stdout; level &= ~VL_FLAG_STDOUT; } va_start(args, fmt); vfverbosef(f, level, fmt, args); va_end(args); } void errorf(const char *fmt, ...) { va_list args; va_start(args, fmt); fverbosef(stderr, VL_ERR, "%s: ", progname); vfverbosef(stderr, VL_ERR, fmt, args); va_end(args); } void tcom_err(errcode_t code, const char *fmt, ...) { va_list args; tools_progress_clear(); va_start(args, fmt); com_err_va(progname, code, fmt, args); va_end(args); tools_progress_restore(); } static int vtools_interact(enum tools_verbosity_level level, const char *fmt, va_list args) { char *s, buffer[NAME_MAX]; int progress_enabled = tools_progress_enabled(); if (progress_enabled) { tools_progress_clear(); tools_progress_disable(); } vfverbosef(stderr, level, fmt, args); if (interactive_answer) { fverbosef(stderr, level, "%c\n", interactive_answer); sprintf(buffer, "%c", interactive_answer); s = buffer; } else s = fgets(buffer, sizeof(buffer), stdin); if (progress_enabled) { tools_progress_enable(); tools_progress_restore(); } if (s && *s) { *s = tolower(*s); if (*s == 'y') return 1; } return 0; } void tools_interactive(void) { interactive = 1; } void tools_interactive_yes(void) { interactive_answer = 'y'; } void tools_interactive_no(void) { interactive_answer = 'n'; } int tools_is_interactive(void) { return interactive; } /* Pass this a question without a newline. */ int tools_interact(const char *fmt, ...) { int rc; va_list args; if (!interactive) return 1; va_start(args, fmt); rc = vtools_interact(VL_ERR, fmt, args); va_end(args); return rc; } /* Only for "DON'T DO THIS WITHOUT REALLY CHECKING!" stuff */ int tools_interact_critical(const char *fmt, ...) { int rc; va_list args; va_start(args, fmt); rc = vtools_interact(VL_CRIT, fmt, args); va_end(args); return rc; } void tools_version(void) { verbosef(VL_ERR, "%s %s\n", progname, VERSION); } const char *tools_progname(void) { return progname; } ./ocfs2-tools-1.6.4/libtools-internal/progress.c0000644000176100017610000003170311303077575016443 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * progress.c * * Internal routines progress output. * * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include "ocfs2-kernel/kernel-list.h" #include "tools-internal/progress.h" #include "libtools-internal.h" enum progress_length { PROGRESS_TRUNC, PROGRESS_SHORT, PROGRESS_LONG, }; #define TRUNC_LEN 3 #define PERCENTAGE_LEN 5 #define SPINNER_LEN 2 struct tools_progress { struct list_head p_list; enum progress_length p_len; char *p_long_name; unsigned int p_long_name_len; char *p_short_name; unsigned int p_short_name_len; uint64_t p_current; uint64_t p_count; unsigned int p_percent; int p_spinner_pos; }; #define PROGRESS_OPEN "[" #define PROGRESS_SEP " > " #define PROGRESS_CLOSE "]" #define PROGRESS_ELIPS "... " static const char spinner[] = "\\|/-"; static char nextline; static LIST_HEAD(progresses); /* When did we last update the progress */ static unsigned int last_tick; /* Are we displaying progress statistics */ static int progress_on = 0; /* A fake progress structure to pass around when we're disabled */ static struct tools_progress disabled_prog; /* * A buffer for storing the current progress output. That way, we can * replay it. * * If the terminal is 80 characters or less, or we can't allocate an * appropriately sized progbuf, we use a static one. The extra 2 characters * are for nextline and the NUL. */ #define DEFAULT_WIDTH 80 #define PROGBUF_EXTRA 2 static char static_progbuf[DEFAULT_WIDTH + PROGBUF_EXTRA]; static char *progbuf = static_progbuf; static unsigned int progbuf_len = DEFAULT_WIDTH + PROGBUF_EXTRA; /* * If we've updated the progress within the last 1/8th of a second, there * is no point in doing it again. Tick algorithm stolen from e2fsck. */ static int check_tick(void) { unsigned int tick; struct timeval tv; gettimeofday(&tv, NULL); tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8)); if (tick == last_tick) return 0; last_tick = tick; return 1; } static unsigned int calc_percent(uint64_t num, uint64_t dem) { double percent = ((double)num) / ((double)dem); return (unsigned int)((100.0 * percent) + 0.5); } /* If the visual percentage hasn't change, there's no point in updating. */ static int check_percent(struct tools_progress *prog) { unsigned int new_percent; /* An unbounded progress always steps */ if (!prog->p_count) return 1; if (prog->p_current >= prog->p_count) prog->p_current = prog->p_count; new_percent = calc_percent(prog->p_current, prog->p_count); if (new_percent == prog->p_percent) return 0; prog->p_percent = new_percent; return 1; } static void step_spinner(struct tools_progress *prog) { prog->p_spinner_pos = (prog->p_spinner_pos + 1) & 3; } static void progress_length_reset(void) { struct list_head *p; struct tools_progress *prog; list_for_each(p, &progresses) { prog = list_entry(p, struct tools_progress, p_list); prog->p_len = PROGRESS_LONG; } } static size_t length_one_prog(struct tools_progress *prog) { size_t len = 0; switch (prog->p_len) { case PROGRESS_LONG: len += prog->p_long_name_len; break; case PROGRESS_SHORT: len += prog->p_short_name_len; break; case PROGRESS_TRUNC: len += TRUNC_LEN; break; default: assert(0); break; } if (prog->p_count) len += PERCENTAGE_LEN; else len += SPINNER_LEN; return len; } static unsigned int progress_length_check(void) { unsigned int len = 0; int first = 1; struct list_head *p; struct tools_progress *prog; assert(!list_empty(&progresses)); list_for_each(p, &progresses) { prog = list_entry(p, struct tools_progress, p_list); if (first) { len += strlen(PROGRESS_OPEN); first = 0; } else len += strlen(PROGRESS_SEP); len += length_one_prog(prog); } len += strlen(PROGRESS_CLOSE); return len; } static int progress_length_shrink(void) { struct list_head *p; struct tools_progress *prog = NULL; enum progress_length len = PROGRESS_LONG; /* * We start from the longest length. We lower that max length * if we see a shorter one. When we then see the boundary (a * longer length after a shorter one), we break out. */ list_for_each(p, &progresses) { prog = list_entry(p, struct tools_progress, p_list); if (len > prog->p_len) len = prog->p_len; else if (len < prog->p_len) break; prog = NULL; } /* * If there was no boundary, all progresses had the same length. * shrink the first one. */ if (!prog) prog = list_entry(progresses.next, struct tools_progress, p_list); /* * If the one we want to shrink already is at PROGRESS_TRUNC, we * can shrink no more. Return false. */ if (prog->p_len == PROGRESS_TRUNC) return 0; prog->p_len--; return 1; } static unsigned int check_display(void) { char *cols = getenv("COLUMNS"); char *tmpbuf; unsigned int tmp, columns = DEFAULT_WIDTH; if (cols) { tmp = atoi(cols); if (tmp) columns = tmp; } tmp = columns + PROGBUF_EXTRA; /* Do we need more space for this width? */ if (tmp > progbuf_len) { tmpbuf = malloc(sizeof(char) * tmp); if (tmpbuf) { progbuf_len = tmp; memset(tmpbuf, 0, tmp); if (progbuf != static_progbuf) free(progbuf); progbuf = tmpbuf; /* * We just grew the buffer, so try long progress * output again. */ progress_length_reset(); } else { /* * We couldn't allocate enough space, so report * what we can actually use. */ columns = progbuf_len - PROGBUF_EXTRA; } } return columns; } static size_t print_one_prog(struct tools_progress *prog, char *buf, size_t len) { int offset = 0; size_t ret; switch (prog->p_len) { case PROGRESS_LONG: ret = snprintf(buf + offset, len - offset, "%s", prog->p_long_name); break; case PROGRESS_SHORT: ret = snprintf(buf + offset, len - offset, "%s", prog->p_short_name); break; case PROGRESS_TRUNC: ret = snprintf(buf + offset, len - offset, "%.*s", TRUNC_LEN, prog->p_short_name); break; default: assert(0); break; } offset += ret; if (prog->p_count) ret = snprintf(buf + offset, len - offset, " %3u%%", prog->p_percent); else ret = snprintf(buf + offset, len - offset, " %c", spinner[prog->p_spinner_pos & 3]); offset += ret; return offset; } static void print_trailer(char *buf, size_t len) { size_t ret; unsigned int offset = 0; ret = snprintf(buf + offset, len - offset, "%s", PROGRESS_CLOSE); offset += ret; assert(offset <= len); ret = snprintf(buf + offset, len - offset, "%c", nextline); assert(ret < (len - offset)); } static void progress_printf(unsigned int columns) { unsigned int offset = 0; size_t ret; int first = 1; struct list_head *p; struct tools_progress *prog = NULL; if (list_empty(&progresses)) return; list_for_each(p, &progresses) { prog = list_entry(p, struct tools_progress, p_list); if (first) { ret = snprintf(progbuf + offset, columns - offset, "%s", PROGRESS_OPEN); first = 0; } else ret = snprintf(progbuf + offset, columns - offset, "%s", PROGRESS_SEP); offset += ret; offset += print_one_prog(prog, progbuf + offset, columns - offset); assert(offset < columns); } /* * From here on out, we use progbuf_len instead of columns. Our * earlier calculations should have gotten this right. */ assert(offset < columns); print_trailer(progbuf + offset, progbuf_len - offset); } static void truncate_printf(unsigned int columns) { struct tools_progress *last = list_entry(progresses.prev, struct tools_progress, p_list); size_t ret, len = length_one_prog(last); unsigned int offset = 0; if ((len + strlen(PROGRESS_CLOSE) + strlen(PROGRESS_ELIPS)) <= columns) { ret = snprintf(progbuf + offset, columns - offset, "%s", PROGRESS_ELIPS); offset += ret; ret = print_one_prog(last, progbuf + offset, columns - offset); offset += ret; assert(offset < columns); print_trailer(progbuf + offset, progbuf_len - offset); } else { /* Give up, no progress */ progbuf[0] = '\0'; } } static void progress_compute(void) { unsigned int columns = check_display(); int truncate = 0; while (progress_length_check() > columns) { truncate = !progress_length_shrink(); if (truncate) break; } if (truncate) truncate_printf(columns); else progress_printf(columns); } static void progress_clear(void) { unsigned int columns = check_display(); memset(progbuf, ' ', columns); snprintf(progbuf + columns, progbuf_len - columns, "%c", nextline); } static void progress_write(void) { printf("%s", progbuf); } static void tools_progress_free(struct tools_progress *prog) { if (prog->p_long_name) free(prog->p_long_name); if (prog->p_short_name) free(prog->p_short_name); free(prog); } static struct tools_progress *tools_progress_alloc(const char *long_name, const char *short_name, uint64_t count) { struct tools_progress *prog; prog = malloc(sizeof(struct tools_progress)); if (!prog) goto out; memset(prog, 0, sizeof(struct tools_progress)); prog->p_long_name = strdup(long_name ? long_name : ""); prog->p_short_name = strdup(short_name ? short_name : long_name); if (!prog->p_long_name || !prog->p_short_name) { tools_progress_free(prog); prog = NULL; goto out; } prog->p_long_name_len = strlen(prog->p_long_name); prog->p_short_name_len = strlen(prog->p_short_name); prog->p_count = count; out: return prog; } /* * API for libtools-internal only */ void tools_progress_clear(void) { if (!progress_on) return; if (list_empty(&progresses)) return; /* * We only need to wipe the line if are doing terminal-based * progress. */ if (nextline != '\r') return; progress_clear(); progress_write(); } void tools_progress_restore(void) { if (!progress_on) return; /* Same here */ if (list_empty(&progresses)) return; if (nextline != '\r') return; progress_compute(); progress_write(); } int tools_progress_enabled(void) { return progress_on; } /* * Public API */ void tools_progress_enable(void) { progress_on = 1; if (!list_empty(&progresses)) return; if (isatty(STDOUT_FILENO)) nextline = '\r'; else nextline = '\n'; } void tools_progress_disable(void) { progress_on = 0; } struct tools_progress *tools_progress_start(const char *long_name, const char *short_name, uint64_t count) { struct tools_progress *prog; if (!progress_on) return &disabled_prog; prog = tools_progress_alloc(long_name, short_name, count); if (!prog) goto out; list_add_tail(&prog->p_list, &progresses); tools_progress_clear(); progress_length_reset(); progress_compute(); progress_write(); out: return prog; } void tools_progress_step(struct tools_progress *prog, unsigned int step) { if (prog == &disabled_prog) return; prog->p_current += step; if (!check_percent(prog)) return; if (!check_tick() && (prog->p_percent != 100) && (!prog->p_count || (prog->p_percent != 0))) return; if (!prog->p_count) step_spinner(prog); progress_compute(); progress_write(); } void tools_progress_stop(struct tools_progress *prog) { if (prog == &disabled_prog) return; tools_progress_clear(); list_del(&prog->p_list); tools_progress_free(prog); if (!list_empty(&progresses)) { progress_length_reset(); tools_progress_restore(); } } #ifdef DEBUG_EXE #include static int run_steps(const char *ln, const char *sn, int count, int (*func)(void)) { int i, ret = 0; struct tools_progress *prog; struct timespec ts = { .tv_nsec = 100000000, }; prog = tools_progress_start(ln, sn, count > 0 ? count : 0); if (!prog) return 1; if (count < 0) count = -count; for (i = 0; i < count; i++) { if (func) ret = func(); if (ret) break; tools_progress_step(prog, 1); nanosleep(&ts, NULL); } tools_progress_stop(prog); return ret; } static int middle(void) { static int try = 0; char lbuf[100], sbuf[100]; try++; snprintf(lbuf, 100, "This is middle %d", try); snprintf(sbuf, 100, "middle%d", try); return run_steps(lbuf, sbuf, -7, NULL); } static int outer(void) { static int try = 0; char lbuf[100], sbuf[100]; try++; snprintf(lbuf, 100, "This is outer %d", try); snprintf(sbuf, 100, "outer%d", try); return run_steps(lbuf, sbuf, 10, middle); } int main(int argc, char *argv[]) { setbuf(stdout, NULL); setbuf(stderr, NULL); tools_progress_enable(); return run_steps("This is a test", "thisis", 5, outer); } #endif ./ocfs2-tools-1.6.4/libtools-internal/libtools-internal.h0000664000176100017610000000164011412217517020235 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * libtools-internal.h * * Internal header for libtools-internal. * * Copyright (C) 2008 Oracle. All rights reserved. * * 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. * * 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. */ #ifndef _LIBTOOLS_INTERNAL_H #define _LIBTOOLS_INTERNAL_H int tools_verbosity(void); int tools_is_interactive(void); void tools_progress_clear(void); void tools_progress_restore(void); int tools_progress_enabled(void); #endif /* _LIBTOOLS_INTERNAL_H */ ./ocfs2-tools-1.6.4/libo2dlm/0000775000176100017610000000000011515641640012547 500000000000000./ocfs2-tools-1.6.4/libo2dlm/Makefile0000644000176100017610000000267211500500544014123 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make INCLUDES = -I. -I$(TOPDIR)/include LIBRARIES = libo2dlm.a CFLAGS += -fPIC ifneq ($(BUILD_FSDLM_SUPPORT),) DEFINES += -DHAVE_FSDLM endif ifneq ($(OCFS2_DEBUG_EXE),) DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES)) DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES))) .SECONDARY: UNINST_PROGRAMS += $(DEBUG_EXE_PROGRAMS) debug_%.o : %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) \ $(INCLUDES) $(DEFINES) \ -DDEBUG_EXE -o $@ -c $< debug_%: debug_%.o libo2dlm.a $(LINK) $(COM_ERR_LIBS) endif CFILES = o2dlm.c capabilities.c HFILES = libdlm-compat.h TESTING_CFILES = o2dlm_test.c HFILES_GEN = o2dlm_err.h ifeq ($(LIBDLM_FOUND),) HFILES_GEN += libdlm.h CLEAN_RULES += clean-libdlm libdlm.h: libdlm-compat.h ln -s $< $@ clean-libdlm: rm -f libdlm.h endif OBJS = $(subst .c,.o,$(CFILES)) \ o2dlm_err.o $(OBJS): $(HFILES) $(HFILES_GEN) TESTING_OBJS = $(subst .c,.o,$(TESTING_CFILES)) o2dlm_err.c o2dlm_err.h: o2dlm_err.et compile_et o2dlm_err.et libo2dlm.a: $(OBJS) rm -f $@ $(AR) r $@ $^ $(RANLIB) $@ o2dlm_test: $(TESTING_OBJS) $(LIBRARIES) $(COM_ERR_LIBS) $(LINK) $(DL_LIBS) DIST_FILES = $(CFILES) $(HFILES) o2dlm_err.et $(TESTING_CFILES) CLEAN_RULES += clean-err clean-test clean-err: rm -f o2dlm_err.c o2dlm_err.h clean-test: rm -f o2dlm_test include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/libo2dlm/o2dlm.c0000644000176100017610000007240311500500544013643 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2dlm.c * * Defines the userspace locking api * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Mark Fasheh */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "o2dlm/o2dlm.h" #include "ocfs2-kernel/kernel-list.h" #define USER_DLMFS_MAGIC 0x76a9f425 struct o2dlm_lock_bast { struct list_head b_bucket; /* to hang us off of the bast list */ int b_fd; /* the fd of the lock file */ void (*b_bast)(void *); void *b_arg; /* Argument to ->b_bast() */ }; struct o2dlm_lock_res { struct list_head l_bucket; /* to hang us off the locks list */ char l_id[O2DLM_LOCK_ID_MAX_LEN]; /* 32 byte, * null * terminated * string */ int l_flags; /* limited set of flags */ enum o2dlm_lock_level l_level; /* either PR or EX */ int l_fd; /* the fd returned by the open call */ #ifdef HAVE_FSDLM struct dlm_lksb l_lksb; /* lksb for fsdlm locking */ char l_lvb[DLM_LVB_LEN]; /* LVB for fsdlm */ #endif }; struct o2dlm_ctxt { int ct_classic; int ct_supports_bast; struct list_head *ct_hash; struct list_head *ct_bast_hash; unsigned int ct_hash_size; char ct_domain_path[O2DLM_MAX_FULL_DOMAIN_PATH]; /* domain * dir */ char ct_ctxt_lock_name[O2DLM_LOCK_ID_MAX_LEN]; #ifdef HAVE_FSDLM void *ct_lib_handle; dlm_lshandle_t ct_handle; #endif }; static errcode_t o2dlm_lock_nochecks(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level); static errcode_t o2dlm_unlock_lock_res(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_res *lockres); static errcode_t o2dlm_generate_random_value(int64_t *value) { int randfd = 0; int readlen = sizeof(*value); if ((randfd = open("/dev/urandom", O_RDONLY)) == -1) return O2DLM_ET_RANDOM; if (read(randfd, value, readlen) != readlen) return O2DLM_ET_RANDOM; close(randfd); return 0; } static void o2dlm_free_ctxt(struct o2dlm_ctxt *ctxt) { if (ctxt->ct_hash) free(ctxt->ct_hash); if (ctxt->ct_bast_hash) free(ctxt->ct_bast_hash); free(ctxt); } #define O2DLM_DEFAULT_HASH_SIZE 4096 static errcode_t o2dlm_alloc_ctxt(const char *mnt_path, const char *dirname, struct o2dlm_ctxt **dlm_ctxt) { errcode_t err; struct o2dlm_ctxt *ctxt; int64_t rand; int len, i; err = o2dlm_generate_random_value(&rand); if (err) return err; ctxt = malloc(sizeof(*ctxt)); if (!ctxt) return O2DLM_ET_NO_MEMORY; memset(ctxt, 0, sizeof(*ctxt)); ctxt->ct_supports_bast = -1; ctxt->ct_hash_size = O2DLM_DEFAULT_HASH_SIZE; ctxt->ct_hash = calloc(ctxt->ct_hash_size, sizeof(struct list_head)); ctxt->ct_bast_hash = calloc(ctxt->ct_hash_size, sizeof(struct list_head)); if (!ctxt->ct_hash || !ctxt->ct_bast_hash) { err = O2DLM_ET_NO_MEMORY; goto exit_and_free; } for(i = 0; i < ctxt->ct_hash_size; i++) { INIT_LIST_HEAD(&ctxt->ct_hash[i]); INIT_LIST_HEAD(&ctxt->ct_bast_hash[i]); } len = snprintf(ctxt->ct_ctxt_lock_name, O2DLM_LOCK_ID_MAX_LEN, ".%016"PRIx64, rand); if (len == O2DLM_LOCK_ID_MAX_LEN) { err = O2DLM_ET_NAME_TOO_LONG; goto exit_and_free; } else if (len < 0) { err = O2DLM_ET_OUTPUT_ERROR; goto exit_and_free; } if (mnt_path) { ctxt->ct_classic = 1; len = snprintf(ctxt->ct_domain_path, PATH_MAX + 1, "%s/%s", mnt_path, dirname); } else { ctxt->ct_classic = 0; len = snprintf(ctxt->ct_domain_path, PATH_MAX + 1, "%s", dirname); } if (len == (PATH_MAX + 1)) { err = O2DLM_ET_BAD_DOMAIN_DIR; goto exit_and_free; } else if (len < 0) { err = O2DLM_ET_OUTPUT_ERROR; goto exit_and_free; } *dlm_ctxt = ctxt; err = 0; exit_and_free: if (err) o2dlm_free_ctxt(ctxt); return err; } static errcode_t o2dlm_check_user_dlmfs(const char *dlmfs_path) { struct statfs statfs_buf; struct stat stat_buf; int ret, fd; fd = open(dlmfs_path, O_RDONLY); if (fd < 0) return O2DLM_ET_OPEN_DLM_DIR; ret = fstat(fd, &stat_buf); if (ret) { close(fd); return O2DLM_ET_STATFS; } if (!S_ISDIR(stat_buf.st_mode)) { close(fd); return O2DLM_ET_NO_FS_DIR; } ret = fstatfs(fd, &statfs_buf); if (ret) { close(fd); return O2DLM_ET_STATFS; } close(fd); if (statfs_buf.f_type != USER_DLMFS_MAGIC) return O2DLM_ET_NO_FS; return 0; } static errcode_t o2dlm_check_domain_dir(struct o2dlm_ctxt *ctxt) { int status; char *dirpath = ctxt->ct_domain_path; struct stat st; status = stat(dirpath, &st); if (status) { if (errno == ENOENT) return O2DLM_ET_NO_DOMAIN_DIR; return O2DLM_ET_BAD_DOMAIN_DIR; } if (!S_ISDIR(st.st_mode)) return O2DLM_ET_BAD_DOMAIN_DIR; return 0; } #define O2DLM_DOMAIN_DIR_MODE 0755 static errcode_t o2dlm_create_domain(struct o2dlm_ctxt *ctxt) { int status; char *dirpath = ctxt->ct_domain_path; status = mkdir(dirpath, O2DLM_DOMAIN_DIR_MODE); if (status) return O2DLM_ET_DOMAIN_CREATE; return 0; } static errcode_t o2dlm_delete_domain_dir(struct o2dlm_ctxt *ctxt) { int ret; ret = rmdir(ctxt->ct_domain_path); if (ret) { if (errno == ENOTEMPTY) return O2DLM_ET_BUSY_DOMAIN_DIR; return O2DLM_ET_DOMAIN_DESTROY; } return 0; } static errcode_t o2dlm_full_path(char *path, struct o2dlm_ctxt *ctxt, const char *filename) { int ret; int len = PATH_MAX + 1; ret = snprintf(path, len, "%s/%s", ctxt->ct_domain_path, filename); if (ret == len) return O2DLM_ET_NAME_TOO_LONG; else if (ret < 0) return O2DLM_ET_OUTPUT_ERROR; return 0; } /* * Most of this hash function taken from dcache.h. It has the * following copyright line at the top: * * (C) Copyright 1997 Thomas Schoebel-Theuer, * with heavy changes by Linus Torvalds */ static inline unsigned long partial_name_hash(unsigned long c, unsigned long prevhash) { return (prevhash + (c << 4) + (c >> 4)) * 11; } static inline unsigned int o2dlm_hash_lockname(struct o2dlm_ctxt *ctxt, const char *name) { unsigned long hash = 0; unsigned int bucket; while(*name) hash = partial_name_hash(*name++, hash); bucket = (unsigned int) hash % ctxt->ct_hash_size; assert(bucket < ctxt->ct_hash_size); return bucket; } static struct o2dlm_lock_res *o2dlm_find_lock_res(struct o2dlm_ctxt *ctxt, const char *lockid) { struct o2dlm_lock_res *lockres; struct list_head *p; unsigned int bucket; bucket = o2dlm_hash_lockname(ctxt, lockid); list_for_each(p, &ctxt->ct_hash[bucket]) { lockres = list_entry(p, struct o2dlm_lock_res, l_bucket); if (!strcmp(lockid, lockres->l_id)) return lockres; } return NULL; } static void o2dlm_insert_lock_res(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_res *lockres) { unsigned int bucket; bucket = o2dlm_hash_lockname(ctxt, lockres->l_id); list_add_tail(&lockres->l_bucket, &ctxt->ct_hash[bucket]); } static inline void o2dlm_remove_lock_res(struct o2dlm_lock_res *lockres) { list_del(&lockres->l_bucket); INIT_LIST_HEAD(&lockres->l_bucket); } static int o2dlm_translate_lock_flags(enum o2dlm_lock_level level, int lockflags) { int flags; switch (level) { case O2DLM_LEVEL_PRMODE: flags = O_RDONLY; break; case O2DLM_LEVEL_EXMODE: flags = O_RDWR; break; default: flags = 0; } if (lockflags & O2DLM_TRYLOCK) flags |= O_NONBLOCK; return flags; } static struct o2dlm_lock_res *o2dlm_new_lock_res(const char *id, enum o2dlm_lock_level level, int flags) { struct o2dlm_lock_res *lockres; lockres = malloc(sizeof(*lockres)); if (lockres) { memset(lockres, 0, sizeof(*lockres)); INIT_LIST_HEAD(&lockres->l_bucket); strncpy(lockres->l_id, id, O2DLM_LOCK_ID_MAX_LEN); lockres->l_flags = flags; lockres->l_level = level; lockres->l_fd = -1; #ifdef HAVE_FSDLM lockres->l_lksb.sb_lvbptr = lockres->l_lvb; memset(lockres->l_lksb.sb_lvbptr, 0, DLM_LVB_LEN); #endif } return lockres; } static inline unsigned int o2dlm_hash_bast(struct o2dlm_ctxt *ctxt, int fd) { return fd % ctxt->ct_hash_size; } static struct o2dlm_lock_bast *o2dlm_find_bast(struct o2dlm_ctxt *ctxt, int fd) { struct o2dlm_lock_bast *bast; struct list_head *p; unsigned int bucket; bucket = o2dlm_hash_bast(ctxt, fd); list_for_each(p, &ctxt->ct_bast_hash[bucket]) { bast = list_entry(p, struct o2dlm_lock_bast, b_bucket); if (fd == bast->b_fd) return bast; } return NULL; } static void o2dlm_insert_bast(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_bast *bast) { unsigned int bucket; bucket = o2dlm_hash_bast(ctxt, bast->b_fd); list_add_tail(&bast->b_bucket, &ctxt->ct_bast_hash[bucket]); } static inline void o2dlm_remove_bast(struct o2dlm_lock_bast *bast) { list_del(&bast->b_bucket); INIT_LIST_HEAD(&bast->b_bucket); } static struct o2dlm_lock_bast *o2dlm_new_bast(int fd, void (*bast_func)(void *), void *bastarg) { struct o2dlm_lock_bast *bast; bast = malloc(sizeof(*bast)); if (bast) { memset(bast, 0, sizeof(*bast)); INIT_LIST_HEAD(&bast->b_bucket); bast->b_bast = bast_func; bast->b_arg = bastarg; bast->b_fd = fd; } return bast; } #define O2DLM_OPEN_MODE 0664 /* * Classic o2dlm */ static errcode_t o2dlm_lock_classic(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level) { int ret, flags, fd; char *path; struct o2dlm_lock_res *lockres; lockres = o2dlm_find_lock_res(ctxt, lockid); if (lockres) return O2DLM_ET_RECURSIVE_LOCK; path = malloc(PATH_MAX + 1); if (!path) return O2DLM_ET_NO_MEMORY; ret = o2dlm_full_path(path, ctxt, lockid); if (ret) { free(path); return ret; } lockflags &= O2DLM_VALID_FLAGS; flags = o2dlm_translate_lock_flags(level, lockflags); lockres = o2dlm_new_lock_res(lockid, level, flags); if (!lockres) { free(path); return O2DLM_ET_NO_MEMORY; } fd = open(path, flags|O_CREAT, O2DLM_OPEN_MODE); if (fd < 0) { free(path); free(lockres); if ((lockflags & O2DLM_TRYLOCK) && (errno == ETXTBSY)) return O2DLM_ET_TRYLOCK_FAILED; return O2DLM_ET_LOCKING; } lockres->l_flags = lockflags; lockres->l_fd = fd; o2dlm_insert_lock_res(ctxt, lockres); free(path); return 0; } static errcode_t o2dlm_drop_lock_classic(struct o2dlm_ctxt *ctxt, const char *lockid) { int ret, len = PATH_MAX + 1; char *path; /* * We're trying to unlink the lockres file from the dlm file * system. Note that EBUSY from unlink is not a fatal error here * -- it simply means that the lock is in use by some other * process. * */ path = malloc(len); if (!path) return O2DLM_ET_NO_MEMORY; ret = o2dlm_full_path(path, ctxt, lockid); if (ret) { free(path); return ret; } ret = unlink(path); free (path); if (ret) { if (errno == EBUSY) return O2DLM_ET_BUSY_LOCK; return O2DLM_ET_UNLINK; } return 0; } static errcode_t o2dlm_unlock_lock_res_classic(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_res *lockres) { close(lockres->l_fd); return 0; } static errcode_t o2dlm_read_lvb_classic(struct o2dlm_ctxt *ctxt, char *lockid, char *lvb, unsigned int len, unsigned int *bytes_read) { int fd, ret; struct o2dlm_lock_res *lockres; lockres = o2dlm_find_lock_res(ctxt, lockid); if (!lockres) return O2DLM_ET_UNKNOWN_LOCK; fd = lockres->l_fd; ret = lseek(fd, 0, SEEK_SET); if (ret < 0) return O2DLM_ET_SEEK; ret = read(fd, lvb, len); if (ret < 0) return O2DLM_ET_LVB_READ; if (!ret) return O2DLM_ET_LVB_INVALID; if (bytes_read) *bytes_read = ret; return 0; } static errcode_t o2dlm_write_lvb_classic(struct o2dlm_ctxt *ctxt, char *lockid, const char *lvb, unsigned int len, unsigned int *bytes_written) { int fd, ret; struct o2dlm_lock_res *lockres; if (!ctxt || !lockid || !lvb) return O2DLM_ET_INVALID_ARGS; lockres = o2dlm_find_lock_res(ctxt, lockid); if (!lockres) return O2DLM_ET_UNKNOWN_LOCK; fd = lockres->l_fd; ret = lseek(fd, 0, SEEK_SET); if (ret < 0) return O2DLM_ET_SEEK; ret = write(fd, lvb, len); if (ret < 0) return O2DLM_ET_LVB_WRITE; if (bytes_written) *bytes_written = ret; return 0; } static errcode_t o2dlm_unlink_all(struct o2dlm_ctxt *ctxt) { int ret; char *name; DIR *dir; struct dirent *de; name = malloc(PATH_MAX + 1); if (!name) return O2DLM_ET_NO_MEMORY; dir = opendir(ctxt->ct_domain_path); if (!dir) { free(name); return O2DLM_ET_DOMAIN_DIR; } de = readdir(dir); while(de) { if ((strlen(de->d_name) == 1) && (de->d_name[0] == '.')) goto next; if ((strlen(de->d_name) == 2) && (de->d_name[0] == '.') && (de->d_name[1] == '.')) goto next; ret = o2dlm_full_path(name, ctxt, de->d_name); if (ret) goto close_and_free; ret = unlink(name); if (ret) { if (errno != EBUSY) { ret = O2DLM_ET_UNLINK; goto close_and_free; } } next: de = readdir(dir); } ret = 0; close_and_free: closedir(dir); free(name); return ret; } static errcode_t o2dlm_destroy_classic(struct o2dlm_ctxt *ctxt) { int ret, i; int error = 0; struct o2dlm_lock_res *lockres; struct o2dlm_lock_bast *bast; struct list_head *p, *n, *bucket; for(i = 0; i < ctxt->ct_hash_size; i++) { bucket = &ctxt->ct_bast_hash[i]; list_for_each_safe(p, n, bucket) { bast = list_entry(p, struct o2dlm_lock_bast, b_bucket); o2dlm_remove_bast(bast); free(bast); } bucket = &ctxt->ct_hash[i]; list_for_each_safe(p, n, bucket) { lockres = list_entry(p, struct o2dlm_lock_res, l_bucket); o2dlm_remove_lock_res(lockres); ret = o2dlm_unlock_lock_res(ctxt, lockres); if (ret && (ret != O2DLM_ET_BUSY_LOCK)) error = O2DLM_ET_FAILED_UNLOCKS; free(lockres); } } if (error) goto free_and_exit; ret = o2dlm_unlink_all(ctxt); if (ret && ret != O2DLM_ET_BUSY_LOCK) { error = ret; goto free_and_exit; } ret = o2dlm_delete_domain_dir(ctxt); if (ret && ret != O2DLM_ET_BUSY_DOMAIN_DIR) error = ret; free_and_exit: o2dlm_free_ctxt(ctxt); return error; } static errcode_t o2dlm_initialize_classic(const char *dlmfs_path, const char *domain_name, struct o2dlm_ctxt **dlm_ctxt) { errcode_t ret, dir_created = 0; struct o2dlm_ctxt *ctxt; if (!dlmfs_path) return O2DLM_ET_INVALID_ARGS; if (strlen(domain_name) >= O2DLM_DOMAIN_MAX_LEN) return O2DLM_ET_NAME_TOO_LONG; if ((strlen(dlmfs_path) + strlen(domain_name)) > O2DLM_MAX_FULL_DOMAIN_PATH) return O2DLM_ET_NAME_TOO_LONG; ret = o2dlm_check_user_dlmfs(dlmfs_path); if (ret) return ret; ret = o2dlm_alloc_ctxt(dlmfs_path, domain_name, &ctxt); if (ret) return ret; ret = o2dlm_check_domain_dir(ctxt); if (ret) { if (ret != O2DLM_ET_NO_DOMAIN_DIR) { o2dlm_free_ctxt(ctxt); return ret; } /* the domain does not yet exist - create it ourselves. */ ret = o2dlm_create_domain(ctxt); if (ret) { o2dlm_free_ctxt(ctxt); return ret; } dir_created = 1; } /* What we want to do here is create a lock which we'll hold * open for the duration of this context. This way if another * process won't be able to shut down this domain underneath * us. */ ret = o2dlm_lock_nochecks(ctxt, ctxt->ct_ctxt_lock_name, 0, O2DLM_LEVEL_PRMODE); if (ret) { if (dir_created) o2dlm_delete_domain_dir(ctxt); /* best effort * cleanup. */ o2dlm_free_ctxt(ctxt); return ret; } *dlm_ctxt = ctxt; return 0; } /* * fsdlm operations */ #ifdef HAVE_FSDLM /* Dynamic symbols */ static dlm_lshandle_t (*fsdlm_create_lockspace)(const char *name, mode_t mode); static int (*fsdlm_release_lockspace)(const char *name, dlm_lshandle_t ls, int force); static int (*fsdlm_ls_lock_wait)(dlm_lshandle_t ls, uint32_t mode, struct dlm_lksb *lksb, uint32_t flags, const void *name, unsigned int namelen, uint32_t parent, void *bastarg, void (*bastaddr)(void *bastarg), void *range); static int (*fsdlm_ls_unlock_wait)(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb); static errcode_t load_fsdlm(struct o2dlm_ctxt *ctxt) { errcode_t ret = O2DLM_ET_SERVICE_UNAVAILABLE; if (ctxt->ct_lib_handle) { ret = 0; goto out; } ctxt->ct_lib_handle = dlopen("libdlm_lt.so", RTLD_NOW | RTLD_LOCAL); if (!ctxt->ct_lib_handle) goto out; #define load_sym(_sym) do { \ fs ## _sym = dlsym(ctxt->ct_lib_handle, #_sym); \ if (! fs ## _sym) \ goto out; \ } while (0) load_sym(dlm_create_lockspace); load_sym(dlm_release_lockspace); load_sym(dlm_ls_lock_wait); load_sym(dlm_ls_unlock_wait); ret = 0; out: if (ret && ctxt->ct_lib_handle) { dlclose(ctxt->ct_lib_handle); ctxt->ct_lib_handle = NULL; } return ret; } static void to_fsdlm_lock(enum o2dlm_lock_level level, int lockflags, uint32_t *fsdlm_mode, uint32_t *fsdlm_flags) { switch (level) { case O2DLM_LEVEL_PRMODE: *fsdlm_mode = LKM_PRMODE; break; case O2DLM_LEVEL_EXMODE: *fsdlm_mode = LKM_EXMODE; break; default: *fsdlm_mode = LKM_NLMODE; break; } if (lockflags & O2DLM_TRYLOCK) *fsdlm_flags = LKF_NOQUEUE; else *fsdlm_flags = 0; } static errcode_t o2dlm_lock_fsdlm(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level) { int rc; errcode_t ret = 0; struct o2dlm_lock_res *lockres; uint32_t mode, flags; if (!fsdlm_ls_lock_wait) return O2DLM_ET_SERVICE_UNAVAILABLE; lockres = o2dlm_find_lock_res(ctxt, lockid); if (lockres) return O2DLM_ET_RECURSIVE_LOCK; lockflags &= O2DLM_VALID_FLAGS; lockres = o2dlm_new_lock_res(lockid, level, lockflags); if (!lockres) return O2DLM_ET_NO_MEMORY; to_fsdlm_lock(level, lockflags, &mode, &flags); flags |= LKF_VALBLK; /* Always use LVBs */ rc = fsdlm_ls_lock_wait(ctxt->ct_handle, mode, &lockres->l_lksb, flags, lockid, strlen(lockid), 0, NULL, NULL, NULL); if (rc) rc = errno; else rc = lockres->l_lksb.sb_status; switch (rc) { case 0: /* Success! */ break; case EAGAIN: if (lockflags & O2DLM_TRYLOCK) ret = O2DLM_ET_TRYLOCK_FAILED; else ret = O2DLM_ET_LOCKING; break; case EINVAL: ret = O2DLM_ET_INVALID_ARGS; break; case ENOMEM: ret = O2DLM_ET_NO_MEMORY; break; case ECANCEL: ret = O2DLM_ET_LOCKING; break; default: ret = O2DLM_ET_INTERNAL_FAILURE; break; } if (!ret) o2dlm_insert_lock_res(ctxt, lockres); else free(lockres); return ret; } static errcode_t o2dlm_unlock_lock_res_fsdlm(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_res *lockres) { int rc; errcode_t ret = 0; if (!fsdlm_ls_unlock_wait) return O2DLM_ET_SERVICE_UNAVAILABLE; rc = fsdlm_ls_unlock_wait(ctxt->ct_handle, lockres->l_lksb.sb_lkid, LKF_VALBLK, &lockres->l_lksb); if (rc) rc = errno; else rc = lockres->l_lksb.sb_status; switch (rc) { case 0: case EUNLOCK: /* Success! */ break; case ENOTCONN: ret = O2DLM_ET_SERVICE_UNAVAILABLE; break; case EINVAL: ret = O2DLM_ET_INVALID_ARGS; break; case ENOENT: ret = O2DLM_ET_UNKNOWN_LOCK; break; default: ret = O2DLM_ET_INTERNAL_FAILURE; break; } return ret; } static errcode_t o2dlm_write_lvb_fsdlm(struct o2dlm_ctxt *ctxt, char *lockid, const char *lvb, unsigned int len, unsigned int *bytes_written) { struct o2dlm_lock_res *lockres; if (!ctxt || !lockid || !lvb) return O2DLM_ET_INVALID_ARGS; lockres = o2dlm_find_lock_res(ctxt, lockid); if (!lockres) return O2DLM_ET_UNKNOWN_LOCK; /* fsdlm only supports DLM_LVB_LEN for userspace locks */ if (len > DLM_LVB_LEN) len = DLM_LVB_LEN; memcpy(lockres->l_lksb.sb_lvbptr, lvb, len); if (bytes_written) *bytes_written = len; return 0; } static errcode_t o2dlm_read_lvb_fsdlm(struct o2dlm_ctxt *ctxt, char *lockid, char *lvb, unsigned int len, unsigned int *bytes_read) { struct o2dlm_lock_res *lockres; lockres = o2dlm_find_lock_res(ctxt, lockid); if (!lockres) return O2DLM_ET_UNKNOWN_LOCK; /* fsdlm only supports DLM_LVB_LEN for userspace locks */ if (len > DLM_LVB_LEN) len = DLM_LVB_LEN; memcpy(lvb, lockres->l_lksb.sb_lvbptr, len); if (bytes_read) *bytes_read = len; return 0; } static errcode_t o2dlm_initialize_fsdlm(const char *domain_name, struct o2dlm_ctxt **dlm_ctxt) { errcode_t ret; struct o2dlm_ctxt *ctxt; if (strlen(domain_name) >= O2DLM_DOMAIN_MAX_LEN) return O2DLM_ET_NAME_TOO_LONG; ret = o2dlm_alloc_ctxt(NULL, domain_name, &ctxt); if (ret) return ret; ret = load_fsdlm(ctxt); if (ret) { o2dlm_free_ctxt(ctxt); return ret; } ctxt->ct_handle = fsdlm_create_lockspace(ctxt->ct_domain_path, 0600); if (!ctxt->ct_handle) { switch (errno) { case EINVAL: ret = O2DLM_ET_INVALID_ARGS; break; case ENOMEM: ret = O2DLM_ET_NO_MEMORY; break; case EEXIST: /* * This is a special case for older * versions of fs/dlm. */ ret = O2DLM_ET_DOMAIN_BUSY; break; case EACCES: case EPERM: ret = O2DLM_ET_BAD_DOMAIN_DIR; break; default: ret = O2DLM_ET_INTERNAL_FAILURE; break; } o2dlm_free_ctxt(ctxt); return ret; } /* What we want to do here is create a lock which we'll hold * open for the duration of this context. This way if another * process won't be able to shut down this domain underneath * us. */ ret = o2dlm_lock_nochecks(ctxt, ctxt->ct_ctxt_lock_name, 0, O2DLM_LEVEL_PRMODE); if (ret) { /* Ignore the error, we want ret to be propagated */ fsdlm_release_lockspace(ctxt->ct_domain_path, ctxt->ct_handle, 0); o2dlm_free_ctxt(ctxt); return ret; } *dlm_ctxt = ctxt; return 0; } static errcode_t o2dlm_destroy_fsdlm(struct o2dlm_ctxt *ctxt) { int i, rc; errcode_t ret, error = 0; struct o2dlm_lock_res *lockres; struct list_head *p, *n, *bucket; if (!fsdlm_release_lockspace) return O2DLM_ET_SERVICE_UNAVAILABLE; for(i = 0; i < ctxt->ct_hash_size; i++) { bucket = &ctxt->ct_hash[i]; list_for_each_safe(p, n, bucket) { lockres = list_entry(p, struct o2dlm_lock_res, l_bucket); o2dlm_remove_lock_res(lockres); ret = o2dlm_unlock_lock_res(ctxt, lockres); if (ret && (ret != O2DLM_ET_BUSY_LOCK)) error = O2DLM_ET_FAILED_UNLOCKS; free(lockres); } } if (error) goto free_and_exit; rc = fsdlm_release_lockspace(ctxt->ct_domain_path, ctxt->ct_handle, 0); if (!rc) goto free_and_exit; switch(errno) { case EBUSY: /* Do nothing */ break; case EINVAL: error = O2DLM_ET_INVALID_ARGS; break; case ENOMEM: error = O2DLM_ET_NO_MEMORY; break; case EACCES: case EPERM: error = O2DLM_ET_BAD_DOMAIN_DIR; break; default: error = O2DLM_ET_INTERNAL_FAILURE; break; } free_and_exit: o2dlm_free_ctxt(ctxt); return error; } #else /* HAVE_FSDLM */ static errcode_t o2dlm_lock_fsdlm(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level) { return O2DLM_ET_SERVICE_UNAVAILABLE; } static errcode_t o2dlm_unlock_lock_res_fsdlm(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_res *lockres) { return O2DLM_ET_SERVICE_UNAVAILABLE; } static errcode_t o2dlm_read_lvb_fsdlm(struct o2dlm_ctxt *ctxt, char *lockid, char *lvb, unsigned int len, unsigned int *bytes_read) { return O2DLM_ET_SERVICE_UNAVAILABLE; } static errcode_t o2dlm_write_lvb_fsdlm(struct o2dlm_ctxt *ctxt, char *lockid, const char *lvb, unsigned int len, unsigned int *bytes_written) { return O2DLM_ET_SERVICE_UNAVAILABLE; } static errcode_t o2dlm_initialize_fsdlm(const char *domain_name, struct o2dlm_ctxt **dlm_ctxt) { return O2DLM_ET_SERVICE_UNAVAILABLE; } static errcode_t o2dlm_destroy_fsdlm(struct o2dlm_ctxt *ctxt) { return O2DLM_ET_SERVICE_UNAVAILABLE; } #endif /* HAVE_FSDLM */ /* * Public API */ /* Use this internally to avoid the check for a reserved name */ static errcode_t o2dlm_lock_nochecks(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level) { if (strlen(lockid) >= O2DLM_LOCK_ID_MAX_LEN) return O2DLM_ET_INVALID_LOCK_NAME; if (level != O2DLM_LEVEL_PRMODE && level != O2DLM_LEVEL_EXMODE) return O2DLM_ET_INVALID_LOCK_LEVEL; if (ctxt->ct_classic) return o2dlm_lock_classic(ctxt, lockid, lockflags, level); else return o2dlm_lock_fsdlm(ctxt, lockid, lockflags, level); } errcode_t o2dlm_lock(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level) { if (!ctxt || !lockid) return O2DLM_ET_INVALID_ARGS; /* names starting with '.' are reserved. */ if (lockid[0] == '.') return O2DLM_ET_INVALID_LOCK_NAME; return o2dlm_lock_nochecks(ctxt, lockid, lockflags, level); } static errcode_t o2dlm_ctxt_supports_bast(struct o2dlm_ctxt *ctxt) { int support; errcode_t ret = 0; if (ctxt->ct_supports_bast == -1) { ret = o2dlm_supports_bast(&support); if (!ret) { ctxt->ct_supports_bast = support; } } if (!ret && !ctxt->ct_supports_bast) ret = O2DLM_ET_BAST_UNSUPPORTED; return ret; } errcode_t o2dlm_lock_with_bast(struct o2dlm_ctxt *ctxt, const char *lockid, int lockflags, enum o2dlm_lock_level level, void (*bast_func)(void *bast_arg), void *bast_arg, int *poll_fd) { errcode_t ret; struct o2dlm_lock_res *lockres; struct o2dlm_lock_bast *bast; if (!ctxt->ct_classic) return O2DLM_ET_BAST_UNSUPPORTED; if (!bast_func || !poll_fd) return O2DLM_ET_INVALID_ARGS; ret = o2dlm_ctxt_supports_bast(ctxt); if (ret) return ret; ret = o2dlm_lock(ctxt, lockid, lockflags, level); if (ret) return ret; lockres = o2dlm_find_lock_res(ctxt, lockid); if (!lockres) { o2dlm_unlock(ctxt, lockid); return O2DLM_ET_INTERNAL_FAILURE; } bast = o2dlm_new_bast(lockres->l_fd, bast_func, bast_arg); if (!bast) { o2dlm_unlock(ctxt, lockid); return O2DLM_ET_NO_MEMORY; } o2dlm_insert_bast(ctxt, bast); *poll_fd = lockres->l_fd; return 0; } static errcode_t o2dlm_unlock_lock_res(struct o2dlm_ctxt *ctxt, struct o2dlm_lock_res *lockres) { if (ctxt->ct_classic) return o2dlm_unlock_lock_res_classic(ctxt, lockres); else return o2dlm_unlock_lock_res_fsdlm(ctxt, lockres); } /* * Dropping locks is only available on dlmfs. No one should be using * libdlm if they can help it. */ errcode_t o2dlm_drop_lock(struct o2dlm_ctxt *ctxt, const char *lockid) { if (!ctxt || !lockid) return O2DLM_ET_INVALID_ARGS; if (o2dlm_find_lock_res(ctxt, lockid)) return O2DLM_ET_BUSY_LOCK; if (ctxt->ct_classic) return o2dlm_drop_lock_classic(ctxt, lockid); else return O2DLM_ET_SERVICE_UNAVAILABLE; } errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt, const char *lockid) { int ret; struct o2dlm_lock_res *lockres; struct o2dlm_lock_bast *bast; if (!ctxt || !lockid) return O2DLM_ET_INVALID_ARGS; lockres = o2dlm_find_lock_res(ctxt, lockid); if (!lockres) return O2DLM_ET_UNKNOWN_LOCK; bast = o2dlm_find_bast(ctxt, lockres->l_fd); if (bast) o2dlm_remove_bast(bast); o2dlm_remove_lock_res(lockres); ret = o2dlm_unlock_lock_res(ctxt, lockres); free(lockres); if (ret && (ret != O2DLM_ET_BUSY_LOCK)) return ret; return 0; } errcode_t o2dlm_read_lvb(struct o2dlm_ctxt *ctxt, char *lockid, char *lvb, unsigned int len, unsigned int *bytes_read) { if (!ctxt || !lockid || !lvb) return O2DLM_ET_INVALID_ARGS; if (ctxt->ct_classic) return o2dlm_read_lvb_classic(ctxt, lockid, lvb, len, bytes_read); else return o2dlm_read_lvb_fsdlm(ctxt, lockid, lvb, len, bytes_read); } errcode_t o2dlm_write_lvb(struct o2dlm_ctxt *ctxt, char *lockid, const char *lvb, unsigned int len, unsigned int *bytes_written) { if (!ctxt || !lockid || !lvb) return O2DLM_ET_INVALID_ARGS; if (ctxt->ct_classic) return o2dlm_write_lvb_classic(ctxt, lockid, lvb, len, bytes_written); else return o2dlm_write_lvb_fsdlm(ctxt, lockid, lvb, len, bytes_written); } void o2dlm_process_bast(struct o2dlm_ctxt *ctxt, int poll_fd) { struct o2dlm_lock_bast *bast; bast = o2dlm_find_bast(ctxt, poll_fd); if (bast) bast->b_bast(bast->b_arg); } /* NULL dlmfs_path means fsdlm */ errcode_t o2dlm_initialize(const char *dlmfs_path, const char *domain_name, struct o2dlm_ctxt **dlm_ctxt) { if (!domain_name || !dlm_ctxt) return O2DLM_ET_INVALID_ARGS; if (dlmfs_path) return o2dlm_initialize_classic(dlmfs_path, domain_name, dlm_ctxt); else return o2dlm_initialize_fsdlm(domain_name, dlm_ctxt); } errcode_t o2dlm_destroy(struct o2dlm_ctxt *ctxt) { if (!ctxt) return O2DLM_ET_INVALID_ARGS; if (ctxt->ct_classic) return o2dlm_destroy_classic(ctxt); else return o2dlm_destroy_fsdlm(ctxt); } ./ocfs2-tools-1.6.4/libo2dlm/capabilities.c0000644000176100017610000000521611500500544015255 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * capabilities.c * * Read dlmfs capabilities. * * Copyright (C) 2010 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #include #include #include #include #include #include "o2dlm/o2dlm.h" #define CAPABILITIES_FILE "/sys/module/ocfs2_dlmfs/parameters/capabilities" static ssize_t read_single_line_file(const char *file, char *line, size_t count) { ssize_t ret = 0; FILE *f; f = fopen(file, "r"); if (f) { if (fgets(line, count, f)) ret = strlen(line); fclose(f); } else ret = -errno; return ret; } static ssize_t o2dlm_read_capabilities(char *line, size_t count) { ssize_t got; got = read_single_line_file(CAPABILITIES_FILE, line, count); if ((got > 0) && (line[got - 1] == '\n')) { got--; line[got] = '\0'; } return got; } static errcode_t o2dlm_has_capability(const char *cap_name, int *found) { char line[PATH_MAX]; char *p; ssize_t got; got = o2dlm_read_capabilities(line, PATH_MAX); if (got == -ENOENT) { got = 0; line[0] = '\0'; } if (got < 0) return O2DLM_ET_SERVICE_UNAVAILABLE; *found = 0; p = strstr(line, cap_name); if (p) { p += strlen(cap_name); if (!*p || (*p == ' ')) *found = 1; } return 0; } errcode_t o2dlm_supports_bast(int *supports) { return o2dlm_has_capability("bast", supports); } errcode_t o2dlm_supports_stackglue(int *supports) { return o2dlm_has_capability("stackglue", supports); } #ifdef DEBUG_EXE int main(int argc, char *argv[]) { errcode_t ret; int i, rc = 0; char **caps; initialize_o2dl_error_table(); ret = o2dlm_supports_bast(&i); if (!ret) fprintf(stdout, "bast: %s\n", i ? "yes" : "no"); else { rc = 1; com_err("debug_capabilities", ret, "while testing bast capability"); } ret = o2dlm_supports_stackglue(&i); if (!ret) fprintf(stdout, "stackglue: %s\n", i ? "yes" : "no"); else { rc = 1; com_err("debug_capabilities", ret, "while testing stackglue capability"); } ret = o2dlm_has_capability("invalid", &i); if (!ret) fprintf(stdout, "invalid: %s\n", i ? "yes" : "no"); else { rc = 1; com_err("debug_capabilities", ret, "while testing invalid capability"); } return ret; } #endif ./ocfs2-tools-1.6.4/libo2dlm/libdlm-compat.h0000644000176100017610000002013611115551035015356 00000000000000/****************************************************************************** ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. ** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** ******************************************************************************* ******************************************************************************/ #ifndef __LIBDLM_H #define __LIBDLM_H /* * Typedefs for things that are compatible with the kernel but replicated here * so that users only need the libdlm include file. libdlm itself needs the * full kernel file so shouldn't use these. */ #define DLM_LVB_LEN 32 #ifndef BUILDING_LIBDLM #define DLM_RESNAME_MAXLEN 64 struct dlm_lksb { int sb_status; uint32_t sb_lkid; char sb_flags; char *sb_lvbptr; }; /* lksb flags */ #define DLM_SBF_DEMOTED 0x01 #define DLM_SBF_VALNOTVALID 0x02 #define DLM_SBF_ALTMODE 0x04 /* dlm_new_lockspace flags */ #define DLM_LSFL_NODIR 0x00000001 #define DLM_LSFL_TIMEWARN 0x00000002 #endif #if 0 /* Dummy definition to keep linkages */ struct dlm_queryinfo; #endif extern int dlm_kernel_version(uint32_t *maj, uint32_t *min, uint32_t *patch); extern void dlm_library_version(uint32_t *maj, uint32_t *min, uint32_t *patch); /* * Using the default lockspace * * lock_resource() - simple sync request or convert (requires pthreads) * unlock_resource() - simple sync unlock (requires pthreads) * dlm_lock() - async request or convert * dlm_unlock() - async unlock or cancel * dlm_lock_wait() - sync request or convert * dlm_unlock_wait() - sync unlock or cancel */ #ifdef _REENTRANT extern int lock_resource(const char *resource, int mode, int flags, int *lockid); extern int unlock_resource(int lockid); #endif extern int dlm_lock(uint32_t mode, struct dlm_lksb *lksb, uint32_t flags, const void *name, unsigned int namelen, uint32_t parent, /* unusued */ void (*astaddr) (void *astarg), void *astarg, void (*bastaddr) (void *astarg), void *range); /* unused */ extern int dlm_unlock(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb, void *astarg); extern int dlm_lock_wait(uint32_t mode, struct dlm_lksb *lksb, uint32_t flags, const void *name, unsigned int namelen, uint32_t parent, /* unused */ void *bastarg, void (*bastaddr) (void *bastarg), void *range); /* unused */ extern int dlm_unlock_wait(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb); /* * These two are for users that want to do their own FD handling * * dlm_get_fd() - returns fd for the default lockspace for polling and dispatch * dlm_dispatch() - dispatches pending asts and basts */ extern int dlm_get_fd(void); extern int dlm_dispatch(int fd); /* * Creating your own lockspace * * dlm_create_lockspace() - create and open a lockspace and return a handle * to it. Privileges are required to create/release. * dlm_new_lockspace() - same as create but allows flags * dlm_open_lockspace() - simply returns a handle for an existing lockspace and * may be called by ordinary users. * dlm_release_lockspace() * dlm_close_lockspace() * dlm_ls_get_fd() * * NOTE: that if you dlm_create_lockspace() then dlm_open_lockspace() you will * have two open files on the same device. Hardly a major problem but I thought * it worth pointing out. */ typedef void *dlm_lshandle_t; extern dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode); extern int dlm_release_lockspace(const char *name, dlm_lshandle_t ls, int force); extern dlm_lshandle_t dlm_open_lockspace(const char *name); extern int dlm_close_lockspace(dlm_lshandle_t ls); extern int dlm_ls_get_fd(dlm_lshandle_t ls); extern dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode, uint32_t flags); /* * Using your own lockspace * * dlm_ls_lock() * dlm_ls_lockx() * dlm_ls_unlock() * dlm_ls_lock_wait() * dlm_ls_unlock_wait() * dlm_ls_deadlock_cancel() * dlm_ls_purge() */ extern int dlm_ls_lock(dlm_lshandle_t lockspace, uint32_t mode, struct dlm_lksb *lksb, uint32_t flags, const void *name, unsigned int namelen, uint32_t parent, /* unused */ void (*astaddr) (void *astarg), void *astarg, void (*bastaddr) (void *astarg), void *range); /* unused */ extern int dlm_ls_lockx(dlm_lshandle_t lockspace, uint32_t mode, struct dlm_lksb *lksb, uint32_t flags, const void *name, unsigned int namelen, uint32_t parent, /* unused */ void (*astaddr) (void *astarg), void *astarg, void (*bastaddr) (void *astarg), uint64_t *xid, uint64_t *timeout); extern int dlm_ls_unlock(dlm_lshandle_t lockspace, uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb, void *astarg); extern int dlm_ls_lock_wait(dlm_lshandle_t lockspace, uint32_t mode, struct dlm_lksb *lksb, uint32_t flags, const void *name, unsigned int namelen, uint32_t parent, /* unused */ void *bastarg, void (*bastaddr) (void *bastarg), void *range); /* unused */ extern int dlm_ls_unlock_wait(dlm_lshandle_t lockspace, uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb); extern int dlm_ls_deadlock_cancel(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags); extern int dlm_ls_purge(dlm_lshandle_t lockspace, int nodeid, int pid); /* * For threaded applications * * dlm_pthread_init() * dlm_ls_pthread_init() - call this before any locking operations and the ASTs * will be delivered in their own thread. * dlm_pthread_cleanup() - call the cleanup routine at application exit * (optional) or, if the locking functions are in a * shared library that is to be unloaded. * * dlm_close/release_lockspace() will tidy the threads for a non-default * lockspace */ #ifdef _REENTRANT extern int dlm_pthread_init(); extern int dlm_ls_pthread_init(dlm_lshandle_t lockspace); extern int dlm_pthread_cleanup(); #endif /* * Lock modes */ #define LKM_NLMODE 0 /* null lock */ #define LKM_CRMODE 1 /* concurrent read */ #define LKM_CWMODE 2 /* concurrent write */ #define LKM_PRMODE 3 /* protected read */ #define LKM_PWMODE 4 /* protected write */ #define LKM_EXMODE 5 /* exclusive */ /* * Locking flags - these match the ones in dlm.h */ #define LKF_NOQUEUE 0x00000001 #define LKF_CANCEL 0x00000002 #define LKF_CONVERT 0x00000004 #define LKF_VALBLK 0x00000008 #define LKF_QUECVT 0x00000010 #define LKF_IVVALBLK 0x00000020 #define LKF_CONVDEADLK 0x00000040 #define LKF_PERSISTENT 0x00000080 #define LKF_NODLCKWT 0x00000100 #define LKF_NODLCKBLK 0x00000200 #define LKF_EXPEDITE 0x00000400 #define LKF_NOQUEUEBAST 0x00000800 #define LKF_HEADQUE 0x00001000 #define LKF_NOORDER 0x00002000 #define LKF_ORPHAN 0x00004000 #define LKF_ALTPR 0x00008000 #define LKF_ALTCW 0x00010000 #define LKF_FORCEUNLOCK 0x00020000 #define LKF_TIMEOUT 0x00040000 #define LKF_WAIT 0x80000000 /* Userspace only, for sync API calls */ /* * Extra return codes used by the DLM */ #define ECANCEL 0x10001 #define EUNLOCK 0x10002 #define EINPROG 0x10003 /* lock operation is in progress */ #endif ./ocfs2-tools-1.6.4/libo2dlm/o2dlm_err.et0000644000176100017610000000513211500500544014674 00000000000000# # o2dlm_err.et # # Error codes for the O2DLM library. # # Copyright (C) 2005 Oracle. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License, version 2, as published by the Free Software Foundation. # # 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 021110-1307, USA. # error_table o2dl ec O2DLM_ET_NO_MEMORY, "Memory allocation failed" ec O2DLM_ET_SERVICE_UNAVAILABLE, "Unable to access cluster service" ec O2DLM_ET_INVALID_LOCK_NAME, "Invalid name for a lock" ec O2DLM_ET_INVALID_LOCK_LEVEL, "Invalid locking level" ec O2DLM_ET_INTERNAL_FAILURE, "Internal logic failure" ec O2DLM_ET_NAME_TOO_LONG, "Name too long" ec O2DLM_ET_STATFS, "Could not stat user_dlmfs mountpoint" ec O2DLM_ET_NO_FS_DIR, "Dlmfs path specified is not a directory." ec O2DLM_ET_NO_FS, "ocfs2_dlmfs file system was not found" ec O2DLM_ET_OPEN_DLM_DIR, "Could not open dlm directory" ec O2DLM_ET_NO_DOMAIN_DIR, "No directory for domain was found" ec O2DLM_ET_BAD_DOMAIN_DIR, "Could not stat domain directory" ec O2DLM_ET_BUSY_DOMAIN_DIR, "Domain directory has active locks" ec O2DLM_ET_DOMAIN_DIR, "Could not read domain dir" ec O2DLM_ET_DOMAIN_DESTROY, "Could not destroy domain" ec O2DLM_ET_DOMAIN_CREATE, "Could not create domain" ec O2DLM_ET_RANDOM, "Could not generate random value" ec O2DLM_ET_BUSY_LOCK, "Lock resource is in use by another process" ec O2DLM_ET_OUTPUT_ERROR, "Output Error" ec O2DLM_ET_UNLINK, "Error unlinking lock resource" ec O2DLM_ET_UNKNOWN_LOCK, "Could not find lock resource" ec O2DLM_ET_RECURSIVE_LOCK, "Already have a lock on this resource" ec O2DLM_ET_LOCKING, "Could not take lock" ec O2DLM_ET_FAILED_UNLOCKS, "Could not drop all locks" ec O2DLM_ET_INVALID_ARGS, "Invalid arguments passed to function" ec O2DLM_ET_TRYLOCK_FAILED, "Trylock failed" ec O2DLM_ET_LVB_READ, "Error reading LVB" ec O2DLM_ET_LVB_WRITE, "Error writing LVB" ec O2DLM_ET_SEEK, "Could not seek within file descriptor" ec O2DLM_ET_DOMAIN_BUSY, "The domain is busy and cannot be accessed" ec O2DLM_ET_BAST_UNSUPPORTED, "This environment does not support BASTs" ec O2DLM_ET_LVB_INVALID, "The LVB is not valid" end ./ocfs2-tools-1.6.4/libo2dlm/o2dlm_test.c0000644000176100017610000001641211115551035014703 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Test driver for libo2dlm. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Mark Fasheh */ #include #include #include #include #include #include #include #include #include #include "o2dlm/o2dlm.h" #define COMMAND_MAX_LEN 4096 static char cbuf[COMMAND_MAX_LEN]; #define DEFAULT_DLMFS_PATH "/dlm/" static char *dlmfs_path = NULL; static char *prog; static struct o2dlm_ctxt *dlm_ctxt = NULL; enum commands { REGISTER = 0, UNREGISTER, LOCK, TRYLOCK, UNLOCK, GETLVB, SETLVB, HELP, NUM_COMMANDS }; static char *command_strings[NUM_COMMANDS] = { [REGISTER] "REGISTER", [UNREGISTER] "UNREGISTER", [LOCK] "LOCK", [TRYLOCK] "TRYLOCK", [UNLOCK] "UNLOCK", [GETLVB] "GETLVB", [SETLVB] "SETLVB", [HELP] "HELP", }; #define NUM_PR_STRINGS 4 static char *pr_strings[NUM_PR_STRINGS] = { "PR", "PRMODE", "RO", "O2DLM_LEVEL_PRMODE" }; #define NUM_EX_STRINGS 4 static char *ex_strings[NUM_EX_STRINGS] = { "EX", "EXMODE", "EX", "O2DLM_LEVEL_EXMODE" }; struct command_s { enum commands c_type; char c_domain[O2DLM_DOMAIN_MAX_LEN]; char c_id[O2DLM_LOCK_ID_MAX_LEN]; enum o2dlm_lock_level c_level; char *c_lvb; }; static void print_commands(void) { printf("Domain Commands:\n"); printf("register \"domain\'\n"); printf("unregister \"domain\'\n"); printf("Locking Commands - \"level\" is one of PR, or EX. " "Some common variations are understood\n"); printf("lock \"level\" \"lockid\"\n"); printf("trylock \"level\" \"lockid\"\n"); printf("unlock \"lockid\"\n"); printf("getlvb \"lockid\"\n"); printf("setlvb \"lockid\" \"lvb\"\n"); } static int decode_type(struct command_s *c, char *buf) { int i; for(i = 0; i < NUM_COMMANDS; i++) { if (!strcasecmp(buf, command_strings[i])) { c->c_type = i; return 0; } } return -1; } static void kill_return(char *buf) { char *c; c = strchr(buf, '\n'); if (c) *c = '\0'; } static int decode_lock(struct command_s *c, char *buf) { kill_return(buf); memset(c->c_id, 0, O2DLM_LOCK_ID_MAX_LEN); strncpy(c->c_id, buf, O2DLM_LOCK_ID_MAX_LEN - 1); return 0; } static int decode_domain(struct command_s *c, char *buf) { kill_return(buf); memset(c->c_domain, 0, O2DLM_DOMAIN_MAX_LEN); strncpy(c->c_domain, buf, O2DLM_DOMAIN_MAX_LEN - 1); return 0; } static int decode_level(struct command_s *c, char *buf) { int i; kill_return(buf); for (i = 0; i < NUM_PR_STRINGS; i++) { if (!strcasecmp(buf, pr_strings[i])) { c->c_level = O2DLM_LEVEL_PRMODE; return 0; } } for (i = 0; i < NUM_EX_STRINGS; i++) { if (!strcasecmp(buf, ex_strings[i])) { c->c_level = O2DLM_LEVEL_EXMODE; return 0; } } return -1; } static void print_command(struct command_s *c, const char *str) { printf("Command: %s ", command_strings[c->c_type]); switch (c->c_type) { case REGISTER: case UNREGISTER: printf("\"%s\" %s\n", c->c_domain, str); break; case LOCK: case TRYLOCK: if (c->c_level == O2DLM_LEVEL_PRMODE) printf("O2DLM_LEVEL_PRMODE "); else printf("O2DLM_LEVEL_EXMODE "); /* fall through */ case GETLVB: case UNLOCK: printf("\"%s\" %s\n", c->c_id, str); break; case SETLVB: printf("\"%s\" \"%s\" %s\n", c->c_id, c->c_lvb, str); break; case HELP: printf("%s\n", str); break; default: printf("wha?!?!?\n"); } } static int get_command(struct command_s *command) { char *next; again: printf("command: "); if (!fgets(cbuf, COMMAND_MAX_LEN, stdin)) return -1; next = strtok(cbuf, " \n"); if (!next) goto again; if (decode_type(command, next)) { fprintf(stderr, "Invalid command type \"%s\"\n", next); goto again; } if (command->c_type == HELP) return 0; next = strtok(NULL, " "); if (!next) { fprintf(stderr, "invalid input!\n"); goto again; } switch (command->c_type) { case REGISTER: case UNREGISTER: if (decode_domain(command, next)) { fprintf(stderr, "Invalid domain \"%s\"\n", next); goto again; } break; case LOCK: case TRYLOCK: if (decode_level(command, next)) { fprintf(stderr, "Invalid lock level \"%s\"\n", next); goto again; } next = strtok(NULL, " "); if (!next) { fprintf(stderr, "invalid input!\n"); goto again; } /* fall through */ case SETLVB: case GETLVB: case UNLOCK: if (decode_lock(command, next)) { fprintf(stderr, "Invalid lock \"%s\"\n", next); goto again; } if (command->c_type == SETLVB) { /* for setlvb we want to get a pointer to the * start of the string to stuff */ next = strtok(NULL, "\n"); if (!next) { fprintf(stderr, "invalid input!\n"); goto again; } kill_return(next); command->c_lvb = next; } break; default: fprintf(stderr, "whoa, can't parse this\n"); } return 0; } #define LVB_LEN 64 static char lvb_buf[LVB_LEN]; static errcode_t exec_command(struct command_s *c) { errcode_t ret = 0; unsigned int bytes, len; switch (c->c_type) { case REGISTER: ret = o2dlm_initialize(dlmfs_path, c->c_domain, &dlm_ctxt); break; case UNREGISTER: ret = o2dlm_destroy(dlm_ctxt); dlm_ctxt = NULL; break; case LOCK: ret = o2dlm_lock(dlm_ctxt, c->c_id, 0, c->c_level); break; case UNLOCK: ret = o2dlm_unlock(dlm_ctxt, c->c_id); break; case TRYLOCK: ret = o2dlm_lock(dlm_ctxt, c->c_id, O2DLM_TRYLOCK, c->c_level); break; case GETLVB: ret = o2dlm_read_lvb(dlm_ctxt, c->c_id, lvb_buf, LVB_LEN, &bytes); if (!ret) { printf("%u bytes read. LVB begins on following " "line and is terminated by a newline\n", bytes); printf("%.*s\n", bytes, lvb_buf); } break; case SETLVB: len = strlen(c->c_lvb); ret = o2dlm_write_lvb(dlm_ctxt, c->c_id, c->c_lvb, len, &bytes); if (!ret) printf("%u bytes written.\n", bytes); break; case HELP: default: print_commands(); } return ret; } int main(int argc, char **argv) { errcode_t error; struct command_s c; initialize_o2dl_error_table(); prog = argv[0]; if (argc < 2) { dlmfs_path = DEFAULT_DLMFS_PATH; printf("No fs path provided, using %s\n", dlmfs_path); } else if (!strcmp(argv[1], "-u")) { dlmfs_path = NULL; printf("Using fsdlm\n"); } else { dlmfs_path = argv[1]; printf("Using fs at %s\n", dlmfs_path); } printf("Type \"help\" to see a list of commands\n"); while (!get_command(&c)) { error = exec_command(&c); if (error) { print_command(&c, "failed!"); com_err(prog, error, "returned\n"); } else print_command(&c, "succeeded!\n"); } return 0; } ./ocfs2-tools-1.6.4/libo2cb/0000775000176100017610000000000011515641640012357 500000000000000./ocfs2-tools-1.6.4/libo2cb/Makefile0000644000176100017610000000231011412747733013737 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make WARNINGS = -Wall -Wstrict-prototypes -Wmissing-prototypes \ -Wmissing-declarations INCLUDES = -I$(TOPDIR)/include -I. LIBRARIES = libo2cb.a CFLAGS += -fPIC ifneq ($(OCFS2_DEBUG_EXE),) DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES)) DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES))) .SECONDARY: UNINST_PROGRAMS += $(DEBUG_EXE_PROGRAMS) debug_%.o : %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) \ $(INCLUDES) $(DEFINES) \ -DDEBUG_EXE -o $@ -c $< debug_%: debug_%.o libo2cb.a $(LINK) $(COM_ERR_LIBS) endif CFILES = \ o2cb_abi.c \ o2cb_crc32.c \ client_proto.c HFILES = \ o2cb_abi.h \ o2cb_crc32.h HFILES_GEN = o2cb_err.h OBJS = $(subst .c,.o,$(CFILES)) \ o2cb_err.o ifneq ($(BUILD_CMAN_SUPPORT),) DEFINES += -DHAVE_CMAN endif $(OBJS): $(HFILES_GEN) o2cb_err.c o2cb_err.h: o2cb_err.et compile_et o2cb_err.et libo2cb.a: $(OBJS) rm -f $@ $(AR) r $@ $^ $(RANLIB) $@ MANS = o2cb.7 DIST_FILES = $(CFILES) $(HFILES) o2cb_err.et o2cb.7.in CLEAN_RULES = clean-err clean-err: rm -f o2cb_err.c o2cb_err.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/libo2cb/o2cb.70000664000176100017610000001116111515641632013215 00000000000000.TH "o2cb" "7" "September 2010" "Version 1.6.4" "OCFS2 Manual Pages" .SH "NAME" o2cb \- Default cluster stack for the \fIOCFS2\fR file system. .SH "DESCRIPTION" .PP \fBo2cb\fR is the default cluster stack for the \fIOCFS2\fR file system. It includes a node manager (o2nm) to keep track of the nodes in the cluster, a heartbeat agent (o2hb) to detect live nodes, a network agent (o2net) for intra-cluster node communication and a distributed lock manager (o2dlm) to keep track of lock resources. All these components are in-kernel. It also includes an in-memory file system, dlmfs, to allow userspace to access the in-kernel dlm. This cluster stack has two configuration files, namely, \fI/etc/ocfs2/cluster.conf\fR and \fI/etc/sysconfig/o2cb\fR. Whereas the former keeps track of the cluster layout, the latter keeps track of the cluster timeouts. Both files are only read when the cluster is brought online. Values in use by the online cluster can be perused in the /sys/kernel/config/cluster directory structure. .SH "CONFIGURATION" .PP The cluster layout is specified in \fB/etc/ocfs2/cluster.conf\fR. While it is easier to populate and propagate this configuration file using \fBocfs2console(8)\fR, one can also do it by manually as long as care is taken to format the file correctly. While the console utility is intuitive to use, there are few points to keep in mind. .TP 1. The node name needs to match the hostname. It does not need to include the domain name. For example, appserver.oracle.com can be appserver. .TP 2. The IP address need not be the one associated with that hostname. As in, any valid IP address on that node can be used. O2CB will not attempt to match the node name (hostname) with the specified IP address. .PP For best performance, use of a private interconnect (lower latency) is recommended. The cluster.conf file is in a stanza format with two types of stanzas, namely, cluster and node. A typical cluster.conf will have one cluster stanza and multiple node stanzas. The \fIcluster stanza\fR has two parameters: .TP \fBnode_count\fR Total number of nodes in the cluster .TP \fBname\fR Name of the cluster .PP The \fInode stanza\fR has five parameters: .TP \fBip_port\fR IP port .TP \fBip_address\fR IP address .TP \fBnumber\fR Unique node number from 0-254 .TP \fBname\fR Hostname .TP \fBcluster\fR Name of the cluster .PP Users populating cluster.conf manually should follow the format strictly. As in, stanza header should start at the first column and end with a colon, stanza parameters should start after a tab, a blank line should demarcate each stanza and care taken to avoid stray whitespaces. The O2CB cluster timeouts are specified in \fB/etc/sysconfig/o2cb\fR and can be configured using the \fIo2cb\fR init script. These timeouts are used by the O2CB clusterstack to determine whether a node is dead or alive. While the use of default values is recommended, users can experiment with other values if the defaults are causing spurious fencing. The \fIcluster timeouts\fR are: .TP \fBHeartbeat Dead Threshold\fR The Disk Heartbeat timeout is the number of two second iterations before a node is considered dead. The exact formula used to convert the timeout in seconds to the number of iterations is as follows: O2CB_HEARTBEAT_THRESHOLD = (((timeout in seconds) / 2) + 1) For e.g., to specify a 60 sec timeout, set it to 31. For 120 secs, set it to 61. The default for this timeout is 60 secs (O2CB_HEARTBEAT_THRESHOLD = 31). .TP \fBNetwork Idle Timeout\fR The Network Idle timeout specifies the time in milliseconds before a network connection is considered dead. It defaults to 30000 ms. .TP \fBNetwork Keepalive Delay\fR The Network Keepalive specifies the maximum delay in milliseconds before a keepalive packet is sent to another node to check whether it is alive or not. If the node is alive, it will respond. Its defaults to 2000 ms. .TP \fBNetwork Reconnect Delay\fR The Network Reconnect specifies the minimum delay in milliseconds between connection attempts. It defaults to 2000 ms. .PP .SH "EXAMPLES" A sample /etc/ocfs2/cluster.conf. cluster: node_count = 3 name = webcluster node: ip_port = 7777 ip_address = 192.168.0.107 number = 7 name = node7 cluster = webcluster node: ip_port = 7777 ip_address = 192.168.0.106 number = 6 name = node6 cluster = webcluster node: ip_port = 7777 ip_address = 192.168.0.110 number = 10 name = node10 cluster = webcluster .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR fsck.ocfs2(8) .BR tunefs.ocfs2(8) .BR debugfs.ocfs2(8) .BR ocfs2console(8) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/libo2cb/o2cb_abi.c0000664000176100017610000013164111506552637014120 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2cb_abi.c * * Kernel<->User ABI for modifying cluster configuration. * * Copyright (C) 2004,2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "o2cb/o2cb.h" #include "o2cb/o2cb_client_proto.h" #include "o2cb_abi.h" #include "o2cb_crc32.h" #define CLUSTER_STACK_FILE "/sys/fs/ocfs2/cluster_stack" #define LOCKING_PROTOCOL_FILE "/sys/fs/ocfs2/max_locking_protocol" #define OCFS2_STACK_LABEL_LEN 4 #define CONTROL_DEVICE "/dev/misc/ocfs2_control" struct o2cb_stack_ops { errcode_t (*list_clusters)(char ***clusters); errcode_t (*begin_group_join)(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); errcode_t (*complete_group_join)(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result); errcode_t (*group_leave)(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); }; struct o2cb_stack { char s_name[OCFS2_STACK_LABEL_LEN + 1]; struct o2cb_stack_ops *s_ops; }; static errcode_t classic_list_clusters(char ***clusters); static errcode_t classic_begin_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); static errcode_t classic_complete_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result); static errcode_t classic_group_leave(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); static struct o2cb_stack_ops classic_ops = { .list_clusters = classic_list_clusters, .begin_group_join = classic_begin_group_join, .complete_group_join = classic_complete_group_join, .group_leave = classic_group_leave, }; static struct o2cb_stack classic_stack = { .s_name = "o2cb", .s_ops = &classic_ops, }; static errcode_t user_list_clusters(char ***clusters); static errcode_t user_begin_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); static errcode_t user_complete_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result); static errcode_t user_group_leave(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region); static struct o2cb_stack_ops user_ops = { .list_clusters = user_list_clusters, .begin_group_join = user_begin_group_join, .complete_group_join = user_complete_group_join, .group_leave = user_group_leave, }; static struct o2cb_stack user_stack = { .s_ops = &user_ops, }; static struct o2cb_stack *current_stack; static int control_daemon_fd = -1; static int control_device_fd = -1; static char *configfs_path; static ssize_t read_single_line_file(const char *file, char *line, size_t count) { ssize_t ret = 0; FILE *f; f = fopen(file, "r"); if (f) { if (fgets(line, count, f)) ret = strlen(line); fclose(f); } else ret = -errno; return ret; } static ssize_t read_stack_file(char *line, size_t count) { return read_single_line_file(CLUSTER_STACK_FILE, line, count); } static errcode_t determine_stack(void) { ssize_t len; char line[100]; errcode_t err = O2CB_ET_SERVICE_UNAVAILABLE; len = read_stack_file(line, sizeof(line)); if (len > 0) { if (line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } if (len != OCFS2_STACK_LABEL_LEN) err = O2CB_ET_INTERNAL_FAILURE; else if (!strcmp(line, classic_stack.s_name)) { current_stack = &classic_stack; err = 0; } else { strncpy(user_stack.s_name, line, OCFS2_STACK_LABEL_LEN); current_stack = &user_stack; err = 0; } } else if (len == -ENOENT) { current_stack = &classic_stack; err = 0; } return err; } errcode_t o2cb_get_stack_name(const char **name) { if (!current_stack) return O2CB_ET_SERVICE_UNAVAILABLE; *name = current_stack->s_name; return 0; } static ssize_t read_locking_proto_file(char *line, size_t count) { return read_single_line_file(LOCKING_PROTOCOL_FILE, line, count); } errcode_t o2cb_get_max_locking_protocol(struct ocfs2_protocol_version *proto) { ssize_t len; char line[100]; errcode_t err; unsigned int major, minor; len = read_locking_proto_file(line, sizeof(line)); if (len <= 0) { switch (-len) { case EACCES: case EPERM: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case 0: case ENOENT: case ENOTDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } goto out; } if (line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } err = O2CB_ET_SERVICE_UNAVAILABLE; if (sscanf(line, "%u.%u", &major, &minor) != 2) goto out; /* Major and minor can't be more than a u8 */ if ((major > (uint8_t)-1) || (minor > (uint8_t)-1)) goto out; proto->pv_major = major; proto->pv_minor = minor; err = 0; out: return err; } errcode_t o2cb_create_cluster(const char *cluster_name) { char path[PATH_MAX]; int ret; errcode_t err = 0; ret = snprintf(path, PATH_MAX - 1, O2CB_FORMAT_CLUSTER, configfs_path, cluster_name); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (ret) { switch (errno) { case EEXIST: err = O2CB_ET_CLUSTER_EXISTS; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case ENOTDIR: case ENOENT: err = O2CB_ET_SERVICE_UNAVAILABLE; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } } return err; } errcode_t o2cb_remove_cluster(const char *cluster_name) { char path[PATH_MAX]; int ret; errcode_t err = 0; ret = snprintf(path, PATH_MAX - 1, O2CB_FORMAT_CLUSTER, configfs_path, cluster_name); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; ret = rmdir(path); if (ret) { switch (errno) { case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case ENOTDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case ENOENT: err = 0; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } } return err; } static int do_read(int fd, void *bytes, size_t count) { int total = 0; int ret; while (total < count) { ret = read(fd, bytes + total, count - total); if (ret < 0) { ret = -errno; if ((ret == -EAGAIN) || (ret == -EINTR)) continue; total = ret; break; } if (ret == 0) break; total += ret; } return total; } static errcode_t do_write(int fd, const void *bytes, size_t count) { int total = 0; int ret; int err = 0; while (total < count) { ret = write(fd, bytes + total, count - total); if (ret < 0) { ret = -errno; if ((ret == -EAGAIN) || (ret == -EINTR)) continue; if (ret == -EIO) err = O2CB_ET_IO; else err = O2CB_ET_INTERNAL_FAILURE; break; } total += ret; } return err; } static errcode_t o2cb_set_attribute(const char *attr_path, const char *attr_value) { errcode_t err = 0; int fd; fd = open(attr_path, O_WRONLY); if (fd < 0) { switch (errno) { default: err = O2CB_ET_INTERNAL_FAILURE; break; case ENOTDIR: case ENOENT: case EISDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; } } else { err = do_write(fd, attr_value, strlen(attr_value)); close(fd); } return err; } static errcode_t o2cb_get_attribute(const char *attr_path, char *attr_value, size_t count) { int ret; errcode_t err = 0; int fd; fd = open(attr_path, O_RDONLY); if (fd < 0) { switch (errno) { default: err = O2CB_ET_INTERNAL_FAILURE; break; case ENOTDIR: case ENOENT: case EISDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; } } else { ret = do_read(fd, attr_value, count); close(fd); if (ret == -EIO) err = O2CB_ET_IO; else if (ret < 0) err = O2CB_ET_INTERNAL_FAILURE; else if (ret < count) attr_value[ret] = '\0'; } return err; } static errcode_t o2cb_set_node_attribute(const char *cluster_name, const char *node_name, const char *attr_name, const char *attr_value) { int ret; char attr_path[PATH_MAX]; ret = snprintf(attr_path, PATH_MAX - 1, O2CB_FORMAT_NODE_ATTR, configfs_path, cluster_name, node_name, attr_name); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; return o2cb_set_attribute(attr_path, attr_value); } static errcode_t o2cb_get_node_attribute(const char *cluster_name, const char *node_name, const char *attr_name, char *attr_value, size_t count) { int ret; char attr_path[PATH_MAX]; ret = snprintf(attr_path, PATH_MAX - 1, O2CB_FORMAT_NODE_ATTR, configfs_path, cluster_name, node_name, attr_name); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; return o2cb_get_attribute(attr_path, attr_value, count); } /* XXX there is no commit yet, so this just creates the node in place * and then sets the attributes in order. if the ipaddr is set * successfully then the node is live */ errcode_t o2cb_add_node(const char *cluster_name, const char *node_name, const char *node_num, const char *ip_address, const char *ip_port, const char *local) { char node_path[PATH_MAX]; int ret; errcode_t err; ret = snprintf(node_path, PATH_MAX - 1, O2CB_FORMAT_NODE, configfs_path, cluster_name, node_name); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out; } ret = mkdir(node_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (ret) { switch (errno) { case EEXIST: err = O2CB_ET_NODE_EXISTS; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case ENOTDIR: case ENOENT: err = O2CB_ET_SERVICE_UNAVAILABLE; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } goto out; } err = o2cb_set_node_attribute(cluster_name, node_name, "ipv4_port", ip_port); if (err) goto out_rmdir; err = o2cb_set_node_attribute(cluster_name, node_name, "ipv4_address", ip_address); if (err) goto out_rmdir; err = o2cb_set_node_attribute(cluster_name, node_name, "num", node_num); if (err) goto out_rmdir; err = o2cb_set_node_attribute(cluster_name, node_name, "local", local); out_rmdir: if (err) rmdir(node_path); out: return err; } errcode_t o2cb_del_node(const char *cluster_name, const char *node_name) { char node_path[PATH_MAX]; int ret; errcode_t err = 0; ret = snprintf(node_path, PATH_MAX - 1, O2CB_FORMAT_NODE, configfs_path, cluster_name, node_name); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out; } ret = rmdir(node_path); if (ret) { switch (errno) { case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case ENOTDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case ENOENT: err = 0; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } } out: return err; } static errcode_t try_file(const char *name, int *fd) { int open_fd; errcode_t err = 0; open_fd = open(name, O_RDONLY); if (open_fd < 0) { switch (errno) { default: err = O2CB_ET_INTERNAL_FAILURE; break; case ENOTDIR: case ENOENT: case EISDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; } } if (!err) *fd = open_fd; return err; } #define O2CB_NEW_CONFIGFS_PATH "/sys/kernel" #define O2CB_OLD_CONFIGFS_PATH "" #define CONFIGFS_MAGIC 0x62656570 static errcode_t try_configfs_path(const char *path) { errcode_t ret; char attr_path[PATH_MAX]; struct stat64 stat_buf; struct statfs64 statfs_buf; ret = snprintf(attr_path, PATH_MAX - 1, CONFIGFS_FORMAT_PATH, path); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; ret = stat64(attr_path, &stat_buf); if (ret || !S_ISDIR(stat_buf.st_mode)) return O2CB_ET_SERVICE_UNAVAILABLE; ret = statfs64(attr_path, &statfs_buf); if (ret || (statfs_buf.f_type != CONFIGFS_MAGIC)) return O2CB_ET_SERVICE_UNAVAILABLE; return 0; } static errcode_t init_configfs(void) { configfs_path = O2CB_NEW_CONFIGFS_PATH; if (!try_configfs_path(configfs_path)) return 0; configfs_path = O2CB_OLD_CONFIGFS_PATH; if (!try_configfs_path(configfs_path)) return 0; configfs_path = NULL; return O2CB_ET_SERVICE_UNAVAILABLE; } #define O2CB_INTERFACE_REVISION_PATH_OLD_PROC "/proc/fs/ocfs2_nodemanager/interface_revision" #define O2CB_INTERFACE_REVISION_PATH_OLD_SYS "/sys/o2cb/interface_revision" #define O2CB_INTERFACE_REVISION_PATH "/sys/fs/o2cb/interface_revision" errcode_t o2cb_init(void) { int ret, fd; unsigned int module_version; errcode_t err; char revision_string[16]; err = determine_stack(); if (err) return err; err = try_file(O2CB_INTERFACE_REVISION_PATH, &fd); if (err == O2CB_ET_SERVICE_UNAVAILABLE) err = try_file(O2CB_INTERFACE_REVISION_PATH_OLD_SYS, &fd); if (err == O2CB_ET_SERVICE_UNAVAILABLE) err = try_file(O2CB_INTERFACE_REVISION_PATH_OLD_PROC, &fd); if (err) return err; ret = do_read(fd, revision_string, sizeof(revision_string) - 1); close(fd); if (ret < 0) { err = O2CB_ET_INTERNAL_FAILURE; if (ret == -EIO) err = O2CB_ET_IO; return err; } revision_string[ret] = '\0'; ret = sscanf(revision_string, "%u\n", &module_version); if (ret < 0) return O2CB_ET_INTERNAL_FAILURE; if (O2NM_API_VERSION < module_version) return O2CB_ET_BAD_VERSION; return init_configfs(); } /* o2cb_get_region_attribute() would just be s/set/get/ of this function */ static errcode_t o2cb_set_region_attribute(const char *cluster_name, const char *region_name, const char *attr_name, const char *attr_value) { int ret; char attr_path[PATH_MAX]; ret = snprintf(attr_path, PATH_MAX - 1, O2CB_FORMAT_HEARTBEAT_REGION_ATTR, configfs_path, cluster_name, region_name, attr_name); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; return o2cb_set_attribute(attr_path, attr_value); } static errcode_t _fake_default_cluster(char *cluster) { errcode_t ret; char **clusters; ret = o2cb_list_clusters(&clusters); if (ret) return ret; snprintf(cluster, NAME_MAX - 1, "%s", clusters[0]); o2cb_free_cluster_list(clusters); return 0; } static errcode_t o2cb_create_heartbeat_region(const char *cluster_name, const char *region_name, const char *device_name, int block_bytes, uint64_t start_block, uint64_t blocks) { char _fake_cluster_name[NAME_MAX]; char region_path[PATH_MAX]; char num_buf[NAME_MAX]; int ret, fd; errcode_t err; if (!cluster_name) { err = _fake_default_cluster(_fake_cluster_name); if (err) return err; cluster_name = _fake_cluster_name; } #define O2CB_MAXIMUM_HEARTBEAT_BLOCKSIZE 4096 if (block_bytes > O2CB_MAXIMUM_HEARTBEAT_BLOCKSIZE) { err = O2CB_ET_INVALID_BLOCK_SIZE; goto out; } #define O2CB_MAX_NODE_COUNT 255 if (!blocks || (blocks > O2CB_MAX_NODE_COUNT)) { err = O2CB_ET_INVALID_BLOCK_COUNT; goto out; } ret = snprintf(region_path, PATH_MAX - 1, O2CB_FORMAT_HEARTBEAT_REGION, configfs_path, cluster_name, region_name); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out; } ret = mkdir(region_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (ret) { switch (errno) { case EEXIST: err = O2CB_ET_REGION_EXISTS; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case ENOTDIR: case ENOENT: err = O2CB_ET_SERVICE_UNAVAILABLE; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } goto out; } ret = snprintf(num_buf, NAME_MAX - 1, "%d", block_bytes); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out_rmdir; } err = o2cb_set_region_attribute(cluster_name, region_name, "block_bytes", num_buf); if (err) goto out_rmdir; ret = snprintf(num_buf, NAME_MAX - 1, "%"PRIu64, start_block); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out_rmdir; } err = o2cb_set_region_attribute(cluster_name, region_name, "start_block", num_buf); if (err) goto out_rmdir; ret = snprintf(num_buf, NAME_MAX - 1, "%"PRIu64, blocks); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out_rmdir; } err = o2cb_set_region_attribute(cluster_name, region_name, "blocks", num_buf); if (err) goto out_rmdir; fd = open64(device_name, O_RDWR); if (fd < 0) { switch (errno) { default: err = O2CB_ET_INTERNAL_FAILURE; break; case ENOTDIR: case ENOENT: case EISDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; } goto out_rmdir; } ret = snprintf(num_buf, NAME_MAX - 1, "%d", fd); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out_close; } err = o2cb_set_region_attribute(cluster_name, region_name, "dev", num_buf); out_close: close(fd); out_rmdir: if (err) rmdir(region_path); out: return err; } static errcode_t o2cb_destroy_sem_set(int semid) { int error; errcode_t ret = 0; error = semctl(semid, 0, IPC_RMID); if (error) { switch(errno) { case EPERM: case EACCES: ret = O2CB_ET_PERMISSION_DENIED; break; case EIDRM: /* Someone raced us to it... can this * happen? */ ret = 0; break; default: ret = O2CB_ET_INTERNAL_FAILURE; } } return ret; } static errcode_t o2cb_get_semid(const char *region, int *semid) { int ret; key_t key; key = (key_t) o2cb_crc32(region); ret = semget(key, 2, IPC_CREAT); if (ret < 0) return O2CB_ET_BAD_SEM; *semid = ret; return 0; } static inline errcode_t o2cb_semop_err(int err) { errcode_t ret; switch (err) { case EACCES: ret = O2CB_ET_PERMISSION_DENIED; break; case EIDRM: /* Other paths depend on us returning this for EIDRM */ ret = O2CB_ET_NO_SEM; break; case EINVAL: ret = O2CB_ET_SERVICE_UNAVAILABLE; break; case ENOMEM: ret = O2CB_ET_NO_MEMORY; break; default: ret = O2CB_ET_INTERNAL_FAILURE; } return ret; } static errcode_t o2cb_mutex_down(int semid) { int err; struct sembuf sops[2] = { { .sem_num = 0, .sem_op = 0, .sem_flg = SEM_UNDO }, { .sem_num = 0, .sem_op = 1, .sem_flg = SEM_UNDO } }; err = semop(semid, sops, 2); if (err) return o2cb_semop_err(errno); return 0; } /* We have coded our semaphore destruction such that you will legally * only get EIDRM when waiting on the mutex. Use this function to look * it up and return it locked - it knows how to loop around on * EIDRM. */ static errcode_t o2cb_mutex_down_lookup(const char *region, int *semid) { int tmpid; errcode_t ret; ret = O2CB_ET_NO_SEM; while (ret == O2CB_ET_NO_SEM) { ret = o2cb_get_semid(region, &tmpid); if (ret) return ret; ret = o2cb_mutex_down(tmpid); if (!ret) { /* At this point, we're the only ones who can destroy * this sem set. */ *semid = tmpid; } } return ret; } static errcode_t o2cb_mutex_up(int semid) { int err; struct sembuf sop = { .sem_num = 0, .sem_op = -1, .sem_flg = SEM_UNDO }; err = semop(semid, &sop, 1); if (err) return o2cb_semop_err(errno); return 0; } static errcode_t __o2cb_get_ref(int semid, int undo) { int err; struct sembuf sop = { .sem_num = 1, .sem_op = 1, .sem_flg = undo ? SEM_UNDO : 0 }; err = semop(semid, &sop, 1); if (err) return o2cb_semop_err(errno); return 0; } errcode_t o2cb_get_region_ref(const char *region_name, int undo) { errcode_t ret, up_ret; int semid; ret = o2cb_mutex_down_lookup(region_name, &semid); if (ret) return ret; ret = __o2cb_get_ref(semid, undo); /* XXX: Maybe try to drop ref if we get an error here? */ up_ret = o2cb_mutex_up(semid); if (up_ret && !ret) ret = up_ret; return ret; } static errcode_t __o2cb_drop_ref(int semid, int undo) { int err; struct sembuf sop = { .sem_num = 1, .sem_op = -1, .sem_flg = undo ? SEM_UNDO : 0 }; err = semop(semid, &sop, 1); if (err) return o2cb_semop_err(errno); return 0; } errcode_t o2cb_put_region_ref(const char *region_name, int undo) { errcode_t ret, up_ret; int semid; ret = o2cb_mutex_down_lookup(region_name, &semid); if (ret) return ret; ret = __o2cb_drop_ref(semid, undo); up_ret = o2cb_mutex_up(semid); if (up_ret && !ret) ret = up_ret; return ret; } static errcode_t __o2cb_get_num_refs(int semid, int *num_refs) { int ret; ret = semctl(semid, 1, GETVAL, NULL); if (ret == -1) return o2cb_semop_err(errno); *num_refs = ret; return 0; } errcode_t o2cb_num_region_refs(const char *region_name, int *num_refs) { errcode_t ret; int semid; ret = o2cb_get_semid(region_name, &semid); if (ret) return ret; ret = __o2cb_get_num_refs(semid, num_refs); /* The semaphore set was destroyed underneath us. We treat * that as zero reference and return success. */ if (ret == O2CB_ET_NO_SEM) { *num_refs = 0; ret = 0; } return ret; } static errcode_t o2cb_remove_heartbeat_region(const char *cluster_name, const char *region_name) { char _fake_cluster_name[NAME_MAX]; char region_path[PATH_MAX]; int ret; errcode_t err = 0; if (!cluster_name) { err = _fake_default_cluster(_fake_cluster_name); if (err) return err; cluster_name = _fake_cluster_name; } ret = snprintf(region_path, PATH_MAX - 1, O2CB_FORMAT_HEARTBEAT_REGION, configfs_path, cluster_name, region_name); if (ret <= 0 || ret == PATH_MAX - 1) { err = O2CB_ET_INTERNAL_FAILURE; goto out; } ret = rmdir(region_path); if (ret) { switch (errno) { case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; case ENOMEM: err = O2CB_ET_NO_MEMORY; break; case ENOTDIR: case ENOENT: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case ENOTEMPTY: case EBUSY: err = O2CB_ET_REGION_IN_USE; break; default: err = O2CB_ET_INTERNAL_FAILURE; break; } } out: return err; } /* For ref counting purposes, we need to know whether this process * called o2cb_create_heartbeat_region_disk. If it did, then we want * to drop the reference taken during startup, otherwise that * reference was dropped automatically at process shutdown so there's * no need to drop one here. */ static errcode_t classic_group_leave(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region) { errcode_t ret, up_ret; int hb_refs; int semid; ret = o2cb_mutex_down_lookup(region->r_name, &semid); if (ret) return ret; ret = __o2cb_get_num_refs(semid, &hb_refs); if (ret) goto up; /* A previous process may have died and left us with no * references on the region. We avoid a negative error count * here and clean up the region as normal. */ if (hb_refs) { ret = __o2cb_drop_ref(semid, !region->r_persist); if (ret) goto up; /* No need to call get_num_refs again -- this was * atomic so we know what the new value must be. */ hb_refs--; } if (!hb_refs) { /* XXX: If this fails, shouldn't we still destroy the * semaphore set? */ ret = o2cb_remove_heartbeat_region(cluster->c_cluster, region->r_name); if (ret) goto up; ret = o2cb_destroy_sem_set(semid); if (ret) goto up; goto done; } up: up_ret = o2cb_mutex_up(semid); if (up_ret && !ret) /* XXX: Maybe stop heartbeat here then? */ ret = up_ret; done: return ret; } static errcode_t classic_begin_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region) { errcode_t ret, up_ret; int semid; ret = o2cb_mutex_down_lookup(region->r_name, &semid); if (ret) return ret; ret = o2cb_create_heartbeat_region(cluster->c_cluster, region->r_name, region->r_device_name, region->r_block_bytes, region->r_start_block, region->r_blocks); if (ret && ret != O2CB_ET_REGION_EXISTS) goto up; ret = __o2cb_get_ref(semid, !region->r_persist); /* XXX: Maybe stop heartbeat on error here? */ up: up_ret = o2cb_mutex_up(semid); if (up_ret && !ret) ret = up_ret; return ret; } static errcode_t classic_complete_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result) { errcode_t ret = 0; if (result) ret = classic_group_leave(cluster, region); return ret; } static errcode_t user_parse_status(char **args, int *error, char **error_msg) { errcode_t err = O2CB_ET_IO; long result; char *ptr = NULL; result = strtol(args[0], &ptr, 10); if (ptr && *ptr != '\0') { /* fprintf(stderr, "Invalid error code string: %s", args[0]); */ } else if ((result == LONG_MIN) || (result == LONG_MAX) || (result < INT_MIN) || (result > INT_MAX)) { /* fprintf(stderr, "Error code %ld out of range", err); */ } else { *error_msg = args[1]; *error = result; err = 0; } return err; } static errcode_t user_begin_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region) { errcode_t err; int rc; int error; char *error_msg; client_message message; char *argv[OCFS2_CONTROLD_MAXARGS + 1]; char buf[OCFS2_CONTROLD_MAXLINE]; if (control_daemon_fd != -1) { /* fprintf(stderr, "Join already in progress!\n"); */ err = O2CB_ET_INTERNAL_FAILURE; goto out; } rc = ocfs2_client_connect(); if (rc < 0) { /* fprintf(stderr, "Unable to connect to ocfs2_controld: %s\n", strerror(-rc)); */ switch (rc) { case -EACCES: case -EPERM: err = O2CB_ET_PERMISSION_DENIED; break; default: err = O2CB_ET_SERVICE_UNAVAILABLE; break; } goto out; } control_daemon_fd = rc; rc = send_message(control_daemon_fd, CM_MOUNT, OCFS2_FS_NAME, region->r_name, cluster->c_cluster, region->r_device_name, region->r_service); if (rc) { /* fprintf(stderr, "Unable to send MOUNT message: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } rc = receive_message(control_daemon_fd, buf, &message, argv); if (rc < 0) { /* fprintf(stderr, "Error reading from daemon: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } switch (message) { case CM_STATUS: err = user_parse_status(argv, &error, &error_msg); if (err) { /* fprintf(stderr, "Bad status message: %s\n", strerror(-rc)); */ goto out; } if (error && (error != EALREADY)) { /* fprintf(stderr, "Error %d from daemon: %s\n", error, error_msg); */ err = O2CB_ET_CONFIGURATION_ERROR; goto out; } break; default: /* fprintf(stderr, "Unexpected message %s from daemon\n", message_to_string(message)); */ err = O2CB_ET_INTERNAL_FAILURE; goto out; break; } err = 0; out: if (err && (control_daemon_fd != -1)) { close(control_daemon_fd); control_daemon_fd = -1; } return err; } static errcode_t user_complete_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result) { errcode_t err = O2CB_ET_SERVICE_UNAVAILABLE; int rc; int error; char *error_msg; client_message message; char *argv[OCFS2_CONTROLD_MAXARGS + 1]; char buf[OCFS2_CONTROLD_MAXLINE]; if (control_daemon_fd == -1) { /* fprintf(stderr, "Join not started!\n"); */ err = O2CB_ET_SERVICE_UNAVAILABLE; goto out; } rc = send_message(control_daemon_fd, CM_MRESULT, OCFS2_FS_NAME, region->r_name, result, region->r_service); if (rc) { /* fprintf(stderr, "Unable to send MRESULT message: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } rc = receive_message(control_daemon_fd, buf, &message, argv); if (rc < 0) { /* fprintf(stderr, "Error reading from daemon: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } switch (message) { case CM_STATUS: err = user_parse_status(argv, &error, &error_msg); if (err) { /* fprintf(stderr, "Bad status message: %s\n", strerror(-rc)); */ goto out; } if (error) { /* fprintf(stderr, "Error %d from daemon: %s\n", error, error_msg); */ err = O2CB_ET_CONFIGURATION_ERROR; } break; default: /* fprintf(stderr, "Unexpected message %s from daemon\n", message_to_string(message)); */ err = O2CB_ET_INTERNAL_FAILURE; goto out; break; } err = 0; out: if (control_daemon_fd != -1) { close(control_daemon_fd); control_daemon_fd = -1; } return err; } static errcode_t user_group_leave(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region) { errcode_t err = O2CB_ET_SERVICE_UNAVAILABLE; int rc; int error; char *error_msg; client_message message; char *argv[OCFS2_CONTROLD_MAXARGS + 1]; char buf[OCFS2_CONTROLD_MAXLINE]; if (control_daemon_fd != -1) { /* fprintf(stderr, "Join in progress!\n"); */ err = O2CB_ET_INTERNAL_FAILURE; goto out; } rc = ocfs2_client_connect(); if (rc < 0) { /* fprintf(stderr, "Unable to connect to ocfs2_controld: %s\n", strerror(-rc)); */ switch (rc) { case -EACCES: case -EPERM: err = O2CB_ET_PERMISSION_DENIED; break; default: err = O2CB_ET_SERVICE_UNAVAILABLE; break; } goto out; } control_daemon_fd = rc; rc = send_message(control_daemon_fd, CM_UNMOUNT, OCFS2_FS_NAME, region->r_name, region->r_service); if (rc) { /* fprintf(stderr, "Unable to send UNMOUNT message: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } rc = receive_message(control_daemon_fd, buf, &message, argv); if (rc < 0) { /* fprintf(stderr, "Error reading from daemon: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } switch (message) { case CM_STATUS: err = user_parse_status(argv, &error, &error_msg); if (err) { /* fprintf(stderr, "Bad status message: %s\n", strerror(-rc)); */ goto out; } if (error) { /* fprintf(stderr, "Error %d from daemon: %s\n", error, error_msg); */ err = O2CB_ET_CONFIGURATION_ERROR; goto out; } break; default: /* fprintf(stderr, "Unexpected message %s from daemon\n", message_to_string(message)); */ err = O2CB_ET_INTERNAL_FAILURE; goto out; break; } err = 0; out: if (control_daemon_fd != -1) { close(control_daemon_fd); control_daemon_fd = -1; } return err; } static errcode_t o2cb_validate_cluster_desc(struct o2cb_cluster_desc *desc) { errcode_t err; const char *name; if (!desc) return O2CB_ET_INVALID_STACK_NAME; if (desc->c_stack && !desc->c_cluster) return O2CB_ET_INVALID_STACK_NAME; err = o2cb_get_stack_name(&name); if (err) return err; if (desc->c_stack) { if (strcmp(desc->c_stack, name)) return O2CB_ET_INVALID_STACK_NAME; } else if (strcmp(name, classic_stack.s_name)) return O2CB_ET_INVALID_STACK_NAME; return 0; } errcode_t o2cb_begin_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region) { errcode_t err; struct o2cb_cluster_desc desc; char _fake_cluster_name[NAME_MAX]; if (!current_stack) return O2CB_ET_SERVICE_UNAVAILABLE; err = o2cb_validate_cluster_desc(cluster); if (err) return err; desc = *cluster; if (!desc.c_cluster) { err = _fake_default_cluster(_fake_cluster_name); if (err) return err; desc.c_cluster = _fake_cluster_name; } return current_stack->s_ops->begin_group_join(&desc, region); } errcode_t o2cb_complete_group_join(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region, int result) { errcode_t err; struct o2cb_cluster_desc desc; char _fake_cluster_name[NAME_MAX]; if (!current_stack) return O2CB_ET_SERVICE_UNAVAILABLE; err = o2cb_validate_cluster_desc(cluster); if (err) return err; desc = *cluster; if (!desc.c_cluster) { err = _fake_default_cluster(_fake_cluster_name); if (err) return err; desc.c_cluster = _fake_cluster_name; } return current_stack->s_ops->complete_group_join(&desc, region, result); } errcode_t o2cb_group_leave(struct o2cb_cluster_desc *cluster, struct o2cb_region_desc *region) { errcode_t err; struct o2cb_cluster_desc desc; char _fake_cluster_name[NAME_MAX]; if (!current_stack) return O2CB_ET_SERVICE_UNAVAILABLE; err = o2cb_validate_cluster_desc(cluster); if (err) return err; desc = *cluster; if (!desc.c_cluster) { err = _fake_default_cluster(_fake_cluster_name); if (err) return err; desc.c_cluster = _fake_cluster_name; } return current_stack->s_ops->group_leave(&desc, region); } void o2cb_free_cluster_desc(struct o2cb_cluster_desc *cluster) { if (cluster->c_stack) free(cluster->c_stack); if (cluster->c_cluster) free(cluster->c_cluster); } errcode_t o2cb_running_cluster_desc(struct o2cb_cluster_desc *cluster) { errcode_t err; const char *stack; char **clusters = NULL; err = o2cb_get_stack_name(&stack); if (err) return err; if (!strcmp(stack, classic_stack.s_name)) { cluster->c_stack = NULL; cluster->c_cluster = NULL; return 0; } cluster->c_stack = strdup(stack); if (!cluster->c_stack) return O2CB_ET_NO_MEMORY; err = o2cb_list_clusters(&clusters); if (err) { free(cluster->c_stack); return err; } /* The first cluster is the default cluster */ if (clusters[0]) { cluster->c_cluster = strdup(clusters[0]); if (!cluster->c_cluster) { free(cluster->c_stack); err = O2CB_ET_NO_MEMORY; } } o2cb_free_cluster_list(clusters); return 0; } static inline int is_dots(const char *name) { size_t len = strlen(name); if (len == 0) return 0; if (name[0] == '.') { if (len == 1) return 1; if (len == 2 && name[1] == '.') return 1; } return 0; } static errcode_t o2cb_list_dir(char *path, char ***objs) { errcode_t ret; int count; char statpath[PATH_MAX]; struct stat stat_buf; DIR *dir; struct dirent *dirent; struct dlist { struct dlist *next; char *name; } *tmp, *list; dir = opendir(path); if (!dir) { switch (errno) { default: ret = O2CB_ET_INTERNAL_FAILURE; break; case ENOTDIR: case ENOENT: ret = O2CB_ET_SERVICE_UNAVAILABLE; break; case ENOMEM: ret = O2CB_ET_NO_MEMORY; break; case EACCES: ret = O2CB_ET_PERMISSION_DENIED; break; } goto out; } ret = O2CB_ET_NO_MEMORY; count = 0; list = NULL; while ((dirent = readdir(dir)) != NULL) { if (is_dots(dirent->d_name)) continue; snprintf(statpath, sizeof(statpath), "%s/%s", path, dirent->d_name); /* Silently ignore, we can't access it anyway */ if (lstat(statpath, &stat_buf)) continue; /* Non-directories are attributes */ if (!S_ISDIR(stat_buf.st_mode)) continue; tmp = malloc(sizeof(struct dlist)); if (!tmp) goto out_free_list; tmp->name = strdup(dirent->d_name); if (!tmp->name) { free(tmp); goto out_free_list; } tmp->next = list; list = tmp; count++; } *objs = malloc(sizeof(char *) * (count + 1)); if (!*objs) goto out_free_list; for (tmp = list, count = 0; tmp; tmp = tmp->next, count++) { (*objs)[count] = tmp->name; tmp->name = NULL; } (*objs)[count] = NULL; ret = 0; out_free_list: while (list) { tmp = list; list = list->next; if (tmp->name) free(tmp->name); free(tmp); } closedir(dir); out: return ret; } static void o2cb_free_dir_list(char **objs) { int i; for (i = 0; objs[i]; i++) free(objs[i]); free(objs); } static errcode_t classic_list_clusters(char ***clusters) { char path[PATH_MAX]; errcode_t ret; if (configfs_path == NULL) return O2CB_ET_SERVICE_UNAVAILABLE; ret = snprintf(path, PATH_MAX - 1, O2CB_FORMAT_CLUSTER_DIR, configfs_path); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; return o2cb_list_dir(path, clusters); } static errcode_t user_list_clusters(char ***clusters) { errcode_t err = O2CB_ET_SERVICE_UNAVAILABLE; int rc, fd = -1; char buf[OCFS2_CONTROLD_MAXLINE]; rc = ocfs2_client_connect(); if (rc < 0) { /* fprintf(stderr, "Unable to connect to ocfs2_controld: %s\n", strerror(-rc)); */ switch (rc) { case -EACCES: case -EPERM: err = O2CB_ET_PERMISSION_DENIED; break; default: err = O2CB_ET_SERVICE_UNAVAILABLE; break; } goto out; } fd = rc; rc = send_message(fd, CM_LISTCLUSTERS); if (rc) { /* fprintf(stderr, "Unable to send LISTCLUSTERS message: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } rc = receive_list(fd, buf, clusters); if (rc) { /* fprintf(stderr, "Error reading from daemon: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } err = 0; out: if (fd != -1) close(fd); return err; } errcode_t o2cb_list_clusters(char ***clusters) { if (!current_stack) return O2CB_ET_SERVICE_UNAVAILABLE; return current_stack->s_ops->list_clusters(clusters); } void o2cb_free_cluster_list(char **clusters) { o2cb_free_dir_list(clusters); } errcode_t o2cb_list_nodes(char *cluster_name, char ***nodes) { char path[PATH_MAX]; errcode_t ret; if (configfs_path == NULL) return O2CB_ET_SERVICE_UNAVAILABLE; ret = snprintf(path, PATH_MAX - 1, O2CB_FORMAT_NODE_DIR, configfs_path, cluster_name); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; return o2cb_list_dir(path, nodes); } void o2cb_free_nodes_list(char **nodes) { o2cb_free_dir_list(nodes); } static errcode_t dump_list_to_string(char **dump_list, char **debug) { int i; size_t len, count = 0; char *ptr; for (i = 0; dump_list[i]; i++) count += strlen(dump_list[i]); *debug = malloc(sizeof(char) * (count + 1)); if (!*debug) return O2CB_ET_NO_MEMORY; ptr = *debug; ptr[count] = '\0'; for (i = 0; dump_list[i]; i++) { len = strlen(dump_list[i]); memcpy(ptr, dump_list[i], len); ptr += len; } return 0; } errcode_t o2cb_control_daemon_debug(char **debug) { errcode_t err = O2CB_ET_SERVICE_UNAVAILABLE; int rc, fd = -1; char buf[OCFS2_CONTROLD_MAXLINE]; char **dump_list = NULL; rc = ocfs2_client_connect(); if (rc < 0) { /* fprintf(stderr, "Unable to connect to ocfs2_controld: %s\n", strerror(-rc)); */ switch (rc) { case -EACCES: case -EPERM: err = O2CB_ET_PERMISSION_DENIED; break; default: err = O2CB_ET_SERVICE_UNAVAILABLE; break; } goto out; } fd = rc; rc = send_message(fd, CM_DUMP); if (rc) { /* fprintf(stderr, "Unable to send DUMP message: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } rc = receive_list(fd, buf, &dump_list); if (rc) { /* fprintf(stderr, "Error reading from daemon: %s\n", strerror(-rc)); */ err = O2CB_ET_IO; goto out; } err = dump_list_to_string(dump_list, debug); o2cb_free_dir_list(dump_list); out: if (fd != -1) close(fd); return err; } errcode_t o2cb_get_hb_thread_pid (const char *cluster_name, const char *region_name, pid_t *pid) { char attr_path[PATH_MAX]; char _fake_cluster_name[NAME_MAX]; char attr_value[16]; errcode_t ret; if (!cluster_name) { ret = _fake_default_cluster(_fake_cluster_name); if (ret) return ret; cluster_name = _fake_cluster_name; } ret = snprintf(attr_path, PATH_MAX - 1, O2CB_FORMAT_HEARTBEAT_REGION_ATTR, configfs_path, cluster_name, region_name, "pid"); if ((ret <= 0) || (ret == (PATH_MAX - 1))) return O2CB_ET_INTERNAL_FAILURE; ret = o2cb_get_attribute(attr_path, attr_value, sizeof(attr_value) - 1); if (ret == 0) *pid = atoi (attr_value); return ret; } errcode_t o2cb_get_node_num(const char *cluster_name, const char *node_name, uint16_t *node_num) { char val[30]; char *p; errcode_t ret; ret = o2cb_get_node_attribute(cluster_name, node_name, "num", val, sizeof(val)); if (ret) return ret; *node_num = strtoul(val, &p, 0); if (!p || (*p && *p != '\n')) return O2CB_ET_INVALID_NODE_NUM; return 0; } /* * The handshake is pretty simple. We need to read all supported control * device protocols from the kernel. Once we've read them, we can write * the protocol we want to use. After that, we're good to go. * * Right now, we will just allow the T01 protocol and not write any * code to handle multiples. We'll add that later if and when it is * necessary. * * The versions read from the kernel are all 4 characers including the * newline. */ #define OCFS2_CONTROL_PROTO "T01\n" #define OCFS2_CONTROL_PROTO_LEN 4 #define OCFS2_CONTROL_MESSAGE_SETNODE_OP "SETN" #define OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN 14 #define OCFS2_CONTROL_MESSAGE_SETVERSION_OP "SETV" #define OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN 11 #define OCFS2_CONTROL_MESSAGE_DOWN_OP "DOWN" #define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN 47 #define OCFS2_CONTROL_MESSAGE_NODENUM_LEN 8 static errcode_t o2cb_control_handshake(unsigned int this_node, struct ocfs2_protocol_version *proto) { errcode_t err = 0; int found = 0; size_t ret; char buf[OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN + 1]; if (control_device_fd == -1) { err = O2CB_ET_INTERNAL_FAILURE; goto out; } buf[OCFS2_CONTROL_PROTO_LEN] = '\0'; while (1) { ret = read(control_device_fd, buf, OCFS2_CONTROL_PROTO_LEN); if (ret == OCFS2_CONTROL_PROTO_LEN) { if (!found && !strcmp(buf, OCFS2_CONTROL_PROTO)) found = 1; continue; } if (ret != 0) err = O2CB_ET_IO; else if (!found) err = O2CB_ET_SERVICE_UNAVAILABLE; /* no match */ break; } if (err) goto out; ret = write(control_device_fd, OCFS2_CONTROL_PROTO, OCFS2_CONTROL_PROTO_LEN); if (ret != OCFS2_CONTROL_PROTO_LEN) { err = O2CB_ET_IO; goto out; } snprintf(buf, OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN + 1, OCFS2_CONTROL_MESSAGE_SETNODE_OP " %08X\n", this_node); ret = write(control_device_fd, buf, OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN); if (ret != OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN) err = O2CB_ET_IO; snprintf(buf, OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN + 1, OCFS2_CONTROL_MESSAGE_SETVERSION_OP " %02X %02X\n", proto->pv_major, proto->pv_minor); ret = write(control_device_fd, buf, OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN); if (ret != OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN) err = O2CB_ET_IO; out: return err; } errcode_t o2cb_control_open(unsigned int this_node, struct ocfs2_protocol_version *proto) { errcode_t err = 0; int rc; if (!current_stack) { err = O2CB_ET_SERVICE_UNAVAILABLE; goto out; } if (control_device_fd != -1) goto out; rc = open(CONTROL_DEVICE, O_RDWR); if (rc < 0) { switch (errno) { default: err = O2CB_ET_INTERNAL_FAILURE; break; case ENOTDIR: case ENOENT: case EISDIR: err = O2CB_ET_SERVICE_UNAVAILABLE; break; case EACCES: case EPERM: case EROFS: err = O2CB_ET_PERMISSION_DENIED; break; } goto out; } control_device_fd = rc; err = o2cb_control_handshake(this_node, proto); if (err) { close(control_device_fd); control_device_fd = -1; } out: return err; } void o2cb_control_close(void) { if (control_device_fd != -1) { close(control_device_fd); control_device_fd = -1; } } errcode_t o2cb_control_node_down(const char *uuid, unsigned int nodeid) { errcode_t err = 0; size_t ret; char buf[OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN + 1]; if (control_device_fd == -1) return O2CB_ET_INTERNAL_FAILURE; snprintf(buf, OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN + 1, "DOWN %.32s %08X\n", uuid, nodeid); ret = write(control_device_fd, buf, OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN); if (ret != OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN) err = O2CB_ET_IO; return err; } errcode_t o2cb_get_hb_ctl_path(char *buf, int count) { int fd; int total = 0; int ret; #define HB_CTL_PATH "/proc/sys/fs/ocfs2/nm/hb_ctl_path" fd = open(HB_CTL_PATH, O_RDONLY); if (fd == -1) { if (errno == ENOENT) return O2CB_ET_MODULE_NOT_LOADED; else return errno; } while (total < count) { ret = read(fd, buf + total, count - total); if (ret < 0) { ret = -errno; if ((ret == -EAGAIN) || (ret == -EINTR)) continue; total = ret; break; } if (ret == 0) break; total += ret; } if (total < 0) { close(fd); return total; } buf[total] = '\0'; if (buf[total - 1] == '\n') buf[total - 1] = '\0'; close(fd); return 0; } ./ocfs2-tools-1.6.4/libo2cb/o2cb_crc32.c0000664000176100017610000001220010673531132014255 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2cb_crc32.c * * Routines for computing a crc * * Crc code copied from scripts/genksyms/genksysms.c. Original header * from that file follows. */ #include "o2cb_crc32.h" /* Generate kernel symbol version hashes. Copyright 1996, 1997 Linux International. New implementation contributed by Richard Henderson Based on original work by Bjorn Ekwall This file was part of the Linux modutils 2.4.22: moved back into the kernel sources by Rusty Russell/Kai Germaschewski. 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. */ static const unsigned int crctab32[] = { 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU }; static inline unsigned long partial_crc32_one(unsigned char c, unsigned long crc) { return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8); } static inline unsigned long partial_crc32(const char *s, unsigned long crc) { while (*s) crc = partial_crc32_one(*s++, crc); return crc; } static inline unsigned long crc32(const char *s) { return partial_crc32(s, 0xffffffff) ^ 0xffffffff; } unsigned long o2cb_crc32(const char *s) { return crc32(s); } ./ocfs2-tools-1.6.4/libo2cb/client_proto.c0000664000176100017610000002164311170734140015145 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2007 Oracle. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. */ #include #include #include #include #include #include #include #include #include #include #include "o2cb/o2cb_client_proto.h" struct client_message { char *cm_command; int cm_argcount; char *cm_format; }; #define BEGIN_MESSAGES(_list) struct client_message _list[] = { #define END_MESSAGES(_list) }; \ int _list##_len = sizeof(_list) / sizeof(_list[0]); #define DEFINE_MESSAGE(_name, _argcount, _format) [CM_##_name] = { \ .cm_command = #_name, \ .cm_argcount = _argcount, \ .cm_format = #_name " " _format, \ }, BEGIN_MESSAGES(message_list) DEFINE_MESSAGE(MOUNT, 5, "%s %s %s %s %s") DEFINE_MESSAGE(MRESULT, 4, "%s %s %d %s") DEFINE_MESSAGE(UNMOUNT, 3, "%s %s %s") DEFINE_MESSAGE(STATUS, 2, "%d %s") DEFINE_MESSAGE(LISTFS, 2, "%s %s") DEFINE_MESSAGE(LISTMOUNTS, 2, "%s %s") DEFINE_MESSAGE(LISTCLUSTERS, 0, "") DEFINE_MESSAGE(ITEMCOUNT, 1, "%u") DEFINE_MESSAGE(ITEM, 1, "%s") DEFINE_MESSAGE(DUMP, 0, "") END_MESSAGES(message_list) const char *message_to_string(client_message message) { return message_list[message].cm_command; } /* No short reads allowed */ static int full_read(int fd, void *buf, size_t count) { size_t off = 0; ssize_t rc = 0; while (off < count) { rc = read(fd, buf + off, count - off); if (rc == 0) return -EPIPE; if (rc == -1) { rc = -errno; if (rc == -EINTR) continue; break; } off += rc; rc = 0; } return rc; } /* No short writes allowed */ static int full_write(int fd, void *buf, size_t count) { size_t off = 0; ssize_t rc = 0; while (off < count) { rc = write(fd, buf + off, count - off); if (rc == 0) return -EPIPE; if (rc == -1) { rc = -errno; if (rc == -EINTR) continue; break; } off += rc; rc = 0; } return rc; } int send_message(int fd, client_message message, ...) { int rc; size_t len; va_list args; char mbuf[OCFS2_CONTROLD_MAXLINE]; memset(mbuf, 0, OCFS2_CONTROLD_MAXLINE); va_start(args, message); rc = vsnprintf(mbuf, OCFS2_CONTROLD_MAXLINE, message_list[message].cm_format, args); va_end(args); /* Remove the trailing space from zero-argument messages */ if (!message_list[message].cm_argcount) { len = strlen(mbuf); if (mbuf[len - 1] == ' ') mbuf[len - 1] = '\0'; } if (rc >= OCFS2_CONTROLD_MAXLINE) rc = -E2BIG; else rc = full_write(fd, mbuf, OCFS2_CONTROLD_MAXLINE); return rc; } static char *get_args(char *buf, int *argc, char **argv, char sep, int want) { char *p = buf, *rp = NULL; int i = 0; /* Skip the first word, which is the command */ p = strchr(buf, sep); if (!p) goto out; p += 1; argv[0] = p; for (i = 1; i < OCFS2_CONTROLD_MAXARGS; i++) { p = strchr(p, sep); if (!p) { rp = p + 1; break; } if (want == i) break; *p = '\0'; p += 1; argv[i] = p; } out: if (argc) *argc = i; /* Terminate the list, the caller expects us to */ argv[i] = NULL; /* we ended by hitting \0, return the point following that */ if (!rp) rp = strchr(buf, '\0') + 1; return rp; } int receive_message_full(int fd, char *buf, client_message *message, char **argv, char **rest) { int i, rc, len, count; client_message msg; char *r; rc = full_read(fd, buf, OCFS2_CONTROLD_MAXLINE); if (rc) goto out; /* Safety first */ buf[OCFS2_CONTROLD_MAXLINE - 1] = '\0'; /* fprintf(stderr, "Got messsage \"%s\"\n", buf); */ for (i = 0; i < message_list_len; i++) { len = strlen(message_list[i].cm_command); if (!strncmp(buf, message_list[i].cm_command, len) && ((buf[len] == ' ') || (buf[len] == '\0'))) break; } if (i >= message_list_len) { rc = -EBADMSG; goto out; } msg = i; r = get_args(buf, &count, argv, ' ', message_list[msg].cm_argcount); if (count != message_list[msg].cm_argcount) { rc = -EBADMSG; } else { /* for (i = 0; i < count; i++) fprintf(stderr, "Arg %d: \"%s\"\n", i, argv[i]); */ if (message) *message = msg; if (rest) *rest = r; } out: return rc; } int receive_message(int fd, char *buf, client_message *message, char **argv) { return receive_message_full(fd, buf, message, argv, NULL); } static int parse_itemcount(char **args, unsigned int *count) { int rc = 0; unsigned long n; char *ptr = NULL; n = strtoul(args[0], &ptr, 10); if (ptr && *ptr != '\0') { fprintf(stderr, "Invalid error code string: %s", args[0]); rc = -EINVAL; } else if ((n == LONG_MAX) || (n > UINT_MAX)) { fprintf(stderr, "Item count %lu out of range", n); rc = -ERANGE; } else { *count = n; } return rc; } int parse_status(char **args, int *error, char **error_msg) { int rc = 0; long err; char *ptr = NULL; err = strtol(args[0], &ptr, 10); if (ptr && *ptr != '\0') { fprintf(stderr, "Invalid error code string: %s", args[0]); rc = -EINVAL; } else if ((err == LONG_MIN) || (err == LONG_MAX) || (err < INT_MIN) || (err > INT_MAX)) { fprintf(stderr, "Error code %ld out of range", err); rc = -ERANGE; } else { *error_msg = args[1]; *error = err; } return rc; } /* * A list is sent as * * ITEMCOUNT * ITEM * x * STATUS 0 OK * * If there are errors in the middle, we'll get a STATUS error. */ int receive_list(int fd, char *buf, char ***ret_list) { int rc, done = 0; int error; unsigned int count = 0, seen = 0; char *error_msg; client_message message; char **list = NULL; char *argv[OCFS2_CONTROLD_MAXARGS + 1]; /* * States are simple. If list==NULL, we haven't gotten ITEMCOUNT * yet. If list!=NULL and seen= count) { rc = -E2BIG; fprintf(stderr, "Too many items!\n"); } else { list[seen] = strdup(argv[0]); if (!list[seen]) rc = -ENOMEM; else seen++; } break; default: rc = -EINVAL; fprintf(stderr, "Unexpected message %s from daemon\n", message_to_string(message)); break; } if (rc) done = 1; } if (!rc) { if (ret_list) *ret_list = list; } else if (list) { for (seen = 0; list[seen]; seen++) free(list[seen]); free(list); } return rc; } void free_received_list(char **list) { int i; for (i = 0; list[i]; i++) free(list[i]); free(list); } int client_listen(const char *path) { struct sockaddr_un addr; socklen_t addrlen; int rv, s; /* we listen for new client connections on socket s */ s = socket(AF_LOCAL, SOCK_STREAM, 0); if (s < 0) { /* log_error("socket error %d %d", s, errno); */ return s; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; strcpy(&addr.sun_path[1], path); addrlen = sizeof(sa_family_t) + strlen(addr.sun_path+1) + 1; rv = bind(s, (struct sockaddr *) &addr, addrlen); if (rv < 0) { /* log_error("bind error %d %d", rv, errno); */ close(s); return rv; } rv = listen(s, 5); if (rv < 0) { /* log_error("listen error %d %d", rv, errno); */ close(s); return rv; } /* log_debug("listen %d", s); */ return s; } int client_connect(const char *path) { struct sockaddr_un sun; socklen_t addrlen; int rv, fd; fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { fd = -errno; goto out; } memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; strcpy(&sun.sun_path[1], path); addrlen = sizeof(sa_family_t) + strlen(sun.sun_path+1) + 1; rv = connect(fd, (struct sockaddr *) &sun, addrlen); if (rv < 0) { close(fd); fd = -errno; } out: return fd; } ./ocfs2-tools-1.6.4/libo2cb/o2cb_abi.h0000664000176100017610000000311511506552637014117 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2cb_abi.c * * Layout of configfs paths for O2CB cluster configuration. * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #ifndef _O2CB_ABI_H #define _O2CB_ABI_H /* * The latest place is /sys/kernel/config, but older O2CB put it * at /config. So, libo2cb has to handle detection */ #define CONFIGFS_FORMAT_PATH "%s/config" #define O2CB_FORMAT_CLUSTER_DIR CONFIGFS_FORMAT_PATH "/cluster" #define O2CB_FORMAT_CLUSTER O2CB_FORMAT_CLUSTER_DIR "/%s" #define O2CB_FORMAT_NODE_DIR O2CB_FORMAT_CLUSTER "/node" #define O2CB_FORMAT_NODE O2CB_FORMAT_NODE_DIR "/%s" #define O2CB_FORMAT_NODE_ATTR O2CB_FORMAT_NODE "/%s" #define O2CB_FORMAT_HEARTBEAT_DIR O2CB_FORMAT_CLUSTER "/heartbeat" #define O2CB_FORMAT_HEARTBEAT_REGION O2CB_FORMAT_HEARTBEAT_DIR "/%s" #define O2CB_FORMAT_HEARTBEAT_REGION_ATTR O2CB_FORMAT_HEARTBEAT_REGION "/%s" #endif /* _O2CB_ABI_H */ ./ocfs2-tools-1.6.4/libo2cb/o2cb_crc32.h0000644000176100017610000000172611115551035014267 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * o2cb_crc32.h * * libo2cb interface to crc32 functionality. * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #ifndef _O2CB_CRC32_H #define _O2CB_CRC32_H unsigned long o2cb_crc32(const char *s); #endif /* _O2CB_CRC32_H */ ./ocfs2-tools-1.6.4/libo2cb/o2cb_err.et0000664000176100017610000000400411506552637014333 00000000000000# # o2cb_err.et # # Error codes for the O2CB library. # # Copyright (C) 2004 Oracle. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License, version 2, as published by the Free Software Foundation. # # 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 021110-1307, USA. # error_table o2cb ec O2CB_ET_INVALID_CLUSTER_NAME, "Invalid name for a cluster" ec O2CB_ET_NO_MEMORY, "Memory allocation failed" ec O2CB_ET_IO, "I/O error on channel" ec O2CB_ET_SERVICE_UNAVAILABLE, "Unable to access cluster service" ec O2CB_ET_INTERNAL_FAILURE, "Internal logic failure" ec O2CB_ET_PERMISSION_DENIED, "Insufficient permissions to access cluster service" ec O2CB_ET_CLUSTER_EXISTS, "Cluster already exists" ec O2CB_ET_NODE_EXISTS, "Node already exists" ec O2CB_ET_REGION_EXISTS, "Heartbeat region already exists" ec O2CB_ET_REGION_IN_USE, "Heartbeat region in use" ec O2CB_ET_INVALID_BLOCK_SIZE, "Block size is invalid" ec O2CB_ET_INVALID_BLOCK_COUNT, "Block count is invalid" ec O2CB_ET_HOSTNAME_UNKNOWN, "Could not determine local host name" ec O2CB_ET_CONFIGURATION_ERROR, "Configuration error discovered" ec O2CB_ET_INVALID_NODE_NUM, "Node number is invalid" ec O2CB_ET_MODULE_NOT_LOADED, "Node manager kernel module is not loaded" ec O2CB_ET_BAD_SEM, "Could not access heartbeat region semaphore set" ec O2CB_ET_NO_SEM, "Region semaphore set destroyed" ec O2CB_ET_BAD_VERSION, "Revision of OCFS2-Tools is out of date." ec O2CB_ET_INVALID_STACK_NAME, "Cluster stack specified does not match the one currently running" end ./ocfs2-tools-1.6.4/libo2cb/o2cb.7.in0000644000176100017610000001116511500500544013612 00000000000000.TH "o2cb" "7" "September 2010" "Version @VERSION@" "OCFS2 Manual Pages" .SH "NAME" o2cb \- Default cluster stack for the \fIOCFS2\fR file system. .SH "DESCRIPTION" .PP \fBo2cb\fR is the default cluster stack for the \fIOCFS2\fR file system. It includes a node manager (o2nm) to keep track of the nodes in the cluster, a heartbeat agent (o2hb) to detect live nodes, a network agent (o2net) for intra-cluster node communication and a distributed lock manager (o2dlm) to keep track of lock resources. All these components are in-kernel. It also includes an in-memory file system, dlmfs, to allow userspace to access the in-kernel dlm. This cluster stack has two configuration files, namely, \fI/etc/ocfs2/cluster.conf\fR and \fI/etc/sysconfig/o2cb\fR. Whereas the former keeps track of the cluster layout, the latter keeps track of the cluster timeouts. Both files are only read when the cluster is brought online. Values in use by the online cluster can be perused in the /sys/kernel/config/cluster directory structure. .SH "CONFIGURATION" .PP The cluster layout is specified in \fB/etc/ocfs2/cluster.conf\fR. While it is easier to populate and propagate this configuration file using \fBocfs2console(8)\fR, one can also do it by manually as long as care is taken to format the file correctly. While the console utility is intuitive to use, there are few points to keep in mind. .TP 1. The node name needs to match the hostname. It does not need to include the domain name. For example, appserver.oracle.com can be appserver. .TP 2. The IP address need not be the one associated with that hostname. As in, any valid IP address on that node can be used. O2CB will not attempt to match the node name (hostname) with the specified IP address. .PP For best performance, use of a private interconnect (lower latency) is recommended. The cluster.conf file is in a stanza format with two types of stanzas, namely, cluster and node. A typical cluster.conf will have one cluster stanza and multiple node stanzas. The \fIcluster stanza\fR has two parameters: .TP \fBnode_count\fR Total number of nodes in the cluster .TP \fBname\fR Name of the cluster .PP The \fInode stanza\fR has five parameters: .TP \fBip_port\fR IP port .TP \fBip_address\fR IP address .TP \fBnumber\fR Unique node number from 0-254 .TP \fBname\fR Hostname .TP \fBcluster\fR Name of the cluster .PP Users populating cluster.conf manually should follow the format strictly. As in, stanza header should start at the first column and end with a colon, stanza parameters should start after a tab, a blank line should demarcate each stanza and care taken to avoid stray whitespaces. The O2CB cluster timeouts are specified in \fB/etc/sysconfig/o2cb\fR and can be configured using the \fIo2cb\fR init script. These timeouts are used by the O2CB clusterstack to determine whether a node is dead or alive. While the use of default values is recommended, users can experiment with other values if the defaults are causing spurious fencing. The \fIcluster timeouts\fR are: .TP \fBHeartbeat Dead Threshold\fR The Disk Heartbeat timeout is the number of two second iterations before a node is considered dead. The exact formula used to convert the timeout in seconds to the number of iterations is as follows: O2CB_HEARTBEAT_THRESHOLD = (((timeout in seconds) / 2) + 1) For e.g., to specify a 60 sec timeout, set it to 31. For 120 secs, set it to 61. The default for this timeout is 60 secs (O2CB_HEARTBEAT_THRESHOLD = 31). .TP \fBNetwork Idle Timeout\fR The Network Idle timeout specifies the time in milliseconds before a network connection is considered dead. It defaults to 30000 ms. .TP \fBNetwork Keepalive Delay\fR The Network Keepalive specifies the maximum delay in milliseconds before a keepalive packet is sent to another node to check whether it is alive or not. If the node is alive, it will respond. Its defaults to 2000 ms. .TP \fBNetwork Reconnect Delay\fR The Network Reconnect specifies the minimum delay in milliseconds between connection attempts. It defaults to 2000 ms. .PP .SH "EXAMPLES" A sample /etc/ocfs2/cluster.conf. cluster: node_count = 3 name = webcluster node: ip_port = 7777 ip_address = 192.168.0.107 number = 7 name = node7 cluster = webcluster node: ip_port = 7777 ip_address = 192.168.0.106 number = 6 name = node6 cluster = webcluster node: ip_port = 7777 ip_address = 192.168.0.110 number = 10 name = node10 cluster = webcluster .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR fsck.ocfs2(8) .BR tunefs.ocfs2(8) .BR debugfs.ocfs2(8) .BR ocfs2console(8) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/libocfs2/0000775000176100017610000000000011515641640012546 500000000000000./ocfs2-tools-1.6.4/libocfs2/Makefile0000644000176100017610000000370211500500544014115 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make INCLUDES = -I$(TOPDIR)/include LIBRARIES = libocfs2.a LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm $(DL_LIBS) LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a CFLAGS += -fPIC ifneq ($(OCFS2_DEBUG_EXE),) DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES)) DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES))) .SECONDARY: UNINST_PROGRAMS += $(DEBUG_EXE_PROGRAMS) debug_%.o : %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) \ $(INCLUDES) $(DEFINES) \ -DDEBUG_EXE -o $@ -c $< debug_%: debug_%.o libocfs2.a $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LINK) $(COM_ERR_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) endif CFILES = \ alloc.c \ bitmap.c \ bitops.c \ blockcheck.c \ cached_inode.c \ chain.c \ chainalloc.c \ checkhb.c \ closefs.c \ dirblock.c \ dir_iterate.c \ dir_scan.c \ dlm.c \ fileio.c \ freefs.c \ expanddir.c \ extend_file.c \ extents.c \ extent_map.c \ getsectsize.c \ getsize.c \ heartbeat.c \ inode.c \ inode_scan.c \ ismounted.c \ kernel-rbtree.c \ link.c \ lookup.c \ memory.c \ mkjournal.c \ namei.c \ openfs.c \ slot_map.c \ sysfile.c \ truncate.c \ unix_io.c \ unlink.c \ lockid.c \ backup_super.c \ feature_string.c\ quota.c \ image.c \ xattr.c \ extent_tree.c \ refcount.c \ dir_indexed.c HFILES = \ bitmap.h \ crc32table.h \ dir_iterate.h \ dir_util.h \ extent_map.h \ extent_tree.h \ refcount.h HFILES_GEN = ocfs2_err.h OBJS = $(subst .c,.o,$(CFILES)) \ ocfs2_err.o $(OBJS): $(HFILES_GEN) ocfs2_err.c ocfs2_err.h: ocfs2_err.et compile_et ocfs2_err.et libocfs2.a: $(OBJS) rm -f $@ $(AR) r $@ $^ $(RANLIB) $@ DIST_FILES = $(CFILES) $(HFILES) ocfs2_err.et CLEAN_RULES = clean-err clean-err: rm -f ocfs2_err.c ocfs2_err.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/libocfs2/alloc.c0000644000176100017610000005225111500500544013716 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * alloc.c * * Allocate inodes, extent_blocks, and actual data space. Part of the * OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/ocfs2.h" static errcode_t ocfs2_chain_alloc_with_io(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t *gd_blkno, uint16_t *suballoc_bit, uint64_t *bitno) { errcode_t ret; if (!cinode->ci_chains) { ret = ocfs2_load_chain_allocator(fs, cinode); if (ret) return ret; } ret = ocfs2_chain_alloc(fs, cinode, gd_blkno, suballoc_bit, bitno); if (ret) return ret; return ocfs2_write_chain_allocator(fs, cinode); } static errcode_t ocfs2_chain_free_with_io(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno) { errcode_t ret; if (!cinode->ci_chains) { ret = ocfs2_load_chain_allocator(fs, cinode); if (ret) return ret; } ret = ocfs2_chain_free(fs, cinode, bitno); if (ret) return ret; return ocfs2_write_chain_allocator(fs, cinode); } static errcode_t ocfs2_load_allocator(ocfs2_filesys *fs, int type, int slot_num, ocfs2_cached_inode **alloc_cinode) { errcode_t ret; uint64_t blkno; if (!*alloc_cinode) { ret = ocfs2_lookup_system_inode(fs, type, slot_num, &blkno); if (ret) return ret; ret = ocfs2_read_cached_inode(fs, blkno, alloc_cinode); if (ret) return ret; } if (!(*alloc_cinode)->ci_chains) { ret = ocfs2_load_chain_allocator(fs, *alloc_cinode); if (ret) return ret; } return 0; } /* * This function is duplicated in mkfs.ocfs2/mkfs.c. * Please keep them in sync. */ static int ocfs2_clusters_per_group(int block_size, int cluster_size_bits) { int megabytes; switch (block_size) { case 4096: case 2048: megabytes = 4; break; case 1024: megabytes = 2; break; case 512: default: megabytes = 1; break; } #define ONE_MB_SHIFT 20 return (megabytes << ONE_MB_SHIFT) >> cluster_size_bits; } static void ocfs2_zero_dinode_id2_with_xattr(int blocksize, struct ocfs2_dinode *di) { unsigned int xattrsize = di->i_xattr_inline_size; if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2) - xattrsize); else memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2)); } void ocfs2_dinode_new_extent_list(ocfs2_filesys *fs, struct ocfs2_dinode *di) { ocfs2_zero_dinode_id2_with_xattr(fs->fs_blocksize, di); di->id2.i_list.l_tree_depth = 0; di->id2.i_list.l_next_free_rec = 0; di->id2.i_list.l_count = ocfs2_extent_recs_per_inode(fs->fs_blocksize); } void ocfs2_set_inode_data_inline(ocfs2_filesys *fs, struct ocfs2_dinode *di) { struct ocfs2_inline_data *idata = &di->id2.i_data; ocfs2_zero_dinode_id2_with_xattr(fs->fs_blocksize, di); idata->id_count = ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di); di->i_dyn_features |= OCFS2_INLINE_DATA_FL; } static void ocfs2_init_inode(ocfs2_filesys *fs, struct ocfs2_dinode *di, int16_t slot, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t blkno, uint16_t mode, uint32_t flags) { int cs_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; unsigned int tl_recs; di->i_generation = fs->fs_super->i_generation; di->i_fs_generation = fs->fs_super->i_fs_generation; di->i_blkno = blkno; di->i_suballoc_slot = slot; di->i_suballoc_loc = gd_blkno; di->i_suballoc_bit = suballoc_bit; di->i_uid = di->i_gid = 0; di->i_mode = mode; if (S_ISDIR(di->i_mode)) di->i_links_count = 2; else di->i_links_count = 1; strcpy((char *)di->i_signature, OCFS2_INODE_SIGNATURE); di->i_atime = di->i_ctime = di->i_mtime = time(NULL); di->i_dtime = 0; di->i_flags = flags; if (flags & OCFS2_LOCAL_ALLOC_FL) { di->id2.i_lab.la_size = ocfs2_local_alloc_size(fs->fs_blocksize); return ; } if (flags & OCFS2_CHAIN_FL) { di->id2.i_chain.cl_count = ocfs2_chain_recs_per_inode(fs->fs_blocksize); di->id2.i_chain.cl_cpg = ocfs2_clusters_per_group(fs->fs_blocksize, cs_bits); di->id2.i_chain.cl_bpc = fs->fs_clustersize / fs->fs_blocksize; di->id2.i_chain.cl_next_free_rec = 0; return ; } if (flags & OCFS2_DEALLOC_FL) { tl_recs = ocfs2_truncate_recs_per_inode(fs->fs_blocksize); di->id2.i_dealloc.tl_count = tl_recs; return ; } if (flags & OCFS2_SUPER_BLOCK_FL) return ; if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) && S_ISDIR(di->i_mode)) ocfs2_set_inode_data_inline(fs, di); else ocfs2_dinode_new_extent_list(fs, di); } static void ocfs2_init_eb(ocfs2_filesys *fs, struct ocfs2_extent_block *eb, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t blkno) { strcpy((char *)eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE); eb->h_fs_generation = fs->fs_super->i_fs_generation; eb->h_blkno = blkno; eb->h_suballoc_slot = 0; eb->h_suballoc_loc = gd_blkno; eb->h_suballoc_bit = suballoc_bit; eb->h_list.l_count = ocfs2_extent_recs_per_eb(fs->fs_blocksize); } errcode_t ocfs2_new_inode(ocfs2_filesys *fs, uint64_t *ino, int mode) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, INODE_ALLOC_SYSTEM_INODE, 0, &fs->fs_inode_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_inode_allocs[0], &gd_blkno, &suballoc_bit, ino); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_inode_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_inode_allocs[0], &gd_blkno, &suballoc_bit, ino); if (ret) goto out; } else if (ret) goto out; memset(buf, 0, fs->fs_blocksize); di = (struct ocfs2_dinode *)buf; ocfs2_init_inode(fs, di, 0, gd_blkno, suballoc_bit, *ino, mode, OCFS2_VALID_FL); ret = ocfs2_write_inode(fs, *ino, buf); if (ret) ocfs2_delete_inode(fs, *ino); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_new_system_inode(ocfs2_filesys *fs, uint64_t *ino, int mode, int flags) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, GLOBAL_INODE_ALLOC_SYSTEM_INODE, 0, &fs->fs_system_inode_alloc); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_system_inode_alloc, &gd_blkno, &suballoc_bit, ino); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_system_inode_alloc); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_system_inode_alloc, &gd_blkno, &suballoc_bit, ino); if (ret) goto out; } memset(buf, 0, fs->fs_blocksize); di = (struct ocfs2_dinode *)buf; ocfs2_init_inode(fs, di, -1, gd_blkno, suballoc_bit, *ino, mode, (flags | OCFS2_VALID_FL | OCFS2_SYSTEM_FL)); ret = ocfs2_write_inode(fs, *ino, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_inode(ocfs2_filesys *fs, uint64_t ino) { errcode_t ret; char *buf; struct ocfs2_dinode *di; int16_t slot; ocfs2_cached_inode **inode_alloc; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, ino, buf); if (ret) goto out; di = (struct ocfs2_dinode *)buf; slot = di->i_suballoc_slot; if (slot == OCFS2_INVALID_SLOT) { inode_alloc = &fs->fs_system_inode_alloc; ret = ocfs2_load_allocator(fs, GLOBAL_INODE_ALLOC_SYSTEM_INODE, 0, inode_alloc); } else { inode_alloc = &fs->fs_inode_allocs[slot]; ret = ocfs2_load_allocator(fs, INODE_ALLOC_SYSTEM_INODE, slot, inode_alloc); } if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, *inode_alloc, ino); if (ret) goto out; di->i_flags &= ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL); di->i_dtime = time(NULL); ret = ocfs2_write_inode(fs, di->i_blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_test_inode_allocated(ocfs2_filesys *fs, uint64_t blkno, int *is_allocated) { int16_t slot; uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ocfs2_cached_inode **ci; int type; errcode_t ret = OCFS2_ET_INTERNAL_FAILURE; for (slot = OCFS2_INVALID_SLOT; slot != max_slots; slot++) { if (slot == OCFS2_INVALID_SLOT) { type = GLOBAL_INODE_ALLOC_SYSTEM_INODE; ci = &fs->fs_system_inode_alloc; } else { type = INODE_ALLOC_SYSTEM_INODE; ci = &fs->fs_inode_allocs[slot]; } ret = ocfs2_load_allocator(fs, type, slot, ci); if (ret) break; ret = ocfs2_chain_test(fs, *ci, blkno, is_allocated); if (ret != OCFS2_ET_INVALID_BIT) break; } return ret; } errcode_t ocfs2_new_extent_block(ocfs2_filesys *fs, uint64_t *blkno) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_extent_block *eb; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, 0, &fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret) goto out; } else if (ret) goto out; memset(buf, 0, fs->fs_blocksize); eb = (struct ocfs2_extent_block *)buf; ocfs2_init_eb(fs, eb, gd_blkno, suballoc_bit, *blkno); ret = ocfs2_write_extent_block(fs, *blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_xattr_block(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf; int slot; struct ocfs2_xattr_block *xb = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_xattr_block(fs, blkno, buf); if (ret) goto out; xb = (struct ocfs2_xattr_block *)buf; slot = xb->xb_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno); if (ret) goto out; out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_extent_block(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf; struct ocfs2_extent_block *eb; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_extent_block(fs, blkno, buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)buf; slot = eb->h_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno); if (ret) goto out; ret = ocfs2_write_extent_block(fs, eb->h_blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_refcount_block(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf; struct ocfs2_refcount_block *rb; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_refcount_block(fs, blkno, buf); if (ret) goto out; rb = (struct ocfs2_refcount_block *)buf; slot = rb->rf_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno); out: ocfs2_free(&buf); return ret; } static void ocfs2_init_rb(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t blkno, uint64_t root_blkno, uint32_t rf_generation) { strcpy((void *)rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE); rb->rf_fs_generation = fs->fs_super->i_fs_generation; rb->rf_blkno = blkno; rb->rf_suballoc_slot = 0; rb->rf_suballoc_loc = gd_blkno; rb->rf_suballoc_bit = suballoc_bit; rb->rf_parent = root_blkno; if (root_blkno) rb->rf_flags = OCFS2_REFCOUNT_LEAF_FL; rb->rf_records.rl_count = ocfs2_refcount_recs_per_rb(fs->fs_blocksize); rb->rf_generation = rf_generation; } errcode_t ocfs2_new_refcount_block(ocfs2_filesys *fs, uint64_t *blkno, uint64_t root_blkno, uint32_t rf_generation) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_refcount_block *rb; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, 0, &fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret) goto out; } else if (ret) goto out; memset(buf, 0, fs->fs_blocksize); rb = (struct ocfs2_refcount_block *)buf; ocfs2_init_rb(fs, rb, gd_blkno, suballoc_bit, *blkno, root_blkno, rf_generation); ret = ocfs2_write_refcount_block(fs, *blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_grow_chain_allocator(ocfs2_filesys *fs, int type, int slot_num, uint32_t num_clusters) { errcode_t ret = OCFS2_ET_INVALID_ARGUMENT; ocfs2_cached_inode *ci; int i, num_groups, cpg; switch (type) { case EXTENT_ALLOC_SYSTEM_INODE: ci = fs->fs_eb_allocs[slot_num]; break; case INODE_ALLOC_SYSTEM_INODE: ci = fs->fs_inode_allocs[slot_num]; break; case GLOBAL_INODE_ALLOC_SYSTEM_INODE: ci = fs->fs_system_inode_alloc; break; default: goto out; } ret = ocfs2_load_allocator(fs, type, slot_num, &ci); if (ret) goto out; cpg = ci->ci_inode->id2.i_chain.cl_cpg; num_groups = (num_clusters + cpg - 1) / cpg; for (i = 0; i < num_groups; ++i) { ret = ocfs2_chain_add_group(fs, ci); if (ret) goto out; } out: return ret; } /* only initiate part of dx_root: * dr_subllaoc_slot * dr_sbualloc_bit * dr_fs_generation * dr_blkno * dr_flags */ static void init_dx_root(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, int slot, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t dr_blkno) { memset(dx_root, 0, fs->fs_blocksize); strcpy((char *)dx_root->dr_signature, OCFS2_DX_ROOT_SIGNATURE); dx_root->dr_suballoc_slot = slot; dx_root->dr_suballoc_loc = gd_blkno; dx_root->dr_suballoc_bit = suballoc_bit; dx_root->dr_fs_generation = fs->fs_super->i_fs_generation; dx_root->dr_blkno = dr_blkno; dx_root->dr_flags |= OCFS2_DX_FLAG_INLINE; } errcode_t ocfs2_new_dx_root(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t *dr_blkno) { errcode_t ret; char *buf = NULL; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_dx_root_block *dx_root; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; slot = di->i_suballoc_slot; if (slot == (uint16_t)OCFS2_INVALID_SLOT) slot = 0; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[slot], &gd_blkno, &suballoc_bit, dr_blkno); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[slot], &gd_blkno, &suballoc_bit, dr_blkno); if (ret) goto out; } else if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)buf; init_dx_root(fs, dx_root, slot, gd_blkno, suballoc_bit, *dr_blkno); ret = ocfs2_write_dx_root(fs, *dr_blkno, (char *)dx_root); out: if (buf) ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_dx_root(ocfs2_filesys *fs, uint64_t dr_blkno) { errcode_t ret; char *buf = NULL; struct ocfs2_dx_root_block *dx_root; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, dr_blkno, buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)buf; slot = dx_root->dr_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], dr_blkno); out: if (buf) ocfs2_free(&buf); return ret; } /* XXX what to do about local allocs? * XXX Well, we shouldn't use local allocs to allocate, as we are * userspace and we have the entire bitmap in memory. However, this * doesn't solve the issue of "is space still in dirty local * allocs?" */ errcode_t ocfs2_new_clusters(ocfs2_filesys *fs, uint32_t min, uint32_t requested, uint64_t *start_blkno, uint32_t *clusters_found) { errcode_t ret; uint64_t start_bit; uint64_t found; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (ret) goto out; ret = ocfs2_chain_alloc_range(fs, fs->fs_cluster_alloc, min, requested, &start_bit, &found); if (ret) goto out; *start_blkno = ocfs2_clusters_to_blocks(fs, start_bit); /* We never have enough bits that can be allocated * contiguously to overflow this. The lower level API needs * fixing. */ *clusters_found = (uint32_t) found; ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc); if (ret) ocfs2_free_clusters(fs, requested, *start_blkno); out: return ret; } errcode_t ocfs2_test_cluster_allocated(ocfs2_filesys *fs, uint32_t cpos, int *is_allocated) { errcode_t ret; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (!ret) { ret = ocfs2_chain_test(fs, fs->fs_cluster_alloc, cpos, is_allocated); } return ret; } errcode_t ocfs2_new_specific_cluster(ocfs2_filesys *fs, uint32_t cpos) { errcode_t ret; int allocatedp = 0; /* Loads the allocator if we need it */ ret = ocfs2_test_cluster_allocated(fs, cpos, &allocatedp); if (ret) goto out; if (allocatedp) { ret = OCFS2_ET_BIT_NOT_FOUND; goto out; } ocfs2_chain_force_val(fs, fs->fs_cluster_alloc, cpos, 1, NULL); ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc); if (ret) ocfs2_free_clusters(fs, 1, ocfs2_blocks_to_clusters(fs, cpos)); out: return ret; } errcode_t ocfs2_free_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno) { errcode_t ret; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (ret) goto out; ret = ocfs2_chain_free_range(fs, fs->fs_cluster_alloc, len, ocfs2_blocks_to_clusters(fs, start_blkno)); if (ret) goto out; /* XXX OK, it's bad if we can't revert this after the io fails */ ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc); out: return ret; } /* * Test whether clusters have the specified value in the bitmap. * test: expected value * matches: 1 if all bits match test, else 0 */ errcode_t ocfs2_test_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno, int test, int *matches) { errcode_t ret; uint32_t start_cluster; int set = 0; *matches = 0; if (!len) return 0; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (ret) goto out; start_cluster = ocfs2_blocks_to_clusters(fs, start_blkno); while (len) { ret = ocfs2_bitmap_test(fs->fs_cluster_alloc->ci_chains, start_cluster, &set); if (ret || set != test) goto out; len--; start_cluster++; } *matches = 1; out: return ret; } #ifdef DEBUG_EXE #include static void print_usage(void) { fprintf(stdout, "debug_alloc \n"); } int main(int argc, char *argv[]) { errcode_t ret; ocfs2_filesys *fs; char *buf; struct ocfs2_dinode *di; uint64_t blkno; if (argc < 3) { print_usage(); return 1; } initialize_ocfs_error_table(); ret = ocfs2_open(argv[2], OCFS2_FLAG_RW, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening \"%s\"", argv[2]); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating buffer"); goto out_close; } di = (struct ocfs2_dinode *)buf; ret = ocfs2_new_inode(fs, &blkno, 0644 | S_IFREG); if (ret) { com_err(argv[0], ret, "while allocating a new inode"); goto out_free; } ret = ocfs2_link(fs, fs->fs_root_blkno, argv[1], blkno, OCFS2_FT_REG_FILE); if (ret) { com_err(argv[0], ret, "while linking inode %"PRIu64, blkno); } out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing \"%s\"", argv[2]); } out: return ret; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/bitmap.c0000644000176100017610000006772611500500544014115 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * bitmap.c * * Basic bitmap routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "bitmap.h" /* The public API */ void ocfs2_bitmap_free(ocfs2_bitmap *bitmap) { struct rb_node *node; struct ocfs2_bitmap_region *br; /* * If the bitmap needs to do extra cleanup of region, * it should have done it in destroy_notify. Same with the * private pointers. */ if (bitmap->b_ops->destroy_notify) (*bitmap->b_ops->destroy_notify)(bitmap); while ((node = rb_first(&bitmap->b_regions)) != NULL) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); rb_erase(&br->br_node, &bitmap->b_regions); ocfs2_bitmap_free_region(br); } ocfs2_free(&bitmap->b_description); ocfs2_free(&bitmap); } errcode_t ocfs2_bitmap_set(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval) { errcode_t ret; int old_tmp; if (bitno >= bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; ret = (*bitmap->b_ops->set_bit)(bitmap, bitno, &old_tmp); if (ret) return ret; if (!old_tmp) bitmap->b_set_bits++; if (oldval) *oldval = old_tmp; return 0; } errcode_t ocfs2_bitmap_clear(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval) { errcode_t ret; int old_tmp; if (bitno >= bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; ret = (*bitmap->b_ops->clear_bit)(bitmap, bitno, &old_tmp); if (ret) return ret; if (old_tmp) bitmap->b_set_bits--; if (oldval) *oldval = old_tmp; return 0; } errcode_t ocfs2_bitmap_test(ocfs2_bitmap *bitmap, uint64_t bitno, int *val) { errcode_t ret; if (bitno >= bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; ret = (*bitmap->b_ops->test_bit)(bitmap, bitno, val); return ret; } errcode_t ocfs2_bitmap_find_next_set(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found) { if (start >= bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; return (*bitmap->b_ops->find_next_set)(bitmap, start, found); } errcode_t ocfs2_bitmap_find_next_clear(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found) { if (start >= bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; return (*bitmap->b_ops->find_next_clear)(bitmap, start, found); } /* kind of poorly named, but I couldn't come up with something nicer */ errcode_t ocfs2_bitmap_alloc_range(ocfs2_bitmap *bitmap, uint64_t min, uint64_t len, uint64_t *first_bit, uint64_t *bits_found) { errcode_t ret; if (min == 0 || len == 0 || len >= bitmap->b_total_bits || min > len) return OCFS2_ET_INVALID_ARGUMENT; ret = (*bitmap->b_ops->alloc_range)(bitmap, min, len, first_bit, bits_found); if (ret == 0 && *bits_found < min) abort(); return ret; } errcode_t ocfs2_bitmap_clear_range(ocfs2_bitmap *bitmap, uint64_t len, uint64_t first_bit) { if (len == 0 || len + first_bit > bitmap->b_total_bits) return OCFS2_ET_INVALID_ARGUMENT; return (*bitmap->b_ops->clear_range)(bitmap, len, first_bit); } errcode_t ocfs2_bitmap_read(ocfs2_bitmap *bitmap) { if (!bitmap->b_ops->read_bitmap) return OCFS2_ET_INVALID_ARGUMENT; /* FIXME: Some sane error, or handle in ->read_bitmap() */ if (rb_first(&bitmap->b_regions)) return OCFS2_ET_INVALID_BIT; return (*bitmap->b_ops->read_bitmap)(bitmap); } errcode_t ocfs2_bitmap_write(ocfs2_bitmap *bitmap) { if (!bitmap->b_ops->write_bitmap) return OCFS2_ET_INVALID_ARGUMENT; return (*bitmap->b_ops->write_bitmap)(bitmap); } uint64_t ocfs2_bitmap_get_set_bits(ocfs2_bitmap *bitmap) { return bitmap->b_set_bits; } /* * The remaining functions are private to the library. */ /* * This function is private to the library. Bitmap subtypes will * use this to allocate their structure, but their b_ops will * determine how they work. */ errcode_t ocfs2_bitmap_new(ocfs2_filesys *fs, uint64_t total_bits, const char *description, struct ocfs2_bitmap_operations *ops, void *private_data, ocfs2_bitmap **ret_bitmap) { errcode_t ret; ocfs2_bitmap *bitmap; if (!ops->set_bit || !ops->clear_bit || !ops->test_bit) return OCFS2_ET_INVALID_ARGUMENT; ret = ocfs2_malloc0(sizeof(struct _ocfs2_bitmap), &bitmap); if (ret) return ret; bitmap->b_fs = fs; bitmap->b_total_bits = total_bits; bitmap->b_ops = ops; bitmap->b_regions = RB_ROOT; bitmap->b_private = private_data; if (description) { ret = ocfs2_malloc0(sizeof(char) * (strlen(description) + 1), &bitmap->b_description); if (ret) goto out_free; strcpy(bitmap->b_description, description); } *ret_bitmap = bitmap; return 0; out_free: ocfs2_free(&bitmap); return ret; } static size_t ocfs2_align_total(int total_bits) { return (total_bits + 7) / 8; } errcode_t ocfs2_bitmap_alloc_region(ocfs2_bitmap *bitmap, uint64_t start_bit, int bitmap_start, int total_bits, struct ocfs2_bitmap_region **ret_br) { errcode_t ret; struct ocfs2_bitmap_region *br; if (total_bits < 0) return OCFS2_ET_INVALID_BIT; ret = ocfs2_malloc0(sizeof(struct ocfs2_bitmap_region), &br); if (ret) return ret; br->br_start_bit = start_bit; br->br_bitmap_start = bitmap_start; br->br_valid_bits = total_bits; br->br_total_bits = total_bits + bitmap_start; br->br_bytes = ocfs2_align_total(br->br_total_bits); ret = ocfs2_malloc0(br->br_bytes, &br->br_bitmap); if (ret) ocfs2_free(&br); else *ret_br = br; return ret; } void ocfs2_bitmap_free_region(struct ocfs2_bitmap_region *br) { if (br->br_bitmap) ocfs2_free(&br->br_bitmap); ocfs2_free(&br); } errcode_t ocfs2_bitmap_realloc_region(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br, int total_bits) { errcode_t ret; size_t new_bytes; if ((br->br_start_bit + total_bits) > bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; new_bytes = ocfs2_align_total(total_bits + br->br_bitmap_start); if (new_bytes > br->br_bytes) { ret = ocfs2_realloc0(new_bytes, &br->br_bitmap, br->br_bytes); if (ret) return ret; br->br_bytes = new_bytes; } br->br_valid_bits = total_bits; br->br_total_bits = total_bits + br->br_bitmap_start; return 0; } errcode_t ocfs2_bitmap_foreach_region(ocfs2_bitmap *bitmap, ocfs2_bitmap_foreach_func func, void *private_data) { struct ocfs2_bitmap_region *br; struct rb_node *node; errcode_t ret = 0; for (node = rb_first(&bitmap->b_regions); node; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); ret = func(br, private_data); if (ret == OCFS2_ET_ITERATION_COMPLETE) { ret = 0; break; } if (ret) break; } return ret; } /* * Attempt to merge two regions. If the merge is successful, 0 will * be returned and prev will be the only valid region. Next will * be freed. */ static errcode_t ocfs2_bitmap_merge_region(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *prev, struct ocfs2_bitmap_region *next) { errcode_t ret; uint64_t new_bits; size_t prev_bytes; uint8_t *pbm, *nbm, offset, diff; if ((prev->br_start_bit + prev->br_valid_bits) != next->br_start_bit) return OCFS2_ET_INVALID_BIT; if (bitmap->b_ops->merge_region && !(*bitmap->b_ops->merge_region)(bitmap, prev, next)) return OCFS2_ET_INVALID_BIT; /* XXX: We don't support merge if the bitmap isn't aligned now. */ if (prev->br_bitmap_start || next->br_bitmap_start) return OCFS2_ET_INVALID_BIT; new_bits = (uint64_t)(prev->br_total_bits) + (uint64_t)(next->br_total_bits); if (new_bits > INT_MAX) return OCFS2_ET_INVALID_BIT; /* grab before realloc changes them */ prev_bytes = prev->br_bytes; offset = prev->br_total_bits % 8; ret = ocfs2_bitmap_realloc_region(bitmap, prev, (int)new_bits); if (ret) return ret; /* if prev's last bit ends on a byte boundary then we can just * copy everything over */ if (offset == 0) { memcpy(prev->br_bitmap + prev_bytes, next->br_bitmap, next->br_bytes); goto done; } /* otherwise we have to shift next in. we're about to free * next, so we consume it as we go. */ pbm = &prev->br_bitmap[prev_bytes - 1]; nbm = &next->br_bitmap[0]; diff = 8 - offset; while(next->br_bytes-- && next->br_total_bits > 0) { /* mask off just the offset bytes in the prev */ *pbm &= ((1 << offset) - 1); /* move 'diff' LSB from next into prevs MSB */ *pbm |= (*nbm & ((1 << diff) - 1)) << offset; pbm++; next->br_total_bits -= diff; if (next->br_total_bits > 0) { /* then set prev's LSB to the next offset MSB. this relies * on 0s being shifted into the MSB */ *pbm = *nbm >> diff; nbm++; next->br_total_bits -= offset; } } done: prev->br_set_bits = prev->br_set_bits + next->br_set_bits; rb_erase(&next->br_node, &bitmap->b_regions); ocfs2_bitmap_free_region(next); return 0; } /* * Find a bitmap_region in the tree that intersects the bit region * that is passed in. * * _p and _parent are set so that callers can use rb_link_node and * rb_insert_color to insert a node after finding that their bit * wasn't found. * * _next is only used if a bitmap_region isn't found. it is set * to the next node in the tree greater than the bitmap range * that was searched. */ static struct ocfs2_bitmap_region *ocfs2_bitmap_lookup(ocfs2_bitmap *bitmap, uint64_t bitno, uint64_t total_bits, struct rb_node ***ret_p, struct rb_node **ret_parent, struct rb_node **ret_next) { struct rb_node **p = &bitmap->b_regions.rb_node; struct rb_node *parent = NULL, *last_left = NULL; struct ocfs2_bitmap_region *br = NULL; while (*p) { parent = *p; br = rb_entry(parent, struct ocfs2_bitmap_region, br_node); if (bitno + total_bits <= br->br_start_bit) { last_left = parent; p = &(*p)->rb_left; br = NULL; } else if (bitno >= (br->br_start_bit + br->br_valid_bits)) { p = &(*p)->rb_right; br = NULL; } else break; } if (ret_p != NULL) *ret_p = p; if (ret_parent != NULL) *ret_parent = parent; if (br == NULL && ret_next != NULL) *ret_next = last_left; return br; } errcode_t ocfs2_bitmap_insert_region(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br) { struct ocfs2_bitmap_region *br_tmp; struct rb_node **p, *parent, *node; if (br->br_start_bit > bitmap->b_total_bits) return OCFS2_ET_INVALID_BIT; /* we shouldn't find an existing region that intersects our new one */ br_tmp = ocfs2_bitmap_lookup(bitmap, br->br_start_bit, br->br_valid_bits, &p, &parent, NULL); if (br_tmp) return OCFS2_ET_INVALID_BIT; rb_link_node(&br->br_node, parent, p); rb_insert_color(&br->br_node, &bitmap->b_regions); /* try to merge our new extent with its neighbours in the tree */ node = rb_prev(&br->br_node); if (node) { br_tmp = rb_entry(node, struct ocfs2_bitmap_region, br_node); ocfs2_bitmap_merge_region(bitmap, br_tmp, br); br = br_tmp; } node = rb_next(&br->br_node); if (node != NULL) { br_tmp = rb_entry(node, struct ocfs2_bitmap_region, br_node); ocfs2_bitmap_merge_region(bitmap, br, br_tmp); } return 0; } static int set_generic_shared(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br, uint64_t bitno) { int old_tmp; old_tmp = ocfs2_set_bit(bitno - br->br_start_bit + br->br_bitmap_start, br->br_bitmap); if (!old_tmp) { br->br_set_bits++; if (bitmap->b_ops->bit_change_notify) (*bitmap->b_ops->bit_change_notify)(bitmap, br, bitno, 1); } return old_tmp; } /* * Helper functions for the most generic of bitmaps. If there is no * memory allocated for the bit, it fails. */ errcode_t ocfs2_bitmap_set_generic(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval) { struct ocfs2_bitmap_region *br; int old_tmp; br = ocfs2_bitmap_lookup(bitmap, bitno, 1, NULL, NULL, NULL); if (!br) return OCFS2_ET_INVALID_BIT; old_tmp = set_generic_shared(bitmap, br, bitno); if (oldval) *oldval = old_tmp; return 0; } static int clear_generic_shared(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br, uint64_t bitno) { int old_tmp; old_tmp = ocfs2_clear_bit(bitno - br->br_start_bit + br->br_bitmap_start, br->br_bitmap); if (old_tmp) { br->br_set_bits--; if (bitmap->b_ops->bit_change_notify) (*bitmap->b_ops->bit_change_notify)(bitmap, br, bitno, 0); } return old_tmp; } errcode_t ocfs2_bitmap_clear_generic(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval) { struct ocfs2_bitmap_region *br; int old_tmp; br = ocfs2_bitmap_lookup(bitmap, bitno, 1, NULL, NULL, NULL); if (!br) return OCFS2_ET_INVALID_BIT; old_tmp = clear_generic_shared(bitmap, br, bitno); if (oldval) *oldval = old_tmp; return 0; } errcode_t ocfs2_bitmap_test_generic(ocfs2_bitmap *bitmap, uint64_t bitno, int *val) { struct ocfs2_bitmap_region *br; br = ocfs2_bitmap_lookup(bitmap, bitno, 1, NULL, NULL, NULL); if (!br) return OCFS2_ET_INVALID_BIT; *val = ocfs2_test_bit(bitno - br->br_start_bit + br->br_bitmap_start, br->br_bitmap) ? 1 : 0; return 0; } errcode_t ocfs2_bitmap_find_next_set_generic(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found) { struct ocfs2_bitmap_region *br; struct rb_node *node = NULL; int offset, ret; /* start from either the node whose's br contains the bit or * the next greatest node in the tree */ br = ocfs2_bitmap_lookup(bitmap, start, 1, NULL, NULL, &node); if (br) node = &br->br_node; for (; node != NULL; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); if (start > br->br_start_bit) offset = start - br->br_start_bit; else offset = 0; ret = ocfs2_find_next_bit_set(br->br_bitmap, br->br_total_bits, offset + br->br_bitmap_start); if (ret != br->br_total_bits) { *found = br->br_start_bit + ret - br->br_bitmap_start; return 0; } } return OCFS2_ET_BIT_NOT_FOUND; } errcode_t ocfs2_bitmap_find_next_clear_generic(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found) { struct ocfs2_bitmap_region *br; struct rb_node *node = NULL; int offset, ret; /* start from either the node whose's br contains the bit or * the next greatest node in the tree */ br = ocfs2_bitmap_lookup(bitmap, start, 1, NULL, NULL, &node); if (br) node = &br->br_node; for (; node != NULL; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); if (start > br->br_start_bit) offset = start - br->br_start_bit; else offset = 0; ret = ocfs2_find_next_bit_clear(br->br_bitmap, br->br_total_bits, offset + br->br_bitmap_start); if (ret != br->br_total_bits) { *found = br->br_start_bit + ret - br->br_bitmap_start; return 0; } } return OCFS2_ET_BIT_NOT_FOUND; } struct alloc_range_args { ocfs2_bitmap *ar_bitmap; uint64_t ar_min_len; uint64_t ar_len; uint64_t ar_first_bit; uint64_t ar_bits_found; errcode_t ar_ret; }; /* Our strategy here to aid discontiguous allocation is to track the * largest free regions (which still fit within ar_min_len) and if the * max allocation fails, fall back to returning one of those. */ static errcode_t alloc_range_func(struct ocfs2_bitmap_region *br, void *private_data) { struct alloc_range_args *ar = private_data; errcode_t ret = 0; uint64_t best_start = UINT64_MAX, best_len = 0; int start, end; if ((br->br_valid_bits - br->br_set_bits) < ar->ar_min_len) goto out; for (start = br->br_bitmap_start; start + ar->ar_min_len <= br->br_total_bits;) { start = ocfs2_find_next_bit_clear(br->br_bitmap, br->br_total_bits, start); if (start == br->br_total_bits) break; /* avoiding start + 1 here so that start at total_bits - 1 * just works out */ end = ocfs2_find_next_bit_set(br->br_bitmap, br->br_total_bits, start); /* We've found a region large enough to hold our max. */ if ((end - start) >= ar->ar_len) { end = start + ar->ar_len; goto found; } if ((end - start) > best_len) { best_len = end - start; best_start = start; } start = end + 1; } /* Nothing found at all */ if (best_start == UINT64_MAX || best_len < ar->ar_min_len) goto out; /* Best fit works */ start = best_start; end = best_start + best_len; found: ar->ar_first_bit = br->br_start_bit + start - br->br_bitmap_start; ar->ar_bits_found = end - start; for (; start < end; start++) set_generic_shared(ar->ar_bitmap, br, br->br_start_bit + start - br->br_bitmap_start); ar->ar_ret = 0; ret = OCFS2_ET_ITERATION_COMPLETE; out: return ret; } errcode_t ocfs2_bitmap_alloc_range_generic(ocfs2_bitmap *bitmap, uint64_t min_len, uint64_t len, uint64_t *first_bit, uint64_t *bits_found) { errcode_t ret; struct alloc_range_args ar = { .ar_bitmap = bitmap, .ar_min_len = min_len, .ar_len = len, .ar_ret = OCFS2_ET_BIT_NOT_FOUND, }; ret = ocfs2_bitmap_foreach_region(bitmap, alloc_range_func, &ar); if (ret == 0) ret = ar.ar_ret; if (ret == 0) { *first_bit = ar.ar_first_bit; *bits_found = ar.ar_bits_found; } return ret; } errcode_t ocfs2_bitmap_clear_range_generic(ocfs2_bitmap *bitmap, uint64_t len, uint64_t first_bit) { struct ocfs2_bitmap_region *br; uint64_t end; br = ocfs2_bitmap_lookup(bitmap, first_bit, len, NULL, NULL, NULL); if (!br) return OCFS2_ET_INVALID_BIT; for (end = first_bit + len; first_bit < end; first_bit++) clear_generic_shared(bitmap, br, first_bit); return 0; } /* * Helper functions for a bitmap with holes in it. * If a bit doesn't have memory allocated for it, we allocate. */ errcode_t ocfs2_bitmap_set_holes(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval) { errcode_t ret; struct ocfs2_bitmap_region *br; if (!ocfs2_bitmap_set_generic(bitmap, bitno, oldval)) return 0; ret = ocfs2_bitmap_alloc_region(bitmap, bitno, 0, 1, &br); if (ret) return ret; ret = ocfs2_bitmap_insert_region(bitmap, br); if (ret) return ret; return ocfs2_bitmap_set_generic(bitmap, bitno, oldval); } errcode_t ocfs2_bitmap_clear_holes(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval) { errcode_t ret; struct ocfs2_bitmap_region *br; if (!ocfs2_bitmap_clear_generic(bitmap, bitno, oldval)) return 0; ret = ocfs2_bitmap_alloc_region(bitmap, bitno, 0, 1, &br); if (ret) return ret; ret = ocfs2_bitmap_insert_region(bitmap, br); return ret; } errcode_t ocfs2_bitmap_test_holes(ocfs2_bitmap *bitmap, uint64_t bitno, int *val) { if (ocfs2_bitmap_test_generic(bitmap, bitno, val)) *val = 0; return 0; } errcode_t ocfs2_bitmap_find_next_set_holes(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found) { return ocfs2_bitmap_find_next_set_generic(bitmap, start, found); } errcode_t ocfs2_bitmap_find_next_clear_holes(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found) { struct ocfs2_bitmap_region *br; struct rb_node *node = NULL; uint64_t seen; int offset, ret; /* start from either the node whose's br contains the bit or * the next greatest node in the tree */ br = ocfs2_bitmap_lookup(bitmap, start, 1, NULL, NULL, &node); if (br) node = &br->br_node; else if (!node) { /* There was nothing past start */ *found = start; return 0; } seen = start; for (; node != NULL; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); /* Did we find a hole? */ if (seen < br->br_start_bit) { *found = seen; return 0; } if (start > br->br_start_bit) offset = start - br->br_start_bit; else offset = 0; ret = ocfs2_find_next_bit_clear(br->br_bitmap, br->br_total_bits, offset + br->br_bitmap_start); if (ret != br->br_total_bits) { *found = br->br_start_bit + ret - br->br_bitmap_start; return 0; } seen = br->br_start_bit + br->br_valid_bits; } return OCFS2_ET_BIT_NOT_FOUND; } static struct ocfs2_bitmap_operations global_cluster_ops = { .set_bit = ocfs2_bitmap_set_generic, .clear_bit = ocfs2_bitmap_clear_generic, .test_bit = ocfs2_bitmap_test_generic, .find_next_set = ocfs2_bitmap_find_next_set_generic, .find_next_clear = ocfs2_bitmap_find_next_clear_generic, .alloc_range = ocfs2_bitmap_alloc_range_generic, .clear_range = ocfs2_bitmap_clear_range_generic, }; errcode_t ocfs2_cluster_bitmap_new(ocfs2_filesys *fs, const char *description, ocfs2_bitmap **ret_bitmap) { errcode_t ret; ocfs2_bitmap *bitmap; uint64_t max_bits, num_bits, bitoff, alloc_bits; struct ocfs2_bitmap_region *br; num_bits = fs->fs_clusters; ret = ocfs2_bitmap_new(fs, num_bits, description ? description : "Generic cluster bitmap", &global_cluster_ops, NULL, &bitmap); if (ret) return ret; bitoff = 0; max_bits = INT_MAX - (fs->fs_clustersize - 1); while (bitoff < num_bits) { alloc_bits = num_bits; if (num_bits > max_bits) alloc_bits = max_bits; ret = ocfs2_bitmap_alloc_region(bitmap, bitoff, 0, alloc_bits, &br); if (ret) { ocfs2_bitmap_free(bitmap); return ret; } ret = ocfs2_bitmap_insert_region(bitmap, br); if (ret) { ocfs2_bitmap_free_region(br); ocfs2_bitmap_free(bitmap); return ret; } bitoff += alloc_bits; } *ret_bitmap = bitmap; return 0; } static struct ocfs2_bitmap_operations global_block_ops = { .set_bit = ocfs2_bitmap_set_holes, .clear_bit = ocfs2_bitmap_clear_holes, .test_bit = ocfs2_bitmap_test_holes, .find_next_set = ocfs2_bitmap_find_next_set_holes, .find_next_clear = ocfs2_bitmap_find_next_clear_holes, /* XXX can't allocate a range yet, would need to fill holes and merge * with adjacent */ }; errcode_t ocfs2_block_bitmap_new(ocfs2_filesys *fs, const char *description, ocfs2_bitmap **ret_bitmap) { errcode_t ret; ocfs2_bitmap *bitmap; ret = ocfs2_bitmap_new(fs, fs->fs_blocks, description ? description : "Generic block bitmap", &global_block_ops, NULL, &bitmap); if (ret) return ret; *ret_bitmap = bitmap; return 0; } #ifdef DEBUG_EXE #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "debug_bitmap [-a] \n"); } extern int opterr, optind; extern char *optarg; static void dump_regions(ocfs2_bitmap *bitmap) { struct ocfs2_bitmap_region *br; struct rb_node *node; fprintf(stdout, "Bitmap \"%s\": total = %"PRIu64", set = %"PRIu64"\n", bitmap->b_description, bitmap->b_total_bits, bitmap->b_set_bits); for (node = rb_first(&bitmap->b_regions);node; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); fprintf(stdout, "(start: %"PRIu64", n: %d, set: %d)\n", br->br_start_bit, br->br_valid_bits, br->br_set_bits); } } static void print_bitmap(ocfs2_bitmap *bitmap) { uint64_t bitno; uint64_t gap_start = 0; /* GCC is dumb */ errcode_t ret; int val, gap; gap = 0; for (bitno = 0; bitno < bitmap->b_total_bits; bitno++) { ret = ocfs2_bitmap_test(bitmap, bitno, &val); if (ret) { if (ret == OCFS2_ET_INVALID_BIT) { if (!gap) { gap = 1; gap_start = bitno; } continue; } com_err("print_bitmap", ret, "while testing bit %"PRIu64"\n", bitno); break; } if (gap) { fprintf(stdout, "\nGap of length %"PRIu64" at %"PRIu64"\n", bitno - gap_start, gap_start); gap = bitno % 72; gap += gap / 8; for (; gap; gap--) fprintf(stdout, " "); fflush(stdout); } else { if (bitno && !(bitno % 72)) fprintf(stdout, "\n"); else if (bitno && !(bitno % 8)) fprintf(stdout, " "); } fprintf(stdout, "%d", val); fflush(stdout); } if ((bitno - 1) % 72) fprintf(stdout, "\n"); } static int try_op(ocfs2_bitmap *bitmap, errcode_t (*func)(ocfs2_bitmap *bitmap, uint64_t bitno, int *val), char *bit_val, int *ret_val) { errcode_t ret; uint64_t bitno; char *ptr; if (!bit_val) { fprintf(stderr, "You must provide a bit offset\n"); return 1; } bitno = read_number(bit_val); if (!bitno) { for (ptr = bit_val; *ptr; ptr++) { if (*ptr != '0') break; } if ((ptr == bit_val) || *ptr) { fprintf(stderr, "Invalid bit offset: %s\n", bit_val); return 1; } } ret = (*func)(bitmap, bitno, ret_val); if (ret) { com_err("try_op", ret, "while setting bit %"PRIu64"\n", bitno); return 1; } return 0; } static int try_op64(ocfs2_bitmap *bitmap, errcode_t (*func)(ocfs2_bitmap *bitmap, uint64_t bitno, uint64_t *val), char *bit_val, uint64_t *ret_val) { errcode_t ret; uint64_t bitno; char *ptr; if (!bit_val) { fprintf(stderr, "You must provide a bit offset\n"); return 1; } bitno = read_number(bit_val); if (!bitno) { for (ptr = bit_val; *ptr; ptr++) { if (*ptr != '0') break; } if ((ptr == bit_val) || *ptr) { fprintf(stderr, "Invalid bit offset: %s\n", bit_val); return 1; } } ret = (*func)(bitmap, bitno, ret_val); if (ret) { com_err("try_op64", ret, "while setting bit %"PRIu64"\n", bitno); return 1; } return 0; } static void run_test(ocfs2_bitmap *bitmap) { char buf[256]; char *ptr, *cmd; uint64_t val64; int val; while (1) { fprintf(stdout, "Command: "); fflush(stdout); if (!fgets(buf, sizeof(buf), stdin)) break; ptr = buf + strlen(buf) - 1; if (*ptr == '\n') *ptr = '\0'; for (cmd = buf; (*cmd == ' ') || (*cmd == '\t'); cmd++); if (!(*cmd)) continue; ptr = strchr(cmd, ' '); if (ptr) { *ptr = '\0'; ptr++; } if (!strcmp(cmd, "set")) { try_op(bitmap, ocfs2_bitmap_set, ptr, NULL); } else if (!strcmp(cmd, "clear")) { try_op(bitmap, ocfs2_bitmap_clear, ptr, NULL); } else if (!strcmp(cmd, "test")) { if (!try_op(bitmap, ocfs2_bitmap_test, ptr, &val)) { fprintf(stdout, "Bit %s is %s\n", ptr, val ? "set" : "clear"); } } else if (!strcmp(cmd, "fns")) { if (!try_op64(bitmap, ocfs2_bitmap_find_next_set, ptr, &val64)) { fprintf(stdout, "Found %"PRIu64"\n", val64); } } else if (!strcmp(cmd, "fnc")) { if (!try_op64(bitmap, ocfs2_bitmap_find_next_clear, ptr, &val64)) { fprintf(stdout, "Found %"PRIu64"\n", val64); } } else if (!strcmp(cmd, "print")) { print_bitmap(bitmap); } else if (!strcmp(cmd, "dump")) { dump_regions(bitmap); } else if (!strcmp(cmd, "quit")) { break; } else { fprintf(stderr, "Invalid command: \"%s\"\n", cmd); } } } int main(int argc, char *argv[]) { errcode_t ret; int c; int alloc = 0; char *filename; ocfs2_filesys *fs; ocfs2_bitmap *bitmap; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "a")) != EOF) { switch (c) { case 'a': alloc = 1; break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); return 1; } if (alloc) ret = ocfs2_block_bitmap_new(fs, "Testing", &bitmap); else ret = ocfs2_cluster_bitmap_new(fs, "Testing", &bitmap); if (ret) { com_err(argv[0], ret, "while creating bitmap"); goto out_close; } run_test(bitmap); ocfs2_bitmap_free(bitmap); out_close: ocfs2_close(fs); return ret; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/bitops.c0000644000176100017610000001171611500500544014125 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * bitops.c * * Bitmap frobbing code for the OCFS2 userspace library. See bitops.h * for inlined versions. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/bitops.c * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #include #include #include #include "ocfs2/bitops.h" /* * For the benefit of those who are trying to port Linux to another * architecture, here are some C-language equivalents. You should * recode these in the native assmebly language, if at all possible. * * C language equivalents written by Theodore Ts'o, 9/26/92. * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian * systems, as well as non-32 bit systems. */ int ocfs2_set_bit(int nr,void * addr) { int mask, retval; unsigned char *ADDR = (unsigned char *) addr; ADDR += nr >> 3; mask = 1 << (nr & 0x07); retval = (mask & *ADDR) != 0; *ADDR |= mask; return retval; } int ocfs2_clear_bit(int nr, void * addr) { int mask, retval; unsigned char *ADDR = (unsigned char *) addr; ADDR += nr >> 3; mask = 1 << (nr & 0x07); retval = (mask & *ADDR) != 0; *ADDR &= ~mask; return retval; } int ocfs2_test_bit(int nr, const void * addr) { int mask; const unsigned char *ADDR = (const unsigned char *) addr; ADDR += nr >> 3; mask = 1 << (nr & 0x07); return ((mask & *ADDR) != 0); } int ocfs2_find_first_bit_set(void *addr, int size) { return ocfs2_find_next_bit_set(addr, size, 0); } int ocfs2_find_first_bit_clear(void *addr, int size) { return ocfs2_find_next_bit_clear(addr, size, 0); } int ocfs2_find_next_bit_set(void *addr, int size, int offset) { unsigned char * p; int set = 0, d0; unsigned int bit = offset & 7, res = 0; unsigned char tilde = ~0; unsigned int mask = 0U | tilde; /* XXX care to check for null ADDR and <= 0 for int args? */ if (size == 0) return 0; res = offset >> 3; p = ((unsigned char *) addr) + res; res <<= 3; if (bit) { set = ffs(*p & ~((1 << bit) - 1)); if (set) return (offset & ~7) + set - 1; p++; res += 8; } while ((size > res) && (*p == 0)) { p++; res += 8; } if (res >= size) return size; if ((res + 8) > size) mask >>= 8 - (size - res); d0 = ffs(*p & mask); if (d0 == 0) return size; return (res + d0 - 1); } int ocfs2_find_next_bit_clear(void *addr, int size, int offset) { unsigned char * p; int set = 0, d0; unsigned int bit = offset & 7, res = 0; unsigned char tilde = ~0; unsigned int mask = 0U | tilde; if (size == 0) return 0; res = offset >> 3; p = ((unsigned char *) addr) + res; res <<= 3; if (bit) { set = ffs(~*p & ~((1 << bit) - 1) & mask); if (set) return (offset & ~7) + set - 1; p++; res += 8; } while ((size > res) && (*p == tilde)) { p++; res += 8; } if (res >= size) return size; if ((res + 8) > size) mask >>= 8 - (size - res); d0 = ffs(~(*p & mask)); if (d0 == 0) return size; return (res + d0 - 1); } int ocfs2_get_bits_set(void *addr, int size, int offset) { int set_bits = 0, found = 0; while (1) { found = ocfs2_find_next_bit_set(addr, size, offset); if (found < size) { set_bits++; offset = found + 1; } else break; } return set_bits; } #ifdef DEBUG_EXE #include #include #include #define bit_expect(expect, which, args...) do { \ int _ret = ocfs2_find_##which(bitmap, args); \ fprintf(stdout, #which "(" #args ") = %d (expected %d: %s)\n", \ _ret, expect, \ _ret == expect ? "correct" : "_incorrect_"); \ } while (0) int main(int argc, char *argv[]) { char bitmap[8 * sizeof(unsigned long)]; int size = sizeof(bitmap) * 8; /* Test an arbitrary size (not byte bounded) */ memset(bitmap, 0, sizeof(bitmap)); ocfs2_set_bit(size - 1, bitmap); bit_expect(size - 3, first_bit_set, size - 3); bit_expect(size - 1, first_bit_set, size); bit_expect(size - 1, next_bit_set, size, size - 1); bit_expect(size, next_bit_clear, size, size - 1); memset(bitmap, 0xFF, sizeof(bitmap)); ocfs2_clear_bit(size - 1, bitmap); bit_expect(size - 3, first_bit_clear, size - 3); bit_expect(size - 1, first_bit_clear, size); bit_expect(size - 1, next_bit_clear, size, size - 1); bit_expect(size, next_bit_set, size, size - 1); /* XXX add more tests */ return 0; } #endif ./ocfs2-tools-1.6.4/libocfs2/blockcheck.c0000644000176100017610000006003411500500544014712 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * blockcheck.c * * Checksum and ECC codes for the OCFS2 userspace library. * * Copyright (C) 2006, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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. * * The 802.3 CRC32 algorithm is copied from the Linux kernel, lib/crc32.c. * Code was from the public domain, is now GPL, so no real copyright * attribution other than "The Linux Kernel". XXX: better text, anyone? */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #ifdef DEBUG_EXE # define _BSD_SOURCE /* For timersub() */ #endif #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "ocfs2/byteorder.h" #include "crc32table.h" static inline unsigned int hc_hweight32(unsigned int w) { unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); res = (res & 0x33333333) + ((res >> 2) & 0x33333333); res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); } /* * Calculate the bit offset in the hamming code buffer based on the bit's * offset in the data buffer. Since the hamming code reserves all * power-of-two bits for parity, the data bit number and the code bit * number are offest by all the parity bits beforehand. * * Recall that bit numbers in hamming code are 1-based. This function * takes the 0-based data bit from the caller. * * An example. Take bit 1 of the data buffer. 1 is a power of two (2^0), * so it's a parity bit. 2 is a power of two (2^1), so it's a parity bit. * 3 is not a power of two. So bit 1 of the data buffer ends up as bit 3 * in the code buffer. * * The caller passes in *p if it wants to keep track of the most recent * number of parity bits added. This allows the function to start the * calculation at the last place. */ static unsigned int calc_code_bit(unsigned int i, unsigned int *p_cache) { unsigned int b, p = 0; /* * Data bits are 0-based, but we're talking code bits, which * are 1-based. */ b = i + 1; /* Use the cache if it is there */ if (p_cache) p = *p_cache; b += p; /* * For every power of two below our bit number, bump our bit. * * We compare with (b + 1) because we have to compare with what b * would be _if_ it were bumped up by the parity bit. Capice? * * p is set above. */ for (; (1 << p) < (b + 1); p++) b++; if (p_cache) *p_cache = p; return b; } /* * This is the low level encoder function. It can be called across * multiple hunks just like the crc32 code. 'd' is the number of bits * _in_this_hunk_. nr is the bit offset of this hunk. So, if you had * two 512B buffers, you would do it like so: * * parity = ocfs2_hamming_encode(0, buf1, 512 * 8, 0); * parity = ocfs2_hamming_encode(parity, buf2, 512 * 8, 512 * 8); * * If you just have one buffer, use ocfs2_hamming_encode_block(). */ uint32_t ocfs2_hamming_encode(uint32_t parity, void *data, unsigned int d, unsigned int nr) { unsigned int i, b, p = 0; if (!d) abort(); /* * b is the hamming code bit number. Hamming code specifies a * 1-based array, but C uses 0-based. So 'i' is for C, and 'b' is * for the algorithm. * * The i++ in the for loop is so that the start offset passed * to ocfs2_find_next_bit_set() is one greater than the previously * found bit. */ for (i = 0; (i = ocfs2_find_next_bit_set(data, d, i)) < d; i++) { /* * i is the offset in this hunk, nr + i is the total bit * offset. */ b = calc_code_bit(nr + i, &p); /* * Data bits in the resultant code are checked by * parity bits that are part of the bit number * representation. Huh? * * * In other words, the parity bit at position 2^k * checks bits in positions having bit k set in * their binary representation. Conversely, for * instance, bit 13, i.e. 1101(2), is checked by * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1. * * * Note that 'k' is the _code_ bit number. 'b' in * our loop. */ parity ^= b; } /* While the data buffer was treated as little endian, the * return value is in host endian. */ return parity; } uint32_t ocfs2_hamming_encode_block(void *data, unsigned int blocksize) { return ocfs2_hamming_encode(0, data, blocksize * 8, 0); } /* * Like ocfs2_hamming_encode(), this can handle hunks. nr is the bit * offset of the current hunk. If bit to be fixed is not part of the * current hunk, this does nothing. * * If you only have one hunk, use ocfs2_hamming_fix_block(). */ void ocfs2_hamming_fix(void *data, unsigned int d, unsigned int nr, unsigned int fix) { unsigned int i, b; if (!d) abort(); /* * If the bit to fix has an hweight of 1, it's a parity bit. One * busted parity bit is its own error. Nothing to do here. */ if (hc_hweight32(fix) == 1) return; /* * nr + d is the bit right past the data hunk we're looking at. * If fix after that, nothing to do */ if (fix >= calc_code_bit(nr + d, NULL)) return; /* * nr is the offset in the data hunk we're starting at. Let's * start b at the offset in the code buffer. See hamming_encode() * for a more detailed description of 'b'. */ b = calc_code_bit(nr, NULL); /* If the fix is before this hunk, nothing to do */ if (fix < b) return; for (i = 0; i < d; i++, b++) { /* Skip past parity bits */ while (hc_hweight32(b) == 1) b++; /* * i is the offset in this data hunk. * nr + i is the offset in the total data buffer. * b is the offset in the total code buffer. * * Thus, when b == fix, bit i in the current hunk needs * fixing. */ if (b == fix) { if (ocfs2_test_bit(i, data)) ocfs2_clear_bit(i, data); else ocfs2_set_bit(i, data); break; } } } void ocfs2_hamming_fix_block(void *data, unsigned int blocksize, unsigned int fix) { ocfs2_hamming_fix(data, blocksize * 8, 0, fix); } /* * table-based crc32_le() stolen from the kernel. This is the one we know * the filesystem is using. * * RFC 3385 shows that the 802.3 crc32 (this one) has the same properties * and probabilities as crc32c (which iSCSI uses) for data blocks < 2^16 * bits. We fit. */ /** * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32 * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for * other uses, or the previous crc32 value if computing incrementally. * @p - pointer to buffer over which CRC is run * @len - length of buffer @p * */ uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len) { const uint32_t *b =(uint32_t *)p; const uint32_t *tab = crc32table_le; #if __BYTE_ORDER == __LITTLE_ENDIAN # define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8) #else # define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8) #endif crc = cpu_to_le32(crc); /* Align it */ if(((long)b)&3 && len){ do { uint8_t *p = (uint8_t *)b; DO_CRC(*p++); b = (void *)p; } while ((--len) && ((long)b)&3 ); } if(len >= 4){ /* load data 32 bits wide, xor data 32 bits wide. */ size_t save_len = len & 3; len = len >> 2; --b; /* use pre increment below(*++b) for speed */ do { crc ^= *++b; DO_CRC(0); DO_CRC(0); DO_CRC(0); DO_CRC(0); } while (--len); b++; /* point to next byte(s) */ len = save_len; } /* And the last few bytes */ if(len){ do { uint8_t *p = (uint8_t *)b; DO_CRC(*p++); b = (void *)p; } while (--len); } return le32_to_cpu(crc); #undef DO_CRC } /* * This function generates check information for a block. * data is the block to be checked. bc is a pointer to the * ocfs2_block_check structure describing the crc32 and the ecc. * * bc should be a pointer inside data, as the function will * take care of zeroing it before calculating the check information. If * bc does not point inside data, the caller must make sure any inline * ocfs2_block_check structures are zeroed. * * The data buffer must be in on-disk endian (little endian for ocfs2). * bc will be filled with little-endian values and will be ready to go to * disk. */ void ocfs2_block_check_compute(void *data, size_t blocksize, struct ocfs2_block_check *bc) { uint32_t crc; uint16_t ecc; memset(bc, 0, sizeof(struct ocfs2_block_check)); crc = crc32_le(~0, data, blocksize); /* We know this will return max 16 bits */ ecc = (uint16_t)ocfs2_hamming_encode_block(data, blocksize); bc->bc_crc32e = cpu_to_le32(crc); bc->bc_ecc = cpu_to_le16(ecc); /* We know it's max 16 bits */ } /* * This function validates existing check information. Like _compute, * the function will take care of zeroing bc before calculating check codes. * If bc is not a pointer inside data, the caller must have zeroed any * inline ocfs2_block_check structures. * * Again, the data passed in should be the on-disk endian. */ errcode_t ocfs2_block_check_validate(void *data, size_t blocksize, struct ocfs2_block_check *bc) { errcode_t err = 0; struct ocfs2_block_check check; uint32_t crc, ecc; check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); check.bc_ecc = le16_to_cpu(bc->bc_ecc); memset(bc, 0, sizeof(struct ocfs2_block_check)); /* Fast path - if the crc32 validates, we're good to go */ crc = crc32_le(~0, data, blocksize); if (crc == check.bc_crc32e) goto out; /* Ok, try ECC fixups */ ecc = ocfs2_hamming_encode_block(data, blocksize); ocfs2_hamming_fix_block(data, blocksize, ecc ^ check.bc_ecc); /* And check the crc32 again */ crc = crc32_le(~0, data, blocksize); if (crc == check.bc_crc32e) goto out; err = OCFS2_ET_IO; out: bc->bc_crc32e = cpu_to_le32(check.bc_crc32e); bc->bc_ecc = cpu_to_le16(check.bc_ecc); return err; } /* * These are the main API. They check the superblock flag before * calling the underlying operations. * * They expect the buffer to be in disk format. */ void ocfs2_compute_meta_ecc(ocfs2_filesys *fs, void *data, struct ocfs2_block_check *bc) { if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super))) ocfs2_block_check_compute(data, fs->fs_blocksize, bc); } errcode_t ocfs2_validate_meta_ecc(ocfs2_filesys *fs, void *data, struct ocfs2_block_check *bc) { errcode_t err = 0; if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super)) && !(fs->fs_flags & OCFS2_FLAG_NO_ECC_CHECKS)) err = ocfs2_block_check_validate(data, fs->fs_blocksize, bc); return err; } #ifdef DEBUG_EXE #include #include #include #include #include #include #include #include #include #include #include /* * The function hamming_encode_orig() is my original, tested version. It's * slow. We work from it to make a faster one. */ /* * We use the following conventions: * * d = # data bits * p = # parity bits * c = # total code bits (d + p) */ static int calc_parity_bits_orig(unsigned int d) { unsigned int p; /* * Bits required for Single Error Correction is as follows: * * d + p + 1 <= 2^p * * We're restricting ourselves to 31 bits of parity, that should be * sufficient. */ for (p = 1; p < 32; p++) { if ((d + p + 1) <= (1 << p)) return p; } return 0; } static unsigned int calc_code_bit_orig(unsigned int i) { unsigned int b, p; /* * Data bits are 0-based, but we're talking code bits, which * are 1-based. */ b = i + 1; /* * For every power of two below our bit number, bump our bit. * * We compare with (b + 1) because we have to compare with what b * would be _if_ it were bumped up by the parity bit. Capice? */ for (p = 0; (1 << p) < (b + 1); p++) b++; return b; } /* * Find the log base 2 of 32-bit v. * * Algorithm found on http://graphics.stanford.edu/~seander/bithacks.html, * by Sean Eron Anderson. Code on the page is in the public domain unless * otherwise noted. * * This particular algorithm is credited to Eric Cole. */ static int find_highest_bit_set(unsigned int v) { static const int MultiplyDeBruijnBitPosition[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; v |= v >> 1; /* first round down to power of 2 */ v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v = (v >> 1) + 1; return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x077CB531UL) >> 27]; } static unsigned int calc_code_bit_cheat(unsigned int i) { unsigned int b, p; /* * Data bits are 0-based, but we're talking code bits, which * are 1-based. */ b = i + 1; /* * As a cheat, we know that all bits below b's highest bit must be * parity bits, so we can start there. */ p = find_highest_bit_set(b); b += p; /* * For every power of two below our bit number, bump our bit. * * We compare with (b + 1) because we have to compare with what b * would be _if_ it were bumped up by the parity bit. Capice? * * We start p at 2^p because of the cheat above. */ for (p = (1 << p); p < (b + 1); p <<= 1) b++; return b; } /* * This is the low level encoder function. It can be called across * multiple hunks just like the crc32 code. 'd' is the number of bits * _in_this_hunk_. nr is the bit offset of this hunk. So, if you had * two 512B buffers, you would do it like so: * * parity = ocfs2_hamming_encode(0, buf1, 512 * 8, 0); * parity = ocfs2_hamming_encode(parity, buf2, 512 * 8, 512 * 8); * * If you just have one buffer, use ocfs2_hamming_encode_block(). */ static uint32_t hamming_encode_orig(uint32_t parity, void *data, unsigned int d, unsigned int nr) { unsigned int p = calc_parity_bits_orig(d); unsigned int i, j, b; if (!p) abort(); /* * b is the hamming code bit number. Hamming code specifies a * 1-based array, but C uses 0-based. So 'i' is for C, and 'b' is * for the algorithm. * * The i++ in the for loop is so that the start offset passed * to ocfs2_find_next_bit_set() is one greater than the previously * found bit. */ for (i = 0; (i = ocfs2_find_next_bit_set(data, d, i)) < d; i++) { /* * i is the offset in this hunk, nr + i is the total bit * offset. */ b = calc_code_bit_orig(nr + i); for (j = 0; j < p; j++) { /* * Data bits in the resultant code are checked by * parity bits that are part of the bit number * representation. Huh? * * * In other words, the parity bit at position 2^k * checks bits in positions having bit k set in * their binary representation. Conversely, for * instance, bit 13, i.e. 1101(2), is checked by * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1. * * * Note that 'k' is the _code_ bit number. 'b' in * our loop. */ if (b & (1 << j)) parity ^= (1 << j); } } /* While the data buffer was treated as little endian, the * return value is in host endian. */ return parity; } /* * This version uses the direct parity ^= b, but the original * calc_parity_bits() and calc_code_bit(). */ static uint32_t ocfs2_hamming_encode_orig_bits(uint32_t parity, void *data, unsigned int d, unsigned int nr) { unsigned int p = calc_parity_bits_orig(d); unsigned int i, b; if (!p) abort(); /* * b is the hamming code bit number. Hamming code specifies a * 1-based array, but C uses 0-based. So 'i' is for C, and 'b' is * for the algorithm. * * The i++ in the for loop is so that the start offset passed * to ocfs2_find_next_bit_set() is one greater than the previously * found bit. */ for (i = 0; (i = ocfs2_find_next_bit_set(data, d, i)) < d; i++) { /* * i is the offset in this hunk, nr + i is the total bit * offset. */ b = calc_code_bit_orig(nr + i); /* * Data bits in the resultant code are checked by * parity bits that are part of the bit number * representation. Huh? * * * In other words, the parity bit at position 2^k * checks bits in positions having bit k set in * their binary representation. Conversely, for * instance, bit 13, i.e. 1101(2), is checked by * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1. * * * Note that 'k' is the _code_ bit number. 'b' in * our loop. */ parity ^= b; } /* While the data buffer was treated as little endian, the * return value is in host endian. */ return parity; } /* * This version uses the direct parity ^= b, but the original * calc_code_bit() */ static uint32_t ocfs2_hamming_encode_orig_code_bit(uint32_t parity, void *data, unsigned int d, unsigned int nr) { unsigned int i, b; if (!d) abort(); /* * b is the hamming code bit number. Hamming code specifies a * 1-based array, but C uses 0-based. So 'i' is for C, and 'b' is * for the algorithm. * * The i++ in the for loop is so that the start offset passed * to ocfs2_find_next_bit_set() is one greater than the previously * found bit. */ for (i = 0; (i = ocfs2_find_next_bit_set(data, d, i)) < d; i++) { /* * i is the offset in this hunk, nr + i is the total bit * offset. */ b = calc_code_bit_orig(nr + i); /* * Data bits in the resultant code are checked by * parity bits that are part of the bit number * representation. Huh? * * * In other words, the parity bit at position 2^k * checks bits in positions having bit k set in * their binary representation. Conversely, for * instance, bit 13, i.e. 1101(2), is checked by * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1. * * * Note that 'k' is the _code_ bit number. 'b' in * our loop. */ parity ^= b; } /* While the data buffer was treated as little endian, the * return value is in host endian. */ return parity; } /* * This version uses the direct parity ^= b, but the cheating * calc_code_bit(). */ static uint32_t ocfs2_hamming_encode_cheat_code_bit(uint32_t parity, void *data, unsigned int d, unsigned int nr) { unsigned int i, b; if (!d) abort(); /* * b is the hamming code bit number. Hamming code specifies a * 1-based array, but C uses 0-based. So 'i' is for C, and 'b' is * for the algorithm. * * The i++ in the for loop is so that the start offset passed * to ocfs2_find_next_bit_set() is one greater than the previously * found bit. */ for (i = 0; (i = ocfs2_find_next_bit_set(data, d, i)) < d; i++) { /* * i is the offset in this hunk, nr + i is the total bit * offset. */ b = calc_code_bit_cheat(nr + i); /* * Data bits in the resultant code are checked by * parity bits that are part of the bit number * representation. Huh? * * * In other words, the parity bit at position 2^k * checks bits in positions having bit k set in * their binary representation. Conversely, for * instance, bit 13, i.e. 1101(2), is checked by * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1. * * * Note that 'k' is the _code_ bit number. 'b' in * our loop. */ parity ^= b; } /* While the data buffer was treated as little endian, the * return value is in host endian. */ return parity; } struct run_context { char *rc_name; void *rc_data; int rc_size; int rc_count; void (*rc_func)(struct run_context *ct, int nr); }; static void timeme(struct run_context *ct) { int i; struct rusage start; struct rusage stop; struct timeval sys_diff, usr_diff; assert(!getrusage(RUSAGE_SELF, &start)); for (i = 0; i < ct->rc_count; i++) ct->rc_func(ct, i); assert(!getrusage(RUSAGE_SELF, &stop)); timersub(&stop.ru_utime, &start.ru_utime, &usr_diff); timersub(&stop.ru_stime, &start.ru_stime, &sys_diff); fprintf(stderr, "Time for %s: %ld.%06ld user, %ld.%06ld system\n", ct->rc_name, usr_diff.tv_sec, usr_diff.tv_usec, sys_diff.tv_sec, sys_diff.tv_usec); } static void crc32_func(struct run_context *ct, int nr) { uint32_t crc = ~0; crc = crc32_le(crc, ct->rc_data, ct->rc_size); } static void run_crc32(char *buf, int size, int count) { struct run_context ct = { .rc_name = "CRC32", .rc_data = buf, .rc_size = size, .rc_count = count, .rc_func = crc32_func, }; timeme(&ct); } struct hamming_context { struct run_context hc_rc; uint32_t hc_ecc; int hc_ecc_valid; uint32_t (*hc_encode)(uint32_t parity, void *data, unsigned int d, unsigned int nr); }; #define rc_to_hc(_rc) ((struct hamming_context *)(_rc)) static void hamming_func(struct run_context *ct, int nr) { uint32_t ecc = 0; struct hamming_context *hc = rc_to_hc(ct); ecc = hc->hc_encode(ecc, ct->rc_data, ct->rc_size * 8, 0); if (hc->hc_ecc_valid) { if (hc->hc_ecc != ecc) { fprintf(stderr, "Calculated ecc %"PRIu32" != saved ecc %"PRIu32"\n", ecc, hc->hc_ecc); exit(1); } } else { assert(!nr); hc->hc_ecc = ecc; hc->hc_ecc_valid = 1; }; } static void run_hamming(char *buf, int size, int count) { struct hamming_context hc = { .hc_rc = { .rc_name = "Original hamming code", .rc_data = buf, .rc_size = size, .rc_count = count, .rc_func = hamming_func, }, .hc_encode = hamming_encode_orig, }; timeme(&hc.hc_rc); hc.hc_rc.rc_name = "Current hamming code"; hc.hc_encode = ocfs2_hamming_encode; timeme(&hc.hc_rc); hc.hc_rc.rc_name = "Parity xor with orig calc bits"; hc.hc_encode = ocfs2_hamming_encode_orig_bits; timeme(&hc.hc_rc); hc.hc_rc.rc_name = "Parity xor with orig calc code bit"; hc.hc_encode = ocfs2_hamming_encode_orig_code_bit; timeme(&hc.hc_rc); hc.hc_rc.rc_name = "Parity xor with cheating calc code bit"; hc.hc_encode = ocfs2_hamming_encode_cheat_code_bit; timeme(&hc.hc_rc); hc.hc_rc.rc_name = "Current hamming code"; hc.hc_encode = ocfs2_hamming_encode; timeme(&hc.hc_rc); } static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void get_file(char *filename, char **buf, int *size) { int rc, fd, tot = 0; char *b; struct stat stat_buf; rc = stat(filename, &stat_buf); if (rc) { fprintf(stderr, "Unable to stat \"%s\": %s\n", filename, strerror(errno)); exit(1); } if (!S_ISREG(stat_buf.st_mode)) { fprintf(stderr, "File \"%s\" is not a regular file\n", filename); exit(1); } b = malloc(stat_buf.st_size * sizeof(char)); if (!b) { fprintf(stderr, "Unable to allocate buffer: %s\n", strerror(errno)); exit(1); } fd = open64(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Unable to open \"%s\": %s\n", filename, strerror(errno)); exit(1); } while (tot < stat_buf.st_size) { rc = read(fd, b + tot, stat_buf.st_size - tot); if (rc < 0) { fprintf(stderr, "Error reading from \"%s\": %s\n", filename, strerror(errno)); exit(1); } if (!rc) { fprintf(stderr, "Unexpected EOF while reading from \"%s\"\n", filename); exit(1); } tot += rc; } close(fd); *size = stat_buf.st_size; *buf = b; } static void print_usage(void) { fprintf(stderr, "Usage: blockcheck []\n"); } int main(int argc, char *argv[]) { int size, count = 1; char *filename, *buf; initialize_ocfs_error_table(); if (argc < 2) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[1]; if (argc > 2) { count = read_number(argv[2]); if (count < 1) { fprintf(stderr, "Invalid count: %d\n", count); print_usage(); return 1; } } get_file(filename, &buf, &size); run_crc32(buf, size, count); run_hamming(buf, size, count); #if 0 ocfs2_block_check_compute(buf, size, &check); fprintf(stdout, "crc32le: %"PRIu32", ecc: %"PRIu16"\n", le32_to_cpu(check.bc_crc32e), le16_to_cpu(check.bc_ecc)); #endif free(buf); return 0; } #endif ./ocfs2-tools-1.6.4/libocfs2/cached_inode.c0000644000176100017610000000515711453177334015232 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * cached_inode.c * * Cache inode structure for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/ocfs2.h" errcode_t ocfs2_read_cached_inode(ocfs2_filesys *fs, uint64_t blkno, ocfs2_cached_inode **ret_ci) { errcode_t ret; char *blk; ocfs2_cached_inode *cinode; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc0(sizeof(ocfs2_cached_inode), &cinode); if (ret) return ret; cinode->ci_fs = fs; cinode->ci_blkno = blkno; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) goto cleanup; cinode->ci_inode = (struct ocfs2_dinode *)blk; ret = ocfs2_read_inode(fs, blkno, blk); if (ret) goto cleanup; *ret_ci = cinode; return 0; cleanup: ocfs2_free_cached_inode(fs, cinode); return ret; } errcode_t ocfs2_free_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *cinode) { if (!cinode) return OCFS2_ET_INVALID_ARGUMENT; if (cinode->ci_chains) ocfs2_bitmap_free(cinode->ci_chains); if (cinode->ci_inode) ocfs2_free(&cinode->ci_inode); ocfs2_free(&cinode); return 0; } errcode_t ocfs2_write_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *cinode) { errcode_t ret; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((cinode->ci_blkno < OCFS2_SUPER_BLOCK_BLKNO) || (cinode->ci_blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_write_inode(fs, cinode->ci_blkno, (char *)cinode->ci_inode); return ret; } errcode_t ocfs2_refresh_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *cinode) { if (cinode->ci_chains) { ocfs2_bitmap_free(cinode->ci_chains); cinode->ci_chains = NULL; } return ocfs2_read_inode(fs, cinode->ci_blkno, (char *)cinode->ci_inode); } ./ocfs2-tools-1.6.4/libocfs2/chain.c0000664000176100017610000002345511506552637013734 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * chain.c * * Iterate over allocation chains. Part of the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/ocfs2.h" #include "ocfs2/byteorder.h" static void ocfs2_swap_group_desc_header(struct ocfs2_group_desc *gd) { gd->bg_size = bswap_16(gd->bg_size); gd->bg_bits = bswap_16(gd->bg_bits); gd->bg_free_bits_count = bswap_16(gd->bg_free_bits_count); gd->bg_chain = bswap_16(gd->bg_chain); gd->bg_generation = bswap_32(gd->bg_generation); gd->bg_next_group = bswap_64(gd->bg_next_group); gd->bg_parent_dinode = bswap_64(gd->bg_parent_dinode); gd->bg_blkno = bswap_64(gd->bg_blkno); } void ocfs2_swap_group_desc_from_cpu(ocfs2_filesys *fs, struct ocfs2_group_desc *gd) { if (cpu_is_little_endian) return; if (ocfs2_gd_is_discontig(gd)) ocfs2_swap_extent_list_from_cpu(fs, gd, &gd->bg_list); ocfs2_swap_group_desc_header(gd); } void ocfs2_swap_group_desc_to_cpu(ocfs2_filesys *fs, struct ocfs2_group_desc *gd) { if (cpu_is_little_endian) return; ocfs2_swap_group_desc_header(gd); if (ocfs2_gd_is_discontig(gd)) ocfs2_swap_extent_list_to_cpu(fs, gd, &gd->bg_list); } errcode_t ocfs2_read_group_desc(ocfs2_filesys *fs, uint64_t blkno, char *gd_buf) { errcode_t ret; char *blk; struct ocfs2_group_desc *gd; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; gd = (struct ocfs2_group_desc *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &gd->bg_check); if (ret) goto out; ret = OCFS2_ET_BAD_GROUP_DESC_MAGIC; if (memcmp(gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE, strlen(OCFS2_GROUP_DESC_SIGNATURE))) goto out; memcpy(gd_buf, blk, fs->fs_blocksize); gd = (struct ocfs2_group_desc *)gd_buf; ocfs2_swap_group_desc_to_cpu(fs, gd); ret = 0; out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_write_group_desc(ocfs2_filesys *fs, uint64_t blkno, char *gd_buf) { errcode_t ret; char *blk; struct ocfs2_group_desc *gd; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; memcpy(blk, gd_buf, fs->fs_blocksize); gd = (struct ocfs2_group_desc *)blk; ocfs2_swap_group_desc_from_cpu(fs, gd); ocfs2_compute_meta_ecc(fs, blk, &gd->bg_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; } struct chain_context { ocfs2_filesys *fs; int (*func)(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data); errcode_t errcode; char *gd_buf; void *priv_data; }; static int chain_iterate_gd(struct ocfs2_chain_rec *c_rec, int chain_num, struct chain_context *ctxt) { int iret = 0; uint64_t blkno; struct ocfs2_group_desc *gd; blkno = c_rec->c_blkno; while (blkno) { iret = (*ctxt->func)(ctxt->fs, blkno, chain_num, ctxt->priv_data); if (iret & OCFS2_CHAIN_ABORT) break; ctxt->errcode = ocfs2_read_group_desc(ctxt->fs, blkno, ctxt->gd_buf); if (ctxt->errcode) { iret |= OCFS2_CHAIN_ERROR; break; } gd = (struct ocfs2_group_desc *)ctxt->gd_buf; if ((gd->bg_blkno != blkno) || (gd->bg_chain != chain_num)) { ctxt->errcode = OCFS2_ET_CORRUPT_GROUP_DESC; iret |= OCFS2_CHAIN_ERROR; break; } blkno = gd->bg_next_group; } return iret; } static int chain_iterate_cl(struct ocfs2_chain_list *cl, struct chain_context *ctxt) { int iret = 0; int i; for (i = 0; i < cl->cl_next_free_rec; i++) { iret |= chain_iterate_gd(&cl->cl_recs[i], i, ctxt); if (iret & (OCFS2_CHAIN_ABORT | OCFS2_CHAIN_ERROR)) break; } if (iret & OCFS2_CHAIN_CHANGED) { /* Something here ? */ } return iret; } errcode_t ocfs2_chain_iterate(ocfs2_filesys *fs, uint64_t blkno, int (*func)(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data), void *priv_data) { int iret = 0; char *buf; struct ocfs2_dinode *inode; errcode_t ret; struct chain_context ctxt; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto out_buf; inode = (struct ocfs2_dinode *)buf; ret = OCFS2_ET_INODE_NOT_VALID; if (!(inode->i_flags & OCFS2_VALID_FL)) goto out_buf; ret = OCFS2_ET_INODE_CANNOT_BE_ITERATED; if (!(inode->i_flags & OCFS2_CHAIN_FL)) goto out_buf; ret = ocfs2_malloc0(fs->fs_blocksize, &ctxt.gd_buf); if (ret) goto out_gd_buf; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ret = 0; iret |= chain_iterate_cl(&inode->id2.i_chain, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_CHANGED) { /* Do something */ } out_gd_buf: if (ctxt.gd_buf) ocfs2_free(&ctxt.gd_buf); out_buf: ocfs2_free(&buf); return ret; } uint64_t ocfs2_get_block_from_group(ocfs2_filesys *fs, struct ocfs2_group_desc *grp, int bpc, int bit_offset) { int cpos, i; struct ocfs2_extent_rec *rec; int block_per_bit = ocfs2_clusters_to_blocks(fs, 1) / bpc; if (!ocfs2_gd_is_discontig(grp)) return grp->bg_blkno + bit_offset * block_per_bit; /* handle discontiguous group. */ cpos = bit_offset / bpc; for (i = 0; i < grp->bg_list.l_next_free_rec; i++) { rec = &grp->bg_list.l_recs[i]; if (rec->e_cpos <= cpos && rec->e_cpos + rec->e_leaf_clusters > cpos) break; } if (i == grp->bg_list.l_next_free_rec) abort(); return rec->e_blkno + (bit_offset * block_per_bit - ocfs2_clusters_to_blocks(fs, rec->e_cpos)); } #ifdef DEBUG_EXE #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: debug_chain -i \n"); } struct walk_it { struct ocfs2_dinode *di; char *gd_buf; int last_chain; int count_free; int count_total; }; static int walk_chain_func(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data) { struct walk_it *wi = priv_data; struct ocfs2_group_desc *gd; errcode_t ret; if (wi->last_chain != chain_num) { fprintf(stdout, "CHAIN[%02d]: %d/%d\n", chain_num, wi->di->id2.i_chain.cl_recs[chain_num].c_free, wi->di->id2.i_chain.cl_recs[chain_num].c_total); wi->last_chain = chain_num; wi->count_free = wi->count_total = 0; } ret = ocfs2_read_group_desc(fs, gd_blkno, wi->gd_buf); if (ret) return OCFS2_CHAIN_ERROR; gd = (struct ocfs2_group_desc *)wi->gd_buf; wi->count_free += gd->bg_free_bits_count; wi->count_total += gd->bg_bits; fprintf(stdout, " %16"PRIu64": %05d/%05d = %05d/%05d\n", gd->bg_blkno, gd->bg_free_bits_count, gd->bg_bits, wi->count_free, wi->count_total); return 0; } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno; int c; char *filename, *buf; ocfs2_filesys *fs; struct ocfs2_dinode *di; struct walk_it wi; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "bei:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (blkno == OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "You must specify an inode block\n"); print_usage(); return 1; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } memset(&wi, 0, sizeof(wi)); ret = ocfs2_read_inode(fs, blkno, buf); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_free; } di = (struct ocfs2_dinode *)buf; fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\"\n", blkno, filename); ret = ocfs2_malloc_block(fs->fs_io, &wi.gd_buf); if (ret) { com_err(argv[0], ret, "while allocating gd buffer"); goto out_free; } wi.di = di; wi.last_chain = -1; ret = ocfs2_chain_iterate(fs, blkno, walk_chain_func, &wi); if (ret) { com_err(argv[0], ret, "while walking extents"); } out_free: if (wi.gd_buf) ocfs2_free(&wi.gd_buf); ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/chainalloc.c0000644000176100017610000006002311500500544014715 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * chainalloc.c * * Functions to use the chain allocators for the OCFS2 userspace * library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/ocfs2.h" #include "bitmap.h" #include "ocfs2/bitops.h" struct chainalloc_bitmap_private { ocfs2_cached_inode *cb_cinode; errcode_t cb_errcode; int cb_dirty; int cb_suballoc; }; struct chainalloc_region_private { struct chainalloc_bitmap_private *cr_cb; struct ocfs2_group_desc *cr_ag; int cr_dirty; /* In discontiguous group block, it is set as * the bit offset of this region in the whole group. * As for contiguous group, it is set to 0. */ int bit_offset; }; static void chainalloc_destroy_notify(ocfs2_bitmap *bitmap) { struct rb_node *node = NULL; struct ocfs2_bitmap_region *br; struct chainalloc_region_private *cr; for (node = rb_first(&bitmap->b_regions); node; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); cr = br->br_private; /* * For discontiguous block group, only destroy * cr_ag once when we meet with the head. */ if (cr->cr_ag && !cr->bit_offset) ocfs2_free(&cr->cr_ag); ocfs2_free(&br->br_private); } ocfs2_free(&bitmap->b_private); } static uint64_t chainalloc_scale_start_bit(ocfs2_filesys *fs, uint64_t blkno, int bpc) { int bitsize = fs->fs_clustersize / bpc; if (bitsize == fs->fs_blocksize) return blkno; if (bitsize < fs->fs_blocksize) return blkno * (fs->fs_blocksize / bitsize); else return blkno / (bitsize / fs->fs_blocksize); } /* * Find the next bitmap_region we could add in the block group. * For contiguous group, the return bits will contains the whole group. * For a discontiguous one, every leaf extent record will become an * individual ocfs2_bitmap_region. So the 'bits' are set properly. */ static void chainalloc_get_next_region(ocfs2_filesys *fs, struct ocfs2_group_desc *gd, struct chainalloc_bitmap_private *cb, uint64_t *start_bit, int bit_offset, int *region_bits, int *set_bits) { int i; int bpc = cb->cb_cinode->ci_inode->id2.i_chain.cl_bpc; uint32_t cpos; uint64_t blkno = gd->bg_blkno; struct ocfs2_extent_rec *rec = NULL; if (!ocfs2_gd_is_discontig(gd) || !gd->bg_list.l_next_free_rec) { /* OK, a contiguous group. */ if (bit_offset) abort(); if (blkno == OCFS2_RAW_SB(fs->fs_super)->s_first_cluster_group) blkno = 0; *start_bit = chainalloc_scale_start_bit(fs, blkno, bpc); *region_bits = gd->bg_bits; *set_bits = gd->bg_bits - gd->bg_free_bits_count; return; } /* handle discontiguous group. */ cpos = bit_offset / bpc; for (i = 0; i < gd->bg_list.l_next_free_rec; i++) { rec = &gd->bg_list.l_recs[i]; if (rec->e_cpos == cpos) break; } if (i == gd->bg_list.l_next_free_rec) abort(); *start_bit = chainalloc_scale_start_bit(fs, rec->e_blkno, bpc); *region_bits = rec->e_leaf_clusters * bpc; *set_bits = ocfs2_get_bits_set(gd->bg_bitmap, bit_offset + *region_bits, bit_offset); return; } /* * Create bitmap regions for the group. * For contiguous group, create one region for the whole group. * For a discontiguous one, every leaf extent record will become an * individual ocfs2_bitmap_region and be inserted. */ static errcode_t create_chainalloc_region(ocfs2_filesys *fs, ocfs2_bitmap *bitmap, struct ocfs2_group_desc *gd, struct chainalloc_bitmap_private *cb) { errcode_t ret; int total_bits = gd->bg_bits; int region_bits = 0, bit_offset = 0, set_bits = 0; uint64_t start_bit; struct chainalloc_region_private *cr = NULL; struct ocfs2_bitmap_region *br = NULL; while (total_bits) { chainalloc_get_next_region(fs, gd, cb, &start_bit, bit_offset, ®ion_bits, &set_bits); ret = ocfs2_malloc0(sizeof(struct chainalloc_region_private), &cr); if (ret) break; cr->cr_cb = cb; cr->cr_ag = gd; cr->bit_offset = bit_offset; /* * In case bit_offset isn't aligned to byte, * We have to alloc/copy some addiontal bits in * the head. */ ret = ocfs2_bitmap_alloc_region(bitmap, start_bit, bit_offset % 8, region_bits, &br); if (ret) break; br->br_private = cr; memcpy(br->br_bitmap, cr->cr_ag->bg_bitmap + bit_offset / 8, br->br_bytes); br->br_set_bits = set_bits; ret = ocfs2_bitmap_insert_region(bitmap, br); if (ret) break; br = NULL; cr = NULL; total_bits -= region_bits; bit_offset += region_bits; } if (br) ocfs2_bitmap_free_region(br); if (cr) ocfs2_free(&cr); return ret; } static int chainalloc_process_group(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data) { ocfs2_bitmap *bitmap = priv_data; struct chainalloc_bitmap_private *cb = bitmap->b_private; char *gd_buf; struct ocfs2_group_desc *gd; cb->cb_errcode = ocfs2_malloc_block(fs->fs_io, &gd_buf); if (cb->cb_errcode) return OCFS2_CHAIN_ABORT; cb->cb_errcode = ocfs2_read_group_desc(fs, gd_blkno, gd_buf); if (cb->cb_errcode) goto out_free_buf; gd = (struct ocfs2_group_desc *)gd_buf; cb->cb_errcode = create_chainalloc_region(fs, bitmap, gd, cb); if (cb->cb_errcode) goto out_free_buf; return 0; out_free_buf: ocfs2_free(&gd_buf); return OCFS2_CHAIN_ABORT; } static errcode_t chainalloc_read_bitmap(ocfs2_bitmap *bitmap) { errcode_t ret; struct chainalloc_bitmap_private *cb = bitmap->b_private; if (!cb->cb_cinode) return OCFS2_ET_INVALID_ARGUMENT; ret = ocfs2_chain_iterate(bitmap->b_fs, cb->cb_cinode->ci_blkno, chainalloc_process_group, bitmap); return ret; } static errcode_t chainalloc_write_group(struct ocfs2_bitmap_region *br, void *private_data) { struct chainalloc_region_private *cr = br->br_private; ocfs2_filesys *fs = private_data; errcode_t ret = 0; uint8_t *bm, *gbm; int offset, end; if (!cr->cr_dirty) return 0; if (cr->bit_offset) { /* * Discontiguous block group. * The lower bits of bg_bitmap[0] isn't controled by this br, * so we should copy them from the original group bitmap. */ offset = cr->bit_offset % 8; gbm = &cr->cr_ag->bg_bitmap[cr->bit_offset / 8]; bm = &br->br_bitmap[0]; *bm &= 0xFF << offset; *bm |= *gbm & (0xFF >> (8 - offset)); } if (br->br_total_bits % 8 != 0) { end = cr->bit_offset + br->br_valid_bits; offset = end % 8; gbm = &cr->cr_ag->bg_bitmap[end / 8]; bm = &br->br_bitmap[br->br_total_bits / 8]; *bm &= 0xFF >> (8 - offset); *bm |= *gbm & (0xFF << offset); } memcpy(cr->cr_ag->bg_bitmap + cr->bit_offset / 8, br->br_bitmap, br->br_bytes); ret = ocfs2_write_group_desc(fs, cr->cr_ag->bg_blkno, (char *)cr->cr_ag); if (ret == 0) cr->cr_dirty = 0; return ret; } static errcode_t chainalloc_write_bitmap(ocfs2_bitmap *bitmap) { struct chainalloc_bitmap_private *cb = bitmap->b_private; ocfs2_filesys *fs; errcode_t ret; if (!cb->cb_cinode) return OCFS2_ET_INVALID_ARGUMENT; if (!cb->cb_dirty) return 0; fs = cb->cb_cinode->ci_fs; ret = ocfs2_bitmap_foreach_region(bitmap, chainalloc_write_group, fs); if (ret) goto out; ret = ocfs2_write_cached_inode(fs, cb->cb_cinode); if (ret == 0) cb->cb_dirty = 0; out: return ret; } static int chainalloc_merge_region(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *prev, struct ocfs2_bitmap_region *next) { /* Can't merge */ return 0; } /* update the free bit counts in the alloc group, chain rec, and inode so * that they are valid if we're asked to write in the future */ static void chainalloc_bit_change_notify(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br, uint64_t bitno, int new_val) { struct chainalloc_bitmap_private *cb = bitmap->b_private; struct chainalloc_region_private *cr = br->br_private; struct ocfs2_dinode *di = cb->cb_cinode->ci_inode; struct ocfs2_group_desc *ag = cr->cr_ag; struct ocfs2_chain_rec *rec = &di->id2.i_chain.cl_recs[ag->bg_chain]; if (new_val) { ag->bg_free_bits_count--; rec->c_free--; di->id1.bitmap1.i_used++; } else { ag->bg_free_bits_count++; rec->c_free++; di->id1.bitmap1.i_used--; } cr->cr_dirty = 1; cb->cb_dirty = 1; } static struct ocfs2_bitmap_operations chainalloc_bitmap_ops = { .set_bit = ocfs2_bitmap_set_generic, .clear_bit = ocfs2_bitmap_clear_generic, .test_bit = ocfs2_bitmap_test_generic, .find_next_set = ocfs2_bitmap_find_next_set_generic, .find_next_clear = ocfs2_bitmap_find_next_clear_generic, .merge_region = chainalloc_merge_region, .read_bitmap = chainalloc_read_bitmap, .write_bitmap = chainalloc_write_bitmap, .destroy_notify = chainalloc_destroy_notify, .bit_change_notify = chainalloc_bit_change_notify, .alloc_range = ocfs2_bitmap_alloc_range_generic, .clear_range = ocfs2_bitmap_clear_range_generic, }; static errcode_t ocfs2_chainalloc_bitmap_new(ocfs2_filesys *fs, const char *description, uint64_t total_bits, ocfs2_bitmap **ret_bitmap) { errcode_t ret; ocfs2_bitmap *bitmap; struct chainalloc_bitmap_private *cb; ret = ocfs2_malloc0(sizeof(struct chainalloc_bitmap_private), &cb); if (ret) return ret; ret = ocfs2_bitmap_new(fs, total_bits, description ? description : "Generic chain allocator bitmap", &chainalloc_bitmap_ops, cb, &bitmap); if (ret) return ret; *ret_bitmap = bitmap; return 0; } static void ocfs2_chainalloc_set_private(ocfs2_bitmap *bitmap, ocfs2_cached_inode *cinode, uint64_t gb_blkno) { struct chainalloc_bitmap_private *cb = bitmap->b_private; cb->cb_cinode = cinode; cb->cb_suballoc = (gb_blkno != cinode->ci_inode->i_blkno); } errcode_t ocfs2_load_chain_allocator(ocfs2_filesys *fs, ocfs2_cached_inode *cinode) { errcode_t ret; uint64_t total_bits, gb_blkno; char name[256]; if (cinode->ci_chains) ocfs2_bitmap_free(cinode->ci_chains); total_bits = (uint64_t)fs->fs_clusters * cinode->ci_inode->id2.i_chain.cl_bpc; ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &gb_blkno); if (ret) return ret; snprintf(name, sizeof(name), "Chain allocator inode %"PRIu64, cinode->ci_blkno); ret = ocfs2_chainalloc_bitmap_new(fs, name, total_bits, &cinode->ci_chains); if (ret) return ret; ocfs2_chainalloc_set_private(cinode->ci_chains, cinode, gb_blkno); ret = ocfs2_bitmap_read(cinode->ci_chains); if (ret) { ocfs2_bitmap_free(cinode->ci_chains); return ret; } return 0; } errcode_t ocfs2_write_chain_allocator(ocfs2_filesys *fs, ocfs2_cached_inode *cinode) { if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; return ocfs2_bitmap_write(cinode->ci_chains); } /* FIXME: should take a hint, no? */ /* FIXME: Better name, too */ errcode_t ocfs2_chain_alloc_range(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t min, uint64_t requested, uint64_t *start_bit, uint64_t *bits_found) { if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; return ocfs2_bitmap_alloc_range(cinode->ci_chains, min, requested, start_bit, bits_found); } errcode_t ocfs2_chain_free_range(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t len, uint64_t start_bit) { if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; return ocfs2_bitmap_clear_range(cinode->ci_chains, len, start_bit); } struct find_gd_state { ocfs2_filesys *fs; uint64_t bitno; uint64_t gd_blkno; uint64_t suballoc_bit; int found; }; static errcode_t chainalloc_find_gd(struct ocfs2_bitmap_region *br, void *private_data) { struct chainalloc_region_private *cr = br->br_private; struct find_gd_state *state = private_data; if ((state->bitno >= br->br_start_bit) && (state->bitno < (br->br_start_bit + br->br_valid_bits))) { state->found = 1; state->gd_blkno = cr->cr_ag->bg_blkno; state->suballoc_bit = state->bitno - br->br_start_bit + cr->bit_offset; if (state->gd_blkno == OCFS2_RAW_SB(state->fs->fs_super)->s_first_cluster_group) state->gd_blkno = 0; return OCFS2_ET_ITERATION_COMPLETE; } return 0; } errcode_t ocfs2_chain_alloc(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t *gd_blkno, uint16_t *suballoc_bit, uint64_t *bitno) { errcode_t ret; int oldval; struct find_gd_state state; if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; ret = ocfs2_bitmap_find_next_clear(cinode->ci_chains, 0, bitno); if (ret) return ret; ret = ocfs2_bitmap_set(cinode->ci_chains, *bitno, &oldval); if (ret) return ret; if (oldval) return OCFS2_ET_INTERNAL_FAILURE; state = (struct find_gd_state) { .fs = fs, .bitno = *bitno, }; ret = ocfs2_bitmap_foreach_region(cinode->ci_chains, chainalloc_find_gd, &state); if (!ret) { if (state.found) { *gd_blkno = state.gd_blkno; *suballoc_bit = state.suballoc_bit; } else ret = OCFS2_ET_INTERNAL_FAILURE; } return ret; } errcode_t ocfs2_chain_free(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno) { errcode_t ret; int oldval; if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; ret = ocfs2_bitmap_clear(cinode->ci_chains, bitno, &oldval); if (ret) return ret; if (!oldval) return OCFS2_ET_FREEING_UNALLOCATED_REGION; return 0; } /* just a variant that won't return failure if it tried to set what * was already set */ errcode_t ocfs2_chain_force_val(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno, int newval, int *oldval) { errcode_t ret; if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; if (newval) ret = ocfs2_bitmap_set(cinode->ci_chains, bitno, oldval); else ret = ocfs2_bitmap_clear(cinode->ci_chains, bitno, oldval); return ret; } errcode_t ocfs2_chain_test(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno, int *oldval) { if (!cinode->ci_chains) return OCFS2_ET_INVALID_ARGUMENT; return ocfs2_bitmap_test(cinode->ci_chains, bitno, oldval); } void ocfs2_init_group_desc(ocfs2_filesys *fs, struct ocfs2_group_desc *gd, uint64_t blkno, uint32_t generation, uint64_t parent_inode, uint16_t bits, uint16_t chain, int suballoc) { memset(gd, 0, fs->fs_blocksize); strcpy((char *)gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE); gd->bg_generation = generation; gd->bg_size = ocfs2_group_bitmap_size(fs->fs_blocksize, suballoc, OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat); gd->bg_bits = bits; gd->bg_chain = chain; gd->bg_parent_dinode = parent_inode; gd->bg_blkno = blkno; /* First bit set to account for the descriptor block */ ocfs2_set_bit(0, gd->bg_bitmap); gd->bg_free_bits_count = gd->bg_bits - 1; } errcode_t ocfs2_chain_add_group(ocfs2_filesys *fs, ocfs2_cached_inode *cinode) { errcode_t ret; uint64_t blkno = 0, old_blkno = 0; uint32_t found; uint16_t chain_num; struct ocfs2_group_desc *gd; char *buf = NULL; struct ocfs2_chain_rec *rec = NULL; struct chainalloc_bitmap_private *cb = cinode->ci_chains->b_private; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; gd = (struct ocfs2_group_desc *)buf; ret = ocfs2_new_clusters(fs, cinode->ci_inode->id2.i_chain.cl_cpg, cinode->ci_inode->id2.i_chain.cl_cpg, &blkno, &found); if (ret) goto out; if (found != cinode->ci_inode->id2.i_chain.cl_cpg) abort(); /* pick chain to add to */ if (cinode->ci_inode->id2.i_chain.cl_next_free_rec < cinode->ci_inode->id2.i_chain.cl_count) chain_num = cinode->ci_inode->id2.i_chain.cl_next_free_rec; else chain_num = (cinode->ci_inode->i_clusters / cinode->ci_inode->id2.i_chain.cl_cpg) % cinode->ci_inode->id2.i_chain.cl_count; ocfs2_init_group_desc(fs, gd, blkno, fs->fs_super->i_fs_generation, cinode->ci_inode->i_blkno, cinode->ci_inode->id2.i_chain.cl_cpg * cinode->ci_inode->id2.i_chain.cl_bpc, chain_num, cb->cb_suballoc); rec = &cinode->ci_inode->id2.i_chain.cl_recs[chain_num]; old_blkno = rec->c_blkno; gd->bg_next_group = old_blkno; ret = ocfs2_write_group_desc(fs, blkno, (char *)gd); if (ret) goto out; /* XXX could be a helper? */ rec->c_free += gd->bg_free_bits_count; rec->c_total += gd->bg_bits; rec->c_blkno = blkno; cinode->ci_inode->i_clusters += cinode->ci_inode->id2.i_chain.cl_cpg; cinode->ci_inode->i_size = (uint64_t)cinode->ci_inode->i_clusters * fs->fs_clustersize; cinode->ci_inode->id1.bitmap1.i_total += gd->bg_bits; cinode->ci_inode->id1.bitmap1.i_used += gd->bg_bits - gd->bg_free_bits_count; if (cinode->ci_inode->id2.i_chain.cl_next_free_rec == chain_num) cinode->ci_inode->id2.i_chain.cl_next_free_rec = chain_num + 1; ret = ocfs2_write_cached_inode(fs, cinode); if (ret) goto out; /* XXX this is probably too clever by half */ ret = chainalloc_process_group(fs, blkno, chain_num, cinode->ci_chains); if (ret) { ret = cb->cb_errcode; goto out; } /* ok, it's official */ blkno = 0; rec = NULL; out: if (rec != NULL) { /* XXX also could be a helper */ rec->c_free -= gd->bg_free_bits_count; rec->c_total -= gd->bg_bits; rec->c_blkno = old_blkno; cinode->ci_inode->i_clusters -= cinode->ci_inode->id2.i_chain.cl_cpg; cinode->ci_inode->i_size = (uint64_t)cinode->ci_inode->i_clusters * fs->fs_clustersize; cinode->ci_inode->id1.bitmap1.i_total -= gd->bg_bits; cinode->ci_inode->id1.bitmap1.i_used -= gd->bg_bits - gd->bg_free_bits_count; if (cinode->ci_inode->id2.i_chain.cl_next_free_rec == (chain_num + 1) && old_blkno == 0) cinode->ci_inode->id2.i_chain.cl_next_free_rec = chain_num; ocfs2_write_cached_inode(fs, cinode); } if (blkno != 0) ocfs2_free_clusters(fs, cinode->ci_inode->id2.i_chain.cl_cpg, blkno); if (buf) ocfs2_free(&buf); return ret; } #ifdef DEBUG_EXE #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "debug_bitmap [-i ] \n"); } extern int opterr, optind; extern char *optarg; static void dump_regions(ocfs2_bitmap *bitmap) { struct ocfs2_bitmap_region *br; struct rb_node *node; fprintf(stdout, "Bitmap \"%s\": total = %"PRIu64", set = %"PRIu64"\n", bitmap->b_description, bitmap->b_total_bits, bitmap->b_set_bits); for (node = rb_first(&bitmap->b_regions);node; node = rb_next(node)) { br = rb_entry(node, struct ocfs2_bitmap_region, br_node); fprintf(stdout, "(start: %"PRIu64", n: %d, set: %d)\n", br->br_start_bit, br->br_valid_bits, br->br_set_bits); } } static void print_bitmap(ocfs2_bitmap *bitmap) { uint64_t bitno; uint64_t gap_start = 0; /* GCC is dumb */ errcode_t ret; int val, gap; gap = 0; for (bitno = 0; bitno < bitmap->b_total_bits; bitno++) { ret = ocfs2_bitmap_test(bitmap, bitno, &val); if (ret) { if (ret == OCFS2_ET_INVALID_BIT) { if (!gap) { gap = 1; gap_start = bitno; } continue; } com_err("print_bitmap", ret, "while testing bit %"PRIu64"\n", bitno); break; } if (gap) { fprintf(stdout, "\nGap of length %"PRIu64" at %"PRIu64"\n", bitno - gap_start, gap_start); gap = bitno % 72; gap += gap / 8; for (; gap; gap--) fprintf(stdout, " "); fflush(stdout); } else { if (bitno && !(bitno % 72)) fprintf(stdout, "\n"); else if (bitno && !(bitno % 8)) fprintf(stdout, " "); } fprintf(stdout, "%d", val); fflush(stdout); } if ((bitno - 1) % 72) fprintf(stdout, "\n"); } static int try_op(ocfs2_bitmap *bitmap, errcode_t (*func)(ocfs2_bitmap *bitmap, uint64_t bitno, int *val), char *bit_val, int *ret_val) { errcode_t ret; uint64_t bitno; char *ptr; if (!bit_val) { fprintf(stderr, "You must provide a bit offset\n"); return 1; } bitno = read_number(bit_val); if (!bitno) { for (ptr = bit_val; *ptr; ptr++) { if (*ptr != '0') break; } if ((ptr == bit_val) || *ptr) { fprintf(stderr, "Invalid bit offset: %s\n", bit_val); return 1; } } ret = (*func)(bitmap, bitno, ret_val); if (ret) { com_err("try_op", ret, "while setting bit %"PRIu64"\n", bitno); return 1; } return 0; } static int try_op64(ocfs2_bitmap *bitmap, errcode_t (*func)(ocfs2_bitmap *bitmap, uint64_t bitno, uint64_t *val), char *bit_val, uint64_t *ret_val) { errcode_t ret; uint64_t bitno; char *ptr; if (!bit_val) { fprintf(stderr, "You must provide a bit offset\n"); return 1; } bitno = read_number(bit_val); if (!bitno) { for (ptr = bit_val; *ptr; ptr++) { if (*ptr != '0') break; } if ((ptr == bit_val) || *ptr) { fprintf(stderr, "Invalid bit offset: %s\n", bit_val); return 1; } } ret = (*func)(bitmap, bitno, ret_val); if (ret) { com_err("try_op64", ret, "while setting bit %"PRIu64"\n", bitno); return 1; } return 0; } static void run_test(ocfs2_bitmap *bitmap) { char buf[256]; char *ptr, *cmd; uint64_t val64; int val; while (1) { fprintf(stdout, "Command: "); fflush(stdout); if (!fgets(buf, sizeof(buf), stdin)) break; ptr = buf + strlen(buf) - 1; if (*ptr == '\n') *ptr = '\0'; for (cmd = buf; (*cmd == ' ') || (*cmd == '\t'); cmd++); if (!(*cmd)) continue; ptr = strchr(cmd, ' '); if (ptr) { *ptr = '\0'; ptr++; } if (!strcmp(cmd, "set")) { try_op(bitmap, ocfs2_bitmap_set, ptr, NULL); } else if (!strcmp(cmd, "clear")) { try_op(bitmap, ocfs2_bitmap_clear, ptr, NULL); } else if (!strcmp(cmd, "test")) { if (!try_op(bitmap, ocfs2_bitmap_test, ptr, &val)) { fprintf(stdout, "Bit %s is %s\n", ptr, val ? "set" : "clear"); } } else if (!strcmp(cmd, "fns")) { if (!try_op64(bitmap, ocfs2_bitmap_find_next_set, ptr, &val64)) { fprintf(stdout, "Found %"PRIu64"\n", val64); } } else if (!strcmp(cmd, "fnc")) { if (!try_op64(bitmap, ocfs2_bitmap_find_next_clear, ptr, &val64)) { fprintf(stdout, "Found %"PRIu64"\n", val64); } } else if (!strcmp(cmd, "print")) { print_bitmap(bitmap); } else if (!strcmp(cmd, "dump")) { dump_regions(bitmap); } else if (!strcmp(cmd, "quit")) { break; } else { fprintf(stderr, "Invalid command: \"%s\"\n", cmd); } } } int main(int argc, char *argv[]) { errcode_t ret; int c; char *filename; uint64_t blkno = 0; ocfs2_filesys *fs; ocfs2_cached_inode *cinode; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (!blkno) { print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); return 1; } ret = ocfs2_read_cached_inode(fs, blkno, &cinode); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_close; } ret = ocfs2_load_chain_allocator(fs, cinode); if (ret) { com_err(argv[0], ret, "while loading chain allocator"); goto out_free_inode; } run_test(cinode->ci_chains); out_free_inode: ocfs2_free_cached_inode(fs, cinode); out_close: ocfs2_close(fs); return ret; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/checkhb.c0000664000176100017610000000776411506552637014246 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * checkhb.c * * ocfs2 check heartbeat function * * Copyright (C) 2004 Oracle. All rights reserved. * * 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 021110-1307, USA. */ #define _LARGEFILE64_SOURCE #define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */ #include #include #include #include #include #include #include #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include "ocfs2-kernel/ocfs1_fs_compat.h" /* * ocfs2_check_heartbeats() check if the list of ocfs2 devices are * mounted on the cluster or not * * Return: * mounted_flags set to ==> * OCFS2_MF_MOUNTED if mounted locally * OCFS2_MF_ISROOT * OCFS2_MF_READONLY * OCFS2_MF_SWAP * OCFS2_MF_BUSY * OCFS2_MF_MOUNTED_CLUSTER if mounted on cluster */ errcode_t ocfs2_check_heartbeats(struct list_head *dev_list, int ignore_local) { ocfs2_filesys *fs = NULL; errcode_t ret = 0; struct list_head *pos; ocfs2_devices *dev = NULL; char *device= NULL; int open_flags, i; list_for_each(pos, dev_list) { dev = list_entry(pos, ocfs2_devices, list); device = dev->dev_name; /* open fs */ fs = NULL; open_flags = OCFS2_FLAG_RO | OCFS2_FLAG_HEARTBEAT_DEV_OK; ret = ocfs2_open(device, open_flags, 0, 0, &fs); if (ret) { ret = 0; continue; } else dev->fs_type = 2; if (OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV)) dev->hb_dev = 1; /* is it locally mounted */ if (!ignore_local || !dev->hb_dev) { ret = ocfs2_check_mount_point(device, &dev->mount_flags, NULL, 0); if (ret) goto bail; } /* get label/uuid for ocfs2 */ memcpy(dev->label, OCFS2_RAW_SB(fs->fs_super)->s_label, sizeof(dev->label)); memcpy(dev->uuid, OCFS2_RAW_SB(fs->fs_super)->s_uuid, sizeof(dev->uuid)); if (OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT)) snprintf(dev->stack, sizeof(dev->stack), "%s", "local"); else if (ocfs2_userspace_stack(OCFS2_RAW_SB(fs->fs_super))) snprintf(dev->stack, sizeof(dev->stack), "%.*s", OCFS2_STACK_LABEL_LEN, OCFS2_RAW_SB(fs->fs_super)->s_cluster_info.ci_stack); else snprintf(dev->stack, sizeof(dev->stack), "%s", "o2cb"); if (dev->hb_dev) goto close; /* read slotmap to get nodes on which the volume is mounted */ ret = ocfs2_load_slot_map(fs, &dev->map); if (ret) { dev->errcode = ret; ret = 0; } else { for (i = 0; i < dev->map->md_num_slots; i++) { if (dev->map->md_slots[i].sd_valid) { dev->mount_flags |= OCFS2_MF_MOUNTED_CLUSTER; break; } } } close: ocfs2_close(fs); } bail: return ret; } /* * ocfs2_get_ocfs1_label() * */ errcode_t ocfs2_get_ocfs1_label(char *device, uint8_t *label, uint16_t label_len, uint8_t *uuid, uint16_t uuid_len) { int fd = -1; int ret = OCFS2_ET_IO; char buf[512]; struct ocfs1_vol_label *v1_lbl; fd = open64(device, O_RDONLY); if (fd == -1) goto bail; if (pread(fd, buf, sizeof(buf), 512) == -1) goto bail; v1_lbl = (struct ocfs1_vol_label *)buf; memcpy(label, v1_lbl->label, label_len); memcpy(uuid, v1_lbl->vol_id, uuid_len); ret = 0; bail: if (fd >= 0) close(fd); return ret; } ./ocfs2-tools-1.6.4/libocfs2/closefs.c0000644000176100017610000000320011453177334014266 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * closefs.c * * Close an OCFS2 filesystem. Part of the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/closefs.c * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include "ocfs2/ocfs2.h" errcode_t ocfs2_flush(ocfs2_filesys *fs) { int type; errcode_t ret; for (type = 0; type < MAXQUOTAS; type++) if (fs->qinfo[type].flags & OCFS2_QF_INFO_DIRTY) { ret = ocfs2_write_global_quota_info(fs, type); if (ret) return ret; ret = ocfs2_write_cached_inode(fs, fs->qinfo[type].qi_inode); if (ret) return ret; } return 0; } errcode_t ocfs2_close(ocfs2_filesys *fs) { errcode_t ret; if (fs->fs_flags & OCFS2_FLAG_DIRTY) { ret = ocfs2_flush(fs); if (ret) return ret; } ocfs2_freefs(fs); return 0; } ./ocfs2-tools-1.6.4/libocfs2/dirblock.c0000664000176100017610000003167311506552637014444 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dirblock.c * * Directory block routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/dirblock.c * Copyright (C) 1995, 1996 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" unsigned int ocfs2_dir_trailer_blk_off(ocfs2_filesys *fs) { return fs->fs_blocksize - sizeof(struct ocfs2_dir_block_trailer); } struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_block(ocfs2_filesys *fs, void *data) { char *p = data; p += ocfs2_dir_trailer_blk_off(fs); return (struct ocfs2_dir_block_trailer *)p; } int ocfs2_dir_has_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di) { if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) && (di->i_dyn_features & OCFS2_INLINE_DATA_FL)) return 0; if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)) && di->i_dyn_features & OCFS2_INDEXED_DIR_FL) return 1; return ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super)); } int ocfs2_supports_dir_trailer(ocfs2_filesys *fs) { return ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super)) || ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)); } int ocfs2_skip_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct ocfs2_dir_entry *de, unsigned long offset) { if (!ocfs2_dir_has_trailer(fs, di)) return 0; if (offset != ocfs2_dir_trailer_blk_off(fs)) return 0; return 1; } /* * We are sure there is prepared space for the trailer, no directory * entry will overlap with the trailer: * - if we rebuild the indexed tree for a directory, no dir entry * will overwrite the trailer's space. * - if we build the indexed tree by tunefs.ocfs2, it will enable * meta ecc feature before enable indexed dirs feature. Which * means space for each trailer is well prepared already. */ void ocfs2_init_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t blkno, void *buf) { struct ocfs2_dir_block_trailer *trailer = ocfs2_dir_trailer_from_block(fs, buf); memset(trailer, 0, sizeof(struct ocfs2_dir_block_trailer)); memcpy(trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE, strlen(OCFS2_DIR_TRAILER_SIGNATURE)); trailer->db_compat_rec_len = sizeof(struct ocfs2_dir_block_trailer); trailer->db_blkno = blkno; trailer->db_parent_dinode = di->i_blkno; } static void ocfs2_swap_dir_entry(struct ocfs2_dir_entry *dirent) { if (cpu_is_little_endian) return; dirent->inode = bswap_64(dirent->inode); dirent->rec_len = bswap_16(dirent->rec_len); } static errcode_t ocfs2_swap_dir_entries_direction(void *buf, uint64_t bytes, int to_cpu) { char *p, *end; struct ocfs2_dir_entry *dirent; unsigned int name_len, rec_len; errcode_t retval = 0; p = (char *) buf; end = (char *) buf + bytes; while (p < end-12) { dirent = (struct ocfs2_dir_entry *) p; if (to_cpu) ocfs2_swap_dir_entry(dirent); name_len = dirent->name_len; rec_len = dirent->rec_len; if (!to_cpu) ocfs2_swap_dir_entry(dirent); if ((rec_len < 12) || (rec_len % 4)) { rec_len = 12; retval = OCFS2_ET_DIR_CORRUPTED; } if (((name_len & 0xFF) + 12) > rec_len) retval = OCFS2_ET_DIR_CORRUPTED; p += rec_len; } return retval; } errcode_t ocfs2_swap_dir_entries_from_cpu(void *buf, uint64_t bytes) { return ocfs2_swap_dir_entries_direction(buf, bytes, 0); } errcode_t ocfs2_swap_dir_entries_to_cpu(void *buf, uint64_t bytes) { return ocfs2_swap_dir_entries_direction(buf, bytes, 1); } void ocfs2_swap_dir_trailer(struct ocfs2_dir_block_trailer *trailer) { if (cpu_is_little_endian) return; trailer->db_compat_inode = bswap_64(trailer->db_compat_inode); trailer->db_compat_rec_len = bswap_64(trailer->db_compat_rec_len); trailer->db_blkno = bswap_64(trailer->db_blkno); trailer->db_parent_dinode = bswap_64(trailer->db_parent_dinode); trailer->db_free_rec_len = bswap_16(trailer->db_free_rec_len); trailer->db_free_next = bswap_64(trailer->db_free_next); } errcode_t ocfs2_read_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t block, void *buf) { errcode_t retval; int end = fs->fs_blocksize; struct ocfs2_dir_block_trailer *trailer = NULL; retval = ocfs2_read_blocks(fs, block, 1, buf); if (retval) goto out; if (ocfs2_dir_has_trailer(fs, di)) { end = ocfs2_dir_trailer_blk_off(fs); trailer = ocfs2_dir_trailer_from_block(fs, buf); retval = ocfs2_validate_meta_ecc(fs, buf, &trailer->db_check); if (retval) goto out; if (memcmp(trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE, strlen(OCFS2_DIR_TRAILER_SIGNATURE))) { retval = OCFS2_ET_BAD_DIR_BLOCK_MAGIC; goto out; } } retval = ocfs2_swap_dir_entries_to_cpu(buf, end); if (!retval) goto out; if (trailer) ocfs2_swap_dir_trailer(trailer); out: return retval; } errcode_t ocfs2_write_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t block, void *inbuf) { errcode_t retval; char *buf = NULL; int end = fs->fs_blocksize; struct ocfs2_dir_block_trailer *trailer = NULL; retval = ocfs2_malloc_block(fs->fs_io, &buf); if (retval) return retval; memcpy(buf, inbuf, fs->fs_blocksize); if (ocfs2_dir_has_trailer(fs, di)) end = ocfs2_dir_trailer_blk_off(fs); retval = ocfs2_swap_dir_entries_from_cpu(buf, end); if (retval) goto out; /* * We can always set trailer - ocfs2_compute_meta_ecc() does * nothing if the filesystem doesn't have the feature turned on */ trailer = ocfs2_dir_trailer_from_block(fs, buf); if (ocfs2_dir_has_trailer(fs, di)) ocfs2_swap_dir_trailer(trailer); ocfs2_compute_meta_ecc(fs, buf, &trailer->db_check); retval = io_write_block(fs->fs_io, block, 1, buf); out: ocfs2_free(&buf); return retval; } static void ocfs2_swap_dx_entry(struct ocfs2_dx_entry *dx_entry) { dx_entry->dx_major_hash = bswap_32(dx_entry->dx_major_hash); dx_entry->dx_minor_hash = bswap_32(dx_entry->dx_minor_hash); dx_entry->dx_dirent_blk = bswap_64(dx_entry->dx_dirent_blk); } static void ocfs2_swap_dx_entry_list_to_cpu(struct ocfs2_dx_entry_list *dl_list) { int i; if (cpu_is_little_endian) return; dl_list->de_count = bswap_16(dl_list->de_count); dl_list->de_num_used = bswap_16(dl_list->de_num_used); for (i = 0; i < dl_list->de_count; i++) ocfs2_swap_dx_entry(&dl_list->de_entries[i]); } static void ocfs2_swap_dx_entry_list_from_cpu(struct ocfs2_dx_entry_list *dl_list) { int i; if (cpu_is_little_endian) return; for (i = 0; i < dl_list->de_count; i++) ocfs2_swap_dx_entry(&dl_list->de_entries[i]); dl_list->de_count = bswap_16(dl_list->de_count); dl_list->de_num_used = bswap_16(dl_list->de_num_used); } static void ocfs2_swap_dx_root_to_cpu(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root) { if (cpu_is_little_endian) return; dx_root->dr_suballoc_slot = bswap_16(dx_root->dr_suballoc_slot); dx_root->dr_suballoc_bit = bswap_16(dx_root->dr_suballoc_bit); dx_root->dr_fs_generation = bswap_32(dx_root->dr_fs_generation); dx_root->dr_blkno = bswap_64(dx_root->dr_blkno); dx_root->dr_last_eb_blk = bswap_64(dx_root->dr_last_eb_blk); dx_root->dr_clusters = bswap_32(dx_root->dr_clusters); dx_root->dr_dir_blkno = bswap_64(dx_root->dr_dir_blkno); dx_root->dr_num_entries = bswap_32(dx_root->dr_num_entries); dx_root->dr_free_blk = bswap_64(dx_root->dr_free_blk); if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) ocfs2_swap_dx_entry_list_to_cpu(&dx_root->dr_entries); else ocfs2_swap_extent_list_to_cpu(fs, dx_root, &dx_root->dr_list); } static void ocfs2_swap_dx_root_from_cpu(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root) { if (cpu_is_little_endian) return; dx_root->dr_suballoc_slot = bswap_16(dx_root->dr_suballoc_slot); dx_root->dr_suballoc_bit = bswap_16(dx_root->dr_suballoc_bit); dx_root->dr_fs_generation = bswap_32(dx_root->dr_fs_generation); dx_root->dr_blkno = bswap_64(dx_root->dr_blkno); dx_root->dr_last_eb_blk = bswap_64(dx_root->dr_last_eb_blk); dx_root->dr_clusters = bswap_32(dx_root->dr_clusters); dx_root->dr_dir_blkno = bswap_64(dx_root->dr_dir_blkno); dx_root->dr_num_entries = bswap_32(dx_root->dr_num_entries); dx_root->dr_free_blk = bswap_64(dx_root->dr_free_blk); if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) ocfs2_swap_dx_entry_list_from_cpu(&dx_root->dr_entries); else ocfs2_swap_extent_list_from_cpu(fs, dx_root, &dx_root->dr_list); } /* XXX: should use the errcode_t return value */ errcode_t ocfs2_read_dx_root(ocfs2_filesys *fs, uint64_t block, void *buf) { errcode_t ret; struct ocfs2_dx_root_block *dx_root; char *dx_root_buf = NULL; ret = ocfs2_malloc_block(fs->fs_io, &dx_root_buf); if (ret) goto out; ret = ocfs2_read_blocks(fs, block, 1, dx_root_buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)dx_root_buf; ret = ocfs2_validate_meta_ecc(fs, dx_root_buf, &dx_root->dr_check); if (ret) goto out; if (memcmp(dx_root->dr_signature, OCFS2_DX_ROOT_SIGNATURE, strlen(OCFS2_DX_ROOT_SIGNATURE))) { ret = OCFS2_ET_DIR_CORRUPTED; goto out; } ocfs2_swap_dx_root_to_cpu(fs, dx_root); memcpy(buf, dx_root_buf, fs->fs_blocksize); ret = 0; out: if (dx_root_buf) ocfs2_free(&dx_root_buf); return ret; } errcode_t ocfs2_write_dx_root(ocfs2_filesys *fs, uint64_t block, char *buf) { errcode_t ret; char *dx_root_buf = NULL; struct ocfs2_dx_root_block *dx_root; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((block < OCFS2_SUPER_BLOCK_BLKNO) || (block > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &dx_root_buf); if (ret) goto out; memcpy(dx_root_buf, buf, fs->fs_blocksize); dx_root = (struct ocfs2_dx_root_block *)dx_root_buf; ocfs2_swap_dx_root_from_cpu(fs, dx_root); ocfs2_compute_meta_ecc(fs, dx_root_buf, &dx_root->dr_check); ret = io_write_block(fs->fs_io, block, 1, dx_root_buf); if (!ret) fs->fs_flags |= OCFS2_FLAG_CHANGED; out: if (dx_root_buf) ocfs2_free(&dx_root_buf); return ret; } static void ocfs2_swap_dx_leaf_to_cpu(struct ocfs2_dx_leaf *dx_leaf) { if (cpu_is_little_endian) return; dx_leaf->dl_blkno = bswap_64(dx_leaf->dl_blkno); dx_leaf->dl_fs_generation = bswap_64(dx_leaf->dl_fs_generation); ocfs2_swap_dx_entry_list_to_cpu(&dx_leaf->dl_list); } static void ocfs2_swap_dx_leaf_from_cpu(struct ocfs2_dx_leaf *dx_leaf) { if (cpu_is_little_endian) return; dx_leaf->dl_blkno = bswap_64(dx_leaf->dl_blkno); dx_leaf->dl_fs_generation = bswap_64(dx_leaf->dl_fs_generation); ocfs2_swap_dx_entry_list_from_cpu(&dx_leaf->dl_list); } errcode_t ocfs2_read_dx_leaf(ocfs2_filesys *fs, uint64_t block, void *buf) { errcode_t ret; struct ocfs2_dx_leaf *dx_leaf; ret = ocfs2_read_blocks(fs, block, 1, buf); if (ret) return ret; dx_leaf = (struct ocfs2_dx_leaf *)buf; ret = ocfs2_validate_meta_ecc(fs, buf, &dx_leaf->dl_check); if (ret) return ret; if (memcmp(dx_leaf->dl_signature, OCFS2_DX_LEAF_SIGNATURE, strlen(OCFS2_DX_LEAF_SIGNATURE))) return OCFS2_ET_DIR_CORRUPTED; ocfs2_swap_dx_leaf_to_cpu(dx_leaf); return 0; } errcode_t ocfs2_write_dx_leaf(ocfs2_filesys *fs, uint64_t block, void *buf) { errcode_t ret; char *dx_leaf_buf = NULL; struct ocfs2_dx_leaf *dx_leaf; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((block < OCFS2_SUPER_BLOCK_BLKNO) || (block > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &dx_leaf_buf); if (ret) goto out; memcpy(dx_leaf_buf, buf, fs->fs_blocksize); dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_buf; ocfs2_swap_dx_leaf_from_cpu(dx_leaf); ocfs2_compute_meta_ecc(fs, dx_leaf_buf, &dx_leaf->dl_check); ret = io_write_block(fs->fs_io, block, 1, dx_leaf_buf); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; out: if (dx_leaf_buf) ocfs2_free(&dx_leaf_buf); return ret; } int ocfs2_dir_indexed(struct ocfs2_dinode *di) { if (di->i_dyn_features & OCFS2_INDEXED_DIR_FL) return 1; return 0; } /* * Only use this when we already know the directory is indexed. */ static int __ocfs2_is_dir_trailer(ocfs2_filesys *fs, unsigned long de_off) { if (de_off == ocfs2_dir_trailer_blk_off(fs)) return 1; return 0; } int ocfs2_is_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, unsigned long de_off) { if (ocfs2_dir_has_trailer(fs, di)) { return __ocfs2_is_dir_trailer(fs, de_off); } return 0; } ./ocfs2-tools-1.6.4/libocfs2/dir_iterate.c0000644000176100017610000003355711500500544015127 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dirblock.c * * Directory block routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/dir_iterate.c * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/ocfs2.h" #include "dir_iterate.h" #include "dir_util.h" static int ocfs2_inline_dir_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct dir_context *ctx); /* * This function checks to see whether or not a potential deleted * directory entry looks valid. What we do is check the deleted entry * and each successive entry to make sure that they all look valid and * that the last deleted entry ends at the beginning of the next * undeleted entry. Returns 1 if the deleted entry looks valid, zero * if not valid. */ static int ocfs2_validate_entry(char *buf, int offset, int final_offset) { struct ocfs2_dir_entry *dirent; while (offset < final_offset) { dirent = (struct ocfs2_dir_entry *)(buf + offset); offset += dirent->rec_len; if ((dirent->rec_len < 8) || ((dirent->rec_len % 4) != 0) || (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) return 0; } return (offset == final_offset); } errcode_t ocfs2_dir_iterate2(ocfs2_filesys *fs, uint64_t dir, int flags, char *block_buf, int (*func)(uint64_t dir, int entry, struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data), void *priv_data) { struct ocfs2_dinode *di; struct dir_context ctx; errcode_t retval; retval = ocfs2_check_directory(fs, dir); if (retval) return retval; ctx.dir = dir; ctx.flags = flags; if (block_buf) ctx.buf = block_buf; else { retval = ocfs2_malloc_block(fs->fs_io, &ctx.buf); if (retval) return retval; } ctx.func = func; ctx.priv_data = priv_data; ctx.errcode = 0; retval = ocfs2_malloc_block(fs->fs_io, &ctx.di); if (retval) goto out; retval = ocfs2_read_inode(fs, dir, ctx.buf); if (retval) goto out; /* * Save off the inode - some paths use the buffer for dirent * data. */ memcpy(ctx.di, ctx.buf, fs->fs_blocksize); di = (struct ocfs2_dinode *)ctx.buf; if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) && di->i_dyn_features & OCFS2_INLINE_DATA_FL) retval = ocfs2_inline_dir_iterate(fs, di, &ctx); else retval = ocfs2_block_iterate(fs, dir, 0, ocfs2_process_dir_block, &ctx); out: if (!block_buf) ocfs2_free(&ctx.buf); if (ctx.di) ocfs2_free(&ctx.di); if (retval) return retval; return ctx.errcode; } struct xlate { int (*func)(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data); void *real_private; }; static int xlate_func(uint64_t dir, int entry, struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct xlate *xl = (struct xlate *) priv_data; return (*xl->func)(dirent, blocknr, offset, blocksize, buf, xl->real_private); } extern errcode_t ocfs2_dir_iterate(ocfs2_filesys *fs, uint64_t dir, int flags, char *block_buf, int (*func)(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data), void *priv_data) { struct xlate xl; xl.real_private = priv_data; xl.func = func; return ocfs2_dir_iterate2(fs, dir, flags, block_buf, xlate_func, &xl); } static int ocfs2_process_dir_entry(ocfs2_filesys *fs, uint64_t blocknr, unsigned int offset, int entry, int *changed, int *do_abort, struct dir_context *ctx) { errcode_t ret; struct ocfs2_dir_entry *dirent; unsigned int next_real_entry = 0; int size; while (offset < fs->fs_blocksize) { dirent = (struct ocfs2_dir_entry *) (ctx->buf + offset); if (((offset + dirent->rec_len) > fs->fs_blocksize) || (dirent->rec_len < 8) || ((dirent->rec_len % 4) != 0) || (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { ctx->errcode = OCFS2_ET_DIR_CORRUPTED; return OCFS2_BLOCK_ABORT; } if (ocfs2_skip_dir_trailer(fs, ctx->di, dirent, offset)) { if (!(ctx->flags & OCFS2_DIRENT_FLAG_INCLUDE_TRAILER)) goto next; } else if (!dirent->inode && !(ctx->flags & OCFS2_DIRENT_FLAG_INCLUDE_EMPTY)) { goto next; } else if ((ctx->flags & OCFS2_DIRENT_FLAG_EXCLUDE_DOTS) && is_dots(dirent->name, dirent->name_len)) { goto next; } ret = (ctx->func)(ctx->dir, (next_real_entry > offset) ? OCFS2_DIRENT_DELETED_FILE : entry, dirent, blocknr, offset, fs->fs_blocksize, ctx->buf, ctx->priv_data); if (entry < OCFS2_DIRENT_OTHER_FILE) entry++; if (ret & OCFS2_DIRENT_CHANGED) *changed += 1; if (ret & OCFS2_DIRENT_ABORT) { *do_abort += 1; break; } next: if (next_real_entry == offset) next_real_entry += dirent->rec_len; if (ctx->flags & OCFS2_DIRENT_FLAG_INCLUDE_REMOVED) { size = ((dirent->name_len & 0xFF) + 11) & ~3; if (dirent->rec_len != size) { unsigned int final_offset; final_offset = offset + dirent->rec_len; offset += size; while (offset < final_offset && !ocfs2_validate_entry(ctx->buf, offset, final_offset)) offset += 4; continue; } } offset += dirent->rec_len; } return 0; } static int ocfs2_inline_dir_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct dir_context *ctx) { unsigned int offset = offsetof(struct ocfs2_dinode, id2.i_data.id_data); int ret = 0, changed = 0, do_abort = 0, entry; entry = OCFS2_DIRENT_DOT_FILE; ret = ocfs2_process_dir_entry(fs, di->i_blkno, offset, entry, &changed, &do_abort, ctx); if (ret) return ret; if (changed) { ctx->errcode = ocfs2_write_inode(fs, di->i_blkno, ctx->buf); if (ctx->errcode) return OCFS2_BLOCK_ABORT; } return 0; } /* * Helper function which is private to this module. Used by * ocfs2_dir_iterate() and ocfs2_dblist_dir_iterate() */ int ocfs2_process_dir_block(ocfs2_filesys *fs, uint64_t blocknr, uint64_t blockcnt, uint16_t ext_flags, void *priv_data) { struct dir_context *ctx = (struct dir_context *) priv_data; unsigned int offset = 0; int ret = 0; int changed = 0; int do_abort = 0; int entry; if (blockcnt < 0) return 0; entry = blockcnt ? OCFS2_DIRENT_OTHER_FILE : OCFS2_DIRENT_DOT_FILE; ctx->errcode = ocfs2_read_dir_block(fs, ctx->di, blocknr, ctx->buf); if (ctx->errcode) return OCFS2_BLOCK_ABORT; ret = ocfs2_process_dir_entry(fs, blocknr, offset, entry, &changed, &do_abort, ctx); if (ret) return ret; if (changed) { ctx->errcode = ocfs2_write_dir_block(fs, ctx->di, blocknr, ctx->buf); if (ctx->errcode) return OCFS2_BLOCK_ABORT; } if (do_abort) return OCFS2_BLOCK_ABORT; return 0; } struct dx_iterator_data { int (*dx_func)(ocfs2_filesys *fs, struct ocfs2_dx_entry_list *entry_list, struct ocfs2_dx_root_block *dx_root, struct ocfs2_dx_leaf *dx_leaf, void *priv_data); void *dx_priv_data; char *leaf_buf; struct ocfs2_dx_root_block *dx_root; errcode_t err; }; static int dx_iterator(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { errcode_t err; int i; struct ocfs2_dx_leaf *dx_leaf; struct dx_iterator_data *iter = priv_data; uint64_t blkno, count; count = ocfs2_clusters_to_blocks(fs, rec->e_leaf_clusters); blkno = rec->e_blkno; for (i = 0; i < count; i++) { err = ocfs2_read_dx_leaf(fs, blkno, iter->leaf_buf); if (err) { iter->err = err; return OCFS2_EXTENT_ERROR; } dx_leaf = (struct ocfs2_dx_leaf *)iter->leaf_buf; err = iter->dx_func(fs, &dx_leaf->dl_list, iter->dx_root, dx_leaf, iter->dx_priv_data); /* callback dx_func() is defined by users, the return value does not * follow libocfs2 error codes. Don't touch iter->err and just stop * the iteration here.*/ if (err) return OCFS2_EXTENT_ERROR; blkno++; } return 0; } extern errcode_t ocfs2_dx_entries_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *dir, int flags, int (*func)(ocfs2_filesys *fs, struct ocfs2_dx_entry_list *entry_list, struct ocfs2_dx_root_block *dx_root, struct ocfs2_dx_leaf *dx_leaf, void *priv_data), void *priv_data) { errcode_t ret = 0; struct ocfs2_dx_root_block *dx_root; uint64_t dx_blkno; char *buf = NULL, *eb_buf = NULL, *leaf_buf = NULL; struct dx_iterator_data data; if (!S_ISDIR(dir->i_mode) && !ocfs2_dir_indexed(dir)) { goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; dx_blkno = (uint64_t) dir->i_dx_root; ret = ocfs2_read_dx_root(fs, dx_blkno, buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)buf; if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) { ret = func(fs, &dx_root->dr_entries, dx_root, NULL, priv_data); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &eb_buf); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &leaf_buf); if (ret) goto out; data.dx_func = func; data.dx_priv_data = priv_data; data.leaf_buf = leaf_buf; data.dx_root = dx_root; data.err = 0; ret = ocfs2_extent_iterate_dx_root(fs, dx_root, OCFS2_EXTENT_FLAG_DATA_ONLY, eb_buf, dx_iterator, &data); /* dx_iterator may set the error code for non-extents-related * errors. If the error code is set by dx_iterator, no matter * what ocfs2_extent_iterate_dx_root() returns, we should take * data.err as retured error code. */ if (data.err) ret = data.err; out: if (buf) ocfs2_free(&buf); if (eb_buf) ocfs2_free(&eb_buf); if (leaf_buf) ocfs2_free(&leaf_buf); return ret; } extern errcode_t ocfs2_dx_frees_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *dir, struct ocfs2_dx_root_block *dx_root, int flags, int (*func)(ocfs2_filesys *fs, uint64_t blkno, struct ocfs2_dir_block_trailer *trailer, char *dirblock, void *priv_data), void *priv_data) { errcode_t ret = 0; uint64_t blkno; char *buf = NULL; struct ocfs2_dir_block_trailer *trailer; if (!S_ISDIR(dir->i_mode) || !(ocfs2_dir_indexed(dir))) { goto out; } if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) { goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; blkno = dx_root->dr_free_blk; while (blkno) { ret = ocfs2_read_dir_block(fs, dir, blkno, buf); if (ret) goto out; trailer = ocfs2_dir_trailer_from_block(fs, buf); func(fs, blkno, trailer, buf, priv_data); blkno = trailer->db_free_next; } out: if (buf) ocfs2_free(&buf); return ret; } #ifdef DEBUG_EXE #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: dir_iterate -i \n"); } static int walk_names_func(struct ocfs2_dir_entry *dentry, int offset, int blocksize, char *buf, void *priv_data) { char name[256]; memcpy(name, dentry->name, dentry->name_len); name[dentry->name_len] = '\0'; fprintf(stdout, "%20"PRIu64" %s\n", dentry->inode, name); return 0; } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno; int c; char *filename, *buf; ocfs2_filesys *fs; struct ocfs2_dinode *di; blkno = 0; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } if (blkno == 0) blkno = fs->fs_root_blkno; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_free; } di = (struct ocfs2_dinode *)buf; fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\"\n", blkno, filename); ret = ocfs2_dir_iterate(fs, blkno, 0, NULL, walk_names_func, NULL); if (ret) { com_err(argv[0], ret, "while listing inode %"PRIu64" on \"%s\"\n", blkno, filename); goto out_free; } out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/dir_scan.c0000664000176100017610000001375411170734140014421 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dir_scan.c * * Read all the entries in a directory. For the OCFS2 userspace * library. * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Manish Singh */ #include #include #include "ocfs2/ocfs2.h" #include "dir_util.h" struct _ocfs2_dir_scan { ocfs2_filesys *fs; int flags; char *buf; unsigned int bufsize; unsigned int total_bufsize; ocfs2_cached_inode *inode; uint64_t total_blocks; uint64_t blocks_read; unsigned int offset; }; static errcode_t get_more_dir_blocks(ocfs2_dir_scan *scan) { errcode_t ret; uint64_t blkno; uint64_t cblocks; if (scan->blocks_read == scan->total_blocks) return OCFS2_ET_ITERATION_COMPLETE; ret = ocfs2_extent_map_get_blocks(scan->inode, scan->blocks_read, 1, &blkno, &cblocks, NULL); if (ret) return ret; ret = ocfs2_read_dir_block(scan->fs, scan->inode->ci_inode, blkno, scan->buf); if (ret) return ret; scan->blocks_read++; scan->bufsize = scan->total_bufsize; scan->offset = 0; return 0; } static inline int valid_dirent(ocfs2_dir_scan *scan, struct ocfs2_dir_entry *dirent) { if (dirent->inode) { if ((scan->flags & OCFS2_DIR_SCAN_FLAG_EXCLUDE_DOTS) && is_dots(dirent->name, dirent->name_len)) return 0; else return 1; } return 0; } errcode_t ocfs2_get_next_dir_entry(ocfs2_dir_scan *scan, struct ocfs2_dir_entry *out_dirent) { errcode_t ret; struct ocfs2_dir_entry *dirent; do { if (scan->offset == scan->bufsize) { ret = get_more_dir_blocks(scan); if (ret == OCFS2_ET_ITERATION_COMPLETE) { memset(out_dirent, 0, sizeof(struct ocfs2_dir_entry)); return 0; } if (ret) return ret; } dirent = (struct ocfs2_dir_entry *) (scan->buf + scan->offset); if (((scan->offset + dirent->rec_len) > scan->fs->fs_blocksize) || (dirent->rec_len < 8) || ((dirent->rec_len % 4) != 0) || (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) return OCFS2_ET_DIR_CORRUPTED; scan->offset += dirent->rec_len; } while (!valid_dirent(scan, dirent) || ocfs2_skip_dir_trailer(scan->fs, scan->inode->ci_inode, dirent, scan->offset)); memcpy(out_dirent, dirent, sizeof(struct ocfs2_dir_entry)); return 0; } errcode_t ocfs2_open_dir_scan(ocfs2_filesys *fs, uint64_t dir, int flags, ocfs2_dir_scan **ret_scan) { ocfs2_dir_scan *scan; errcode_t ret; ret = ocfs2_check_directory(fs, dir); if (ret) return ret; ret = ocfs2_malloc0(sizeof(struct _ocfs2_dir_scan), &scan); if (ret) return ret; scan->fs = fs; scan->flags = flags; ret = ocfs2_malloc_block(fs->fs_io, &scan->buf); if (ret) goto bail_scan; ret = ocfs2_read_cached_inode(fs, dir, &scan->inode); if (ret) goto bail_dir_block; scan->total_blocks = scan->inode->ci_inode->i_size / fs->fs_blocksize; /* * Should we check i_size % blocksize? * total_blocks <= i_clusters? */ scan->total_bufsize = fs->fs_blocksize; *ret_scan = scan; return 0; bail_dir_block: ocfs2_free(&scan->buf); bail_scan: ocfs2_free(&scan); return ret; } void ocfs2_close_dir_scan(ocfs2_dir_scan *scan) { if (!scan) return; ocfs2_free_cached_inode(scan->fs, scan->inode); ocfs2_free(&scan->buf); ocfs2_free(&scan); return; } #ifdef DEBUG_EXE #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: dir_scan -i \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; char *filename; uint64_t blkno; int c; ocfs2_filesys *fs; ocfs2_dir_scan *scan; int done; struct ocfs2_dir_entry *dirent; blkno = 0; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc0(sizeof(struct ocfs2_dir_entry), &dirent); if (ret) { com_err(argv[0], ret, "while allocating dirent buffer"); goto out_close; } if (blkno == 0) blkno = fs->fs_root_blkno; ret = ocfs2_open_dir_scan(fs, blkno, 0, &scan); if (ret) { com_err(argv[0], ret, "while opening dir scan"); goto out_free; } done = 0; while (!done) { ret = ocfs2_get_next_dir_entry(scan, dirent); if (ret) { com_err(argv[0], ret, "while getting next dirent"); goto out_close_scan; } if (dirent->rec_len) { dirent->name[dirent->name_len] = '\0'; fprintf(stdout, "%s\n", dirent->name); } else done = 1; } out_close_scan: ocfs2_close_dir_scan(scan); out_free: ocfs2_free(&dirent); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/dlm.c0000664000176100017610000002105211506552637013415 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dlm.c * * Interface the OCFS2 userspace library to the userspace DLM library * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include "ocfs2/ocfs2.h" #define DEFAULT_DLMFS_PATH "/dlm/" static errcode_t ocfs2_get_journal_blkno(ocfs2_filesys *fs, uint64_t *jrnl_blkno) { struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super); char sysfile[OCFS2_MAX_FILENAME_LEN]; int i; errcode_t ret = 0; for (i = 0; i < sb->s_max_slots; ++i) { snprintf (sysfile, sizeof(sysfile), ocfs2_system_inodes[JOURNAL_SYSTEM_INODE].si_name, i); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, sysfile, strlen(sysfile), NULL, &(jrnl_blkno[i])); if (ret) goto bail; } bail: return ret; } errcode_t ocfs2_lock_down_cluster(ocfs2_filesys *fs) { struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super); uint64_t jrnl_blkno[OCFS2_MAX_SLOTS]; ocfs2_cached_inode *ci; errcode_t ret = 0; int i; ret = ocfs2_get_journal_blkno(fs, jrnl_blkno); if (ret) goto bail; ret = ocfs2_super_lock(fs); if (ret) goto bail; for (i = 0; i < sb->s_max_slots; ++i) { ret = ocfs2_read_cached_inode(fs, jrnl_blkno[i], &ci); if (ret) { ocfs2_super_unlock(fs); goto bail; } ret = ocfs2_meta_lock(fs, ci, O2DLM_LEVEL_EXMODE, O2DLM_TRYLOCK); if (ret) { ocfs2_super_unlock(fs); ocfs2_free_cached_inode(fs, ci); goto bail; } ocfs2_meta_unlock(fs, ci); ocfs2_free_cached_inode(fs, ci); } bail: return ret; } errcode_t ocfs2_release_cluster(ocfs2_filesys *fs) { errcode_t ret = 0; ret = ocfs2_super_unlock(fs); if (ret) goto bail; bail: return ret; } errcode_t ocfs2_fill_cluster_desc(ocfs2_filesys *fs, struct o2cb_cluster_desc *desc) { errcode_t ret = 0; struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super); if (!ocfs2_userspace_stack(sb)) { desc->c_stack = NULL; desc->c_cluster = NULL; return 0; } ret = ocfs2_malloc0(OCFS2_STACK_LABEL_LEN + 1, &desc->c_stack); if (ret) return ret; ret = ocfs2_malloc0(OCFS2_CLUSTER_NAME_LEN + 1, &desc->c_cluster); if (ret) { ocfs2_free(&desc->c_stack); return ret; } memcpy(desc->c_stack, sb->s_cluster_info.ci_stack, OCFS2_STACK_LABEL_LEN); memcpy(desc->c_cluster, sb->s_cluster_info.ci_cluster, OCFS2_CLUSTER_NAME_LEN); return 0; } errcode_t ocfs2_set_cluster_desc(ocfs2_filesys *fs, struct o2cb_cluster_desc *desc) { errcode_t ret; struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super); if (desc->c_stack) { if (!desc->c_stack[0] || !desc->c_cluster || !desc->c_cluster[0]) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } if (!ocfs2_uses_extended_slot_map(sb)) { sb->s_feature_incompat |= OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP; ret = ocfs2_format_slot_map(fs); if (ret) goto out; } sb->s_feature_incompat |= OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK; memcpy(sb->s_cluster_info.ci_stack, desc->c_stack, OCFS2_STACK_LABEL_LEN); memcpy(sb->s_cluster_info.ci_cluster, desc->c_cluster, OCFS2_CLUSTER_NAME_LEN); } else { sb->s_feature_incompat &= ~OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK; } ret = ocfs2_write_super(fs); out: return ret; } errcode_t ocfs2_initialize_dlm(ocfs2_filesys *fs, const char *service) { struct o2dlm_ctxt *dlm_ctxt = NULL; errcode_t ret = 0; int stackglue_support; struct o2cb_cluster_desc cluster; struct o2cb_region_desc desc; char *stack_path; ret = ocfs2_fill_cluster_desc(fs, &cluster); if (ret) goto bail; ret = ocfs2_fill_heartbeat_desc(fs, &desc); if (ret) goto bail; ret = o2dlm_supports_stackglue(&stackglue_support); if (ret) goto bail; desc.r_service = (char *)service; desc.r_persist = 0; ret = o2cb_begin_group_join(&cluster, &desc); if (ret) goto bail; /* * We want to use dlmfs if we can, as it provides the full feature * set of libo2dlm. Any dlmfs with the 'stackglue' capability will * support all cluster stacks. An empty cluster.c_stack means * o2cb, which always supports dlmfs. * * If we're unlucky enough to have older userspace stack code, * we pass NULL to avoid dlmfs. */ if (stackglue_support || !cluster.c_stack) stack_path = DEFAULT_DLMFS_PATH; else stack_path = NULL; ret = o2dlm_initialize(stack_path, fs->uuid_str, &dlm_ctxt); if (ret) { /* What to do with an error code? */ /* Ignore the result of complete_group_join, as we want * to propagate our o2dlm_initialize() error */ o2cb_complete_group_join(&cluster, &desc, ret); goto bail; } ret = o2cb_complete_group_join(&cluster, &desc, 0); if (!ret) fs->fs_dlm_ctxt = dlm_ctxt; else o2dlm_destroy(dlm_ctxt); bail: return ret; } errcode_t ocfs2_shutdown_dlm(ocfs2_filesys *fs, const char *service) { errcode_t ret; struct o2cb_cluster_desc cluster; struct o2cb_region_desc desc; ret = o2dlm_destroy(fs->fs_dlm_ctxt); if (ret) goto bail; fs->fs_dlm_ctxt = NULL; ret = ocfs2_fill_cluster_desc(fs, &cluster); if (ret) goto bail; ret = ocfs2_fill_heartbeat_desc(fs, &desc); if (ret) goto bail; desc.r_service = (char *)service; desc.r_persist = 0; ret = o2cb_group_leave(&cluster, &desc); bail: return ret; } errcode_t ocfs2_super_lock(ocfs2_filesys *fs) { char lock_name[OCFS2_LOCK_ID_MAX_LEN]; errcode_t ret; ocfs2_encode_lockres(OCFS2_LOCK_TYPE_SUPER, OCFS2_SUPER_BLOCK_BLKNO, 0, 0, lock_name); ret = o2dlm_lock(fs->fs_dlm_ctxt, lock_name, O2DLM_TRYLOCK, O2DLM_LEVEL_EXMODE); return ret; } errcode_t ocfs2_super_unlock(ocfs2_filesys *fs) { char lock_name[OCFS2_LOCK_ID_MAX_LEN]; errcode_t ret; ocfs2_encode_lockres(OCFS2_LOCK_TYPE_SUPER, OCFS2_SUPER_BLOCK_BLKNO, 0, 0, lock_name); ret = o2dlm_unlock(fs->fs_dlm_ctxt, lock_name); return ret; } errcode_t ocfs2_meta_lock(ocfs2_filesys *fs, ocfs2_cached_inode *ci, enum o2dlm_lock_level level, int flags) { char lock_name[OCFS2_LOCK_ID_MAX_LEN]; errcode_t ret; ocfs2_encode_lockres(OCFS2_LOCK_TYPE_META, ci->ci_blkno, ci->ci_inode->i_generation, 0, lock_name); ret = o2dlm_lock(fs->fs_dlm_ctxt, lock_name, flags, level); return ret; } errcode_t ocfs2_meta_unlock(ocfs2_filesys *fs, ocfs2_cached_inode *ci) { char lock_name[OCFS2_LOCK_ID_MAX_LEN]; errcode_t ret; ocfs2_encode_lockres(OCFS2_LOCK_TYPE_META, ci->ci_blkno, ci->ci_inode->i_generation, 0, lock_name); ret = o2dlm_unlock(fs->fs_dlm_ctxt, lock_name); return ret; } #ifdef DEBUG_EXE #include #include #include #include #define DEBUG_SERVICE "debug" static void print_usage(void) { fprintf(stderr, "Usage: dlm \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; int c; char *filename; ocfs2_filesys *fs = NULL; char *progname; initialize_ocfs_error_table(); initialize_o2dl_error_table(); if (argc < 2) { print_usage(); exit(1); } filename = argv[1]; progname = basename(argv[0]); ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(progname, ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_initialize_dlm(fs, DEBUG_SERVICE); if (ret) { com_err(progname, ret, "while initializing dlm"); goto out; } printf("DLM initialized\n"); ret = ocfs2_lock_down_cluster(fs); if (ret) { com_err(progname, ret, "while locking cluster"); goto out; } printf("Cluster is locked\nPress any key to continue..."); c = getchar(); ret = ocfs2_release_cluster(fs); if (ret) { com_err(progname, ret, "while releasing cluster"); goto out; } printf("Cluster released\n"); out: if (fs->fs_dlm_ctxt) { ret = ocfs2_shutdown_dlm(fs, DEBUG_SERVICE); if (ret) com_err(progname, ret, "while shutting down dlm"); } if (fs) { ret = ocfs2_close(fs); if (ret) com_err(progname, ret, "while closing file \"%s\"", filename); } return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/fileio.c0000644000176100017610000004422511453177334014113 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * fileio.c * * I/O to files. Part of the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/fileio.c * Copyright (C) 1997 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include "ocfs2/ocfs2.h" #include "refcount.h" struct read_whole_context { char *buf; char *ptr; int size; int offset; errcode_t errcode; }; static int read_whole_func(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data) { struct read_whole_context *ctx = priv_data; if (ext_flags & OCFS2_EXT_UNWRITTEN) { memset(ctx->ptr, 0, fs->fs_blocksize); ctx->errcode = 0; } else ctx->errcode = ocfs2_read_blocks(fs, blkno, 1, ctx->ptr); if (ctx->errcode) return OCFS2_BLOCK_ABORT; ctx->ptr += fs->fs_blocksize; ctx->offset += fs->fs_blocksize; return 0; } static errcode_t ocfs2_inline_data_read(struct ocfs2_dinode *di, void *buf, uint32_t count, uint64_t offset, uint32_t *got) { struct ocfs2_inline_data *id; uint8_t *p; if (!(di->i_dyn_features & OCFS2_INLINE_DATA_FL)) return OCFS2_ET_INVALID_ARGUMENT; id = &(di->id2.i_data); *got = 0; if (offset > id->id_count) return 0; p = (__u8 *) &(id->id_data); p += offset; *got = ocfs2_min((uint64_t)(di->i_size - offset), (uint64_t)count); memcpy(buf, p, *got); return 0; } errcode_t ocfs2_read_whole_file(ocfs2_filesys *fs, uint64_t blkno, char **buf, int *len) { struct read_whole_context ctx; errcode_t retval; char *inode_buf; struct ocfs2_dinode *di; /* So the caller can see nothing was read */ *len = 0; *buf = NULL; retval = ocfs2_malloc_block(fs->fs_io, &inode_buf); if (retval) return retval; retval = ocfs2_read_inode(fs, blkno, inode_buf); if (retval) goto out_free; di = (struct ocfs2_dinode *)inode_buf; /* Arbitrary limit for our malloc */ retval = OCFS2_ET_INVALID_ARGUMENT; if (di->i_size > INT_MAX) goto out_free; retval = ocfs2_malloc_blocks(fs->fs_io, ocfs2_blocks_in_bytes(fs, di->i_size), buf); if (retval) goto out_free; if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) return ocfs2_inline_data_read(di, *buf, di->i_size, 0, (uint32_t *)len); ctx.buf = *buf; ctx.ptr = *buf; ctx.size = di->i_size; ctx.offset = 0; ctx.errcode = 0; retval = ocfs2_block_iterate(fs, blkno, 0, read_whole_func, &ctx); *len = ctx.size; if (ctx.offset < ctx.size) *len = ctx.offset; out_free: ocfs2_free(&inode_buf); if (!(*len)) { ocfs2_free(buf); *buf = NULL; } if (retval) return retval; return ctx.errcode; } errcode_t ocfs2_file_read(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset, uint32_t *got) { ocfs2_filesys *fs = ci->ci_fs; errcode_t ret = 0; char *ptr = (char *) buf; uint32_t wanted_blocks; uint64_t contig_blocks; uint64_t v_blkno; uint64_t p_blkno; uint32_t tmp; uint64_t num_blocks; uint16_t extent_flags; if (ci->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL) return ocfs2_inline_data_read(ci->ci_inode, buf, count, offset, got); /* o_direct requires aligned io */ tmp = fs->fs_blocksize - 1; if ((count & tmp) || (offset & (uint64_t)tmp) || ((unsigned long)ptr & tmp)) return OCFS2_ET_INVALID_ARGUMENT; wanted_blocks = count >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; v_blkno = offset >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; *got = 0; num_blocks = (ci->ci_inode->i_size + fs->fs_blocksize - 1) >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; if (v_blkno >= num_blocks) return 0; if (v_blkno + wanted_blocks > num_blocks) wanted_blocks = (uint32_t) (num_blocks - v_blkno); while(wanted_blocks) { ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, &contig_blocks, &extent_flags); if (ret) return ret; if (contig_blocks > wanted_blocks) contig_blocks = wanted_blocks; if (!p_blkno || extent_flags & OCFS2_EXT_UNWRITTEN) { /* * we meet with a hole or an unwritten extent, * so just empty the content. */ memset(ptr, 0, contig_blocks * fs->fs_blocksize); } else { ret = ocfs2_read_blocks(fs, p_blkno, contig_blocks, ptr); if (ret) return ret; } *got += (contig_blocks << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits); wanted_blocks -= contig_blocks; if (wanted_blocks) { ptr += (contig_blocks << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits); v_blkno += (uint64_t)contig_blocks; } else { if (*got + offset > ci->ci_inode->i_size) *got = (uint32_t) (ci->ci_inode->i_size - offset); /* break */ } } return ret; } /* * Emtpy the blocks on the disk. */ static errcode_t empty_blocks(ocfs2_filesys *fs, uint64_t start_blk, uint64_t num_blocks) { errcode_t ret; char *buf = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; memset(buf, 0, fs->fs_blocksize); while (num_blocks) { ret = io_write_block(fs->fs_io, start_blk, 1, buf); if (ret) goto bail; num_blocks--; start_blk++; } bail: if (buf) ocfs2_free(&buf); return ret; } static errcode_t ocfs2_inline_data_write(struct ocfs2_dinode *di, void *buf, uint32_t count, uint64_t offset) { struct ocfs2_inline_data *id; uint8_t *p; if (!(di->i_dyn_features & OCFS2_INLINE_DATA_FL)) return OCFS2_ET_INVALID_ARGUMENT; id = &(di->id2.i_data); if (offset + count > id->id_count) return OCFS2_ET_NO_SPACE; p = (__u8 *) &(id->id_data); p += offset; memcpy(p, buf, count); return 0; } static errcode_t ocfs2_file_block_write(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset, uint32_t *wrote) { ocfs2_filesys *fs = ci->ci_fs; errcode_t ret = 0; char *ptr = (char *) buf; uint32_t wanted_blocks; uint64_t contig_blocks; uint64_t v_blkno; uint64_t p_blkno, p_start, p_end; uint64_t begin_blocks = 0, end_blocks = 0; uint32_t tmp; uint64_t num_blocks; int bs_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; uint32_t n_clusters, cluster_begin, cluster_end; uint64_t bpc = fs->fs_clustersize/fs->fs_blocksize; int insert = 0; uint16_t extent_flags = 0; /* o_direct requires aligned io */ tmp = fs->fs_blocksize - 1; if ((count & tmp) || (offset & (uint64_t)tmp) || ((unsigned long)ptr & tmp)) return OCFS2_ET_INVALID_ARGUMENT; wanted_blocks = count >> bs_bits; v_blkno = offset >> bs_bits; *wrote = 0; num_blocks = (ci->ci_inode->i_size + fs->fs_blocksize - 1) >> bs_bits; if (v_blkno >= num_blocks) return 0; if (v_blkno + wanted_blocks > num_blocks) wanted_blocks = (uint32_t) (num_blocks - v_blkno); if (ocfs2_refcount_tree(OCFS2_RAW_SB(fs->fs_super)) && (ci->ci_inode->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)) { cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno); cluster_end = ocfs2_blocks_to_clusters(fs, v_blkno + wanted_blocks - 1); n_clusters = cluster_end - cluster_begin + 1; ret = ocfs2_refcount_cow(ci, cluster_begin, n_clusters, UINT_MAX); if (ret) return ret; } while(wanted_blocks) { ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, &contig_blocks, &extent_flags); if (ret) return ret; if (contig_blocks > wanted_blocks) contig_blocks = wanted_blocks; begin_blocks = 0; end_blocks = 0; p_end = 0; if (!p_blkno) { /* * We meet with a hole here, so we allocate clusters * and empty the both ends in case. * * We will postpone the extent insertion after we * successfully write the extent block, so that and * problems happens in block writing would not affect * the file. */ cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno); cluster_end = ocfs2_blocks_to_clusters(fs, v_blkno + contig_blocks -1); n_clusters = cluster_end - cluster_begin + 1; ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_start, &n_clusters); if (ret || n_clusters == 0) return ret; begin_blocks = v_blkno & (bpc - 1); p_blkno = p_start + begin_blocks; contig_blocks = n_clusters * bpc - begin_blocks; if (contig_blocks > wanted_blocks) { end_blocks = contig_blocks - wanted_blocks; contig_blocks = wanted_blocks; p_end = p_blkno + wanted_blocks; } insert = 1; } else if (extent_flags & OCFS2_EXT_UNWRITTEN) { begin_blocks = v_blkno & (bpc - 1); p_start = p_blkno - begin_blocks; p_end = p_blkno + wanted_blocks; end_blocks = (p_end & (bpc - 1)) ? bpc - (p_end & (bpc - 1 )) : 0; } if (begin_blocks) { /* * The user don't write the first blocks, * so we have to empty them. */ ret = empty_blocks(fs, p_start, begin_blocks); if (ret) return ret; } if (end_blocks) { /* * we don't need to write that many blocks, * so empty the blocks at the bottom. */ ret = empty_blocks(fs, p_end, end_blocks); if (ret) return ret; } ret = io_write_block(fs->fs_io, p_blkno, contig_blocks, ptr); if (ret) return ret; if (insert) { ret = ocfs2_cached_inode_insert_extent(ci, ocfs2_blocks_to_clusters(fs,v_blkno), p_start, n_clusters, 0); if (ret) { /* * XXX: We don't wan't to overwrite the error * from insert_extent(). But we probably need * to BE LOUDLY UPSET. */ ocfs2_free_clusters(fs, n_clusters, p_start); return ret; } /* save up what we have done. */ ret = ocfs2_write_cached_inode(fs, ci); if (ret) return ret; ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, NULL, NULL); /* now we shouldn't find a hole. */ if (!p_blkno || p_blkno != p_start + begin_blocks) ret = OCFS2_ET_INTERNAL_FAILURE; if (ret) return ret; insert = 0; } else if (extent_flags & OCFS2_EXT_UNWRITTEN) { cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno); cluster_end = ocfs2_blocks_to_clusters(fs, v_blkno + contig_blocks -1); n_clusters = cluster_end - cluster_begin + 1; ret = ocfs2_mark_extent_written(fs, ci->ci_inode, cluster_begin, n_clusters, p_blkno & ~(bpc - 1)); if (ret) return ret; /* * We don't cache in the library right now, so any * work done in mark_extent_written won't be reflected * in our now stale copy. So refresh it. */ ret = ocfs2_refresh_cached_inode(fs, ci); if (ret) return ret; } *wrote += (contig_blocks << bs_bits); wanted_blocks -= contig_blocks; if (wanted_blocks) { ptr += (contig_blocks << bs_bits); v_blkno += (uint64_t)contig_blocks; } else { if (*wrote + offset > ci->ci_inode->i_size) *wrote = (uint32_t) (ci->ci_inode->i_size - offset); /* break */ } } return ret; } static inline int ocfs2_size_fits_inline_data(struct ocfs2_dinode *di, uint64_t new_size) { if (new_size <= di->id2.i_data.id_count) return 1; return 0; } static void ocfs2_expand_last_dirent(char *start, uint16_t old_size, uint16_t new_size) { struct ocfs2_dir_entry *de; struct ocfs2_dir_entry *prev_de; char *de_buf, *limit; uint16_t bytes = new_size - old_size; limit = start + old_size; de_buf = start; de = (struct ocfs2_dir_entry *)de_buf; do { prev_de = de; de_buf += de->rec_len; de = (struct ocfs2_dir_entry *)de_buf; } while (de_buf < limit); prev_de->rec_len += bytes; } errcode_t ocfs2_convert_inline_data_to_extents(ocfs2_cached_inode *ci) { errcode_t ret; uint32_t bytes, n_clusters; uint64_t p_start; char *inline_data = NULL; struct ocfs2_dinode *di = ci->ci_inode; ocfs2_filesys *fs = ci->ci_fs; uint64_t bpc = fs->fs_clustersize/fs->fs_blocksize; unsigned int new_size; if (di->i_size) { ret = ocfs2_malloc_block(fs->fs_io, &inline_data); if (ret) goto out; ret = ocfs2_inline_data_read(di, inline_data, fs->fs_blocksize, 0, &bytes); if (ret) goto out; } ocfs2_dinode_new_extent_list(fs, di); di->i_dyn_features &= ~OCFS2_INLINE_DATA_FL; ret = ocfs2_new_clusters(fs, 1, 1, &p_start, &n_clusters); if (ret || n_clusters == 0) goto out; ret = empty_blocks(fs, p_start, bpc); if (ret) goto out; if (di->i_size) { if (S_ISDIR(di->i_mode)) { if (ocfs2_supports_dir_trailer(fs)) new_size = ocfs2_dir_trailer_blk_off(fs); else new_size = fs->fs_blocksize; ocfs2_expand_last_dirent(inline_data, di->i_size, new_size); if (ocfs2_supports_dir_trailer(fs)) ocfs2_init_dir_trailer(fs, di, p_start, inline_data); di->i_size = fs->fs_blocksize; ret = ocfs2_write_dir_block(fs, di, p_start, inline_data); } else ret = io_write_block(fs->fs_io, p_start, 1, inline_data); if (ret) goto out; } ret = ocfs2_cached_inode_insert_extent(ci, 0, p_start, n_clusters, 0); if (ret) goto out; ret = ocfs2_write_cached_inode(fs, ci); out: if (inline_data) ocfs2_free(&inline_data); return ret; } static errcode_t ocfs2_try_to_write_inline_data(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset) { int ret; uint64_t end = offset + count; ocfs2_filesys *fs = ci->ci_fs; struct ocfs2_dinode *di = ci->ci_inode; /* Handle inodes which already have inline data 1st. */ if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { if (ocfs2_size_fits_inline_data(ci->ci_inode, end)) goto do_inline_write; /* * The write won't fit - we have to give this inode an * inline extent list now. */ ret = ocfs2_convert_inline_data_to_extents(ci); if (!ret) ret = OCFS2_ET_CANNOT_INLINE_DATA; goto out; } if (di->i_clusters > 0 || end > ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di)) return OCFS2_ET_CANNOT_INLINE_DATA; ocfs2_set_inode_data_inline(fs, ci->ci_inode); ci->ci_inode->i_dyn_features |= OCFS2_INLINE_DATA_FL; do_inline_write: ret = ocfs2_inline_data_write(di, buf, count, offset); if (ret) goto out; ret = ocfs2_write_cached_inode(fs, ci); out: return ret; } errcode_t ocfs2_file_write(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset, uint32_t *wrote) { errcode_t ret; ocfs2_filesys *fs = ci->ci_fs; if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super))) { ret = ocfs2_try_to_write_inline_data(ci, buf, count, offset); if (!ret || ret != OCFS2_ET_CANNOT_INLINE_DATA) goto out; } ret = ocfs2_file_block_write(ci, buf, count, offset, wrote); out: return ret; } /* * FIXME: port the reset of e2fsprogs/lib/ext2fs/fileio.c */ #ifdef DEBUG_EXE #include #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: debug_fileio [-i ] \n"); } static void dump_filebuf(const char *buf, int len) { int rc, offset; offset = 0; while (offset < len) { rc = write(STDOUT_FILENO, buf + offset, len - offset); if (rc < 0) { fprintf(stderr, "Write error: %s\n", strerror(errno)); return; } else if (rc) { offset += rc; } else { fprintf(stderr, "Wha? Unexpected EOF\n"); return; } } return; } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno, result_blkno; int c, len; char *filename, *lookup_path, *buf; char *filebuf; char *p; char lookup_name[256]; ocfs2_filesys *fs; blkno = 0; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; optind++; if (optind >= argc) { fprintf(stdout, "Missing path to lookup\n"); print_usage(); return 1; } lookup_path = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } if (!blkno) blkno = OCFS2_RAW_SB(fs->fs_super)->s_root_blkno; for (p = lookup_path; *p == '/'; p++); lookup_path = p; for (p = lookup_path; ; p++) { if (*p && *p != '/') continue; memcpy(lookup_name, lookup_path, p - lookup_path); lookup_name[p - lookup_path] = '\0'; ret = ocfs2_lookup(fs, blkno, lookup_name, strlen(lookup_name), NULL, &result_blkno); if (ret) { com_err(argv[0], ret, "while looking up \"%s\" in inode %"PRIu64 " on \"%s\"\n", lookup_name, blkno, filename); goto out_free; } blkno = result_blkno; for (; *p == '/'; p++); lookup_path = p; if (!*p) break; } if (ocfs2_check_directory(fs, blkno) != OCFS2_ET_NO_DIRECTORY) { com_err(argv[0], ret, "\"%s\" is not a file", filename); goto out_free; } ret = ocfs2_read_whole_file(fs, blkno, &filebuf, &len); if (ret) { com_err(argv[0], ret, "while reading file \"%s\" -- read %d bytes", filename, len); goto out_free_filebuf; } if (!len) fprintf(stderr, "boo!\n"); dump_filebuf(filebuf, len); out_free_filebuf: if (len) ocfs2_free(&filebuf); out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/freefs.c0000644000176100017610000000260411115551036014077 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * freefs.c * * Free an OCFS2 filesystem. Part of the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/freefs.c * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/ocfs2.h" void ocfs2_freefs(ocfs2_filesys *fs) { if (!fs) abort(); if (fs->fs_orig_super) ocfs2_free(&fs->fs_orig_super); if (fs->fs_super) ocfs2_free(&fs->fs_super); if (fs->fs_devname) ocfs2_free(&fs->fs_devname); if (fs->fs_io) io_close(fs->fs_io); ocfs2_free(&fs); } ./ocfs2-tools-1.6.4/libocfs2/expanddir.c0000644000176100017610000001550611500500544014604 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * expanddir.c * * Expands an OCFS2 directory. For the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/expanddir.c * Copyright (C) 1993, 1999 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #if HAVE_UNISTD_H #include #endif #include "ocfs2/ocfs2.h" /* * ocfs2_expand_dir() * */ errcode_t ocfs2_expand_dir(ocfs2_filesys *fs, uint64_t dir) { errcode_t ret = 0; ocfs2_cached_inode *cinode = NULL; uint64_t used_blks; uint64_t totl_blks; uint64_t new_blk; uint64_t contig; char *buf = NULL; struct ocfs2_dir_entry *de; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; /* ensure it is a dir */ ret = ocfs2_check_directory(fs, dir); if (ret) goto bail; /* read inode */ ret = ocfs2_read_cached_inode(fs, dir, &cinode); if (ret) goto bail; if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) && cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL) { ret = ocfs2_convert_inline_data_to_extents(cinode); if ((ret == 0) && ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super))) { ret = ocfs2_dx_dir_build(fs, dir); } goto bail; } /* This relies on the fact that i_size of a directory is a * multiple of blocksize */ used_blks = cinode->ci_inode->i_size >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; totl_blks = ocfs2_clusters_to_blocks(fs, cinode->ci_inode->i_clusters); if (used_blks >= totl_blks) { ocfs2_free_cached_inode(fs, cinode); cinode = NULL; /* extend the directory */ ret = ocfs2_extend_allocation(fs, dir, 1); if (ret) goto bail; ret = ocfs2_read_cached_inode(fs, dir, &cinode); if (ret) goto bail; } /* get the next free block */ ret = ocfs2_extent_map_get_blocks(cinode, used_blks, 1, &new_blk, &contig, NULL); if (ret) goto bail; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; memset(buf, 0, fs->fs_blocksize); de = (struct ocfs2_dir_entry *)buf; if (ocfs2_dir_has_trailer(fs, cinode->ci_inode)) { de->rec_len = ocfs2_dir_trailer_blk_off(fs); ocfs2_init_dir_trailer(fs, cinode->ci_inode, new_blk, buf); } else de->rec_len = fs->fs_blocksize; /* write new dir block */ ret = ocfs2_write_dir_block(fs, cinode->ci_inode, new_blk, buf); if (ret) goto bail; /* increase the size */ cinode->ci_inode->i_size += fs->fs_blocksize; /* update the size of the inode */ ret = ocfs2_write_cached_inode(fs, cinode); if (ret) goto bail; bail: if (buf) ocfs2_free(&buf); if (cinode) ocfs2_free_cached_inode(fs, cinode); return ret; } static void ocfs2_fill_initial_dirents(uint64_t dir, uint64_t parent, char *start, uint16_t size) { struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start; de->inode = dir; de->name_len = 1; de->rec_len = OCFS2_DIR_REC_LEN(de->name_len); de->name[0] = '.'; de->file_type = OCFS2_FT_DIR; de = (struct ocfs2_dir_entry *) ((char *)de + de->rec_len); de->inode = parent; de->rec_len = size - OCFS2_DIR_REC_LEN(1); de->name_len = 2; strcpy(de->name, ".."); de->file_type = OCFS2_FT_DIR; } errcode_t ocfs2_init_dir(ocfs2_filesys *fs, uint64_t dir, uint64_t parent_dir) { errcode_t ret = 0; ocfs2_cached_inode *cinode = NULL; struct ocfs2_dinode *parent; uint16_t size; uint64_t blkno, contig; char *buf = NULL, *data = NULL; struct ocfs2_inline_data *inline_data; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; /* ensure it is a dir */ ret = ocfs2_check_directory(fs, dir); if (ret) goto bail; /* read inode */ ret = ocfs2_read_cached_inode(fs, dir, &cinode); if (ret) goto bail; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super))) { if (!(cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL)) return OCFS2_ET_DIR_CORRUPTED; inline_data = &cinode->ci_inode->id2.i_data; data = (char *)inline_data->id_data; size = inline_data->id_count; } else { if (cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL) return OCFS2_ET_DIR_CORRUPTED; ret = ocfs2_expand_dir(fs, dir); if (ret) goto bail; ocfs2_free_cached_inode(fs, cinode); cinode = NULL; ret = ocfs2_read_cached_inode(fs, dir, &cinode); if (ret) goto bail; ret = ocfs2_extent_map_get_blocks(cinode, 0, 1, &blkno, &contig, NULL); if (ret) goto bail; data = buf; size = fs->fs_blocksize; if (ocfs2_supports_dir_trailer(fs)) size = ocfs2_dir_trailer_blk_off(fs); } /* set '..' and '.' in dir. */ ocfs2_fill_initial_dirents(dir, parent_dir, data, size); /* And set the trailer if necessary */ if (!(cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL) && ocfs2_supports_dir_trailer(fs)) ocfs2_init_dir_trailer(fs, cinode->ci_inode, blkno, data); if (!(cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL)) { ret = ocfs2_write_dir_block(fs, cinode->ci_inode, blkno, buf); if (ret) goto bail; } /* * Only build indexed tree if the directory is initiated as non-inline. * Otherwise, the indexed tree will be build when convert the inlined * directory to extent in ocfs2_expand_dir() */ if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)) && !(cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL)) { ret = ocfs2_dx_dir_build(fs, dir); if (ret) goto bail; /* * Re-read the 'cached inode' as ocfs2_dx_dir_build() * may have written out changes which won't be * reflected in our copy. */ ret = ocfs2_read_cached_inode(fs, dir, &cinode); if (ret) goto bail; } /* set link count of the parent */ ret = ocfs2_read_inode(fs, parent_dir, buf); if (ret) goto bail; parent = (struct ocfs2_dinode *)buf; parent->i_links_count++; ret = ocfs2_write_inode(fs, parent_dir, buf); if (ret) goto bail; /* increase the size */ cinode->ci_inode->i_size = size; /* update the inode */ ret = ocfs2_write_cached_inode(fs, cinode); bail: if (buf) ocfs2_free(&buf); if (cinode) ocfs2_free_cached_inode(fs, cinode); return ret; } ./ocfs2-tools-1.6.4/libocfs2/extend_file.c0000644000176100017610000002063611453177334015132 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extend_file.c * * Adds extents to an OCFS2 inode. For the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #if HAVE_UNISTD_H #include #endif #include #include #include #include "ocfs2/ocfs2.h" #include "extent_tree.h" /* * Insert an extent into an inode btree. */ errcode_t ocfs2_inode_insert_extent(ocfs2_filesys *fs, uint64_t ino, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag) { errcode_t ret; ocfs2_cached_inode *ci = NULL; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto bail; ret = ocfs2_cached_inode_insert_extent(ci, cpos, c_blkno, clusters, flag); if (ret) goto bail; ret = ocfs2_write_cached_inode(fs, ci); bail: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } errcode_t ocfs2_cached_inode_insert_extent(ocfs2_cached_inode *ci, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag) { struct ocfs2_extent_tree et; ocfs2_init_dinode_extent_tree(&et, ci->ci_fs, (char *)ci->ci_inode, ci->ci_inode->i_blkno); return ocfs2_tree_insert_extent(ci->ci_fs, &et, cpos, c_blkno, clusters, flag); } errcode_t ocfs2_cached_inode_extend_allocation(ocfs2_cached_inode *ci, uint32_t new_clusters) { errcode_t ret = 0; uint32_t n_clusters = 0, cpos; uint64_t blkno, file_size; ocfs2_filesys *fs = ci->ci_fs; file_size = ci->ci_inode->i_size; cpos = (file_size + fs->fs_clustersize - 1) / fs->fs_clustersize; while (new_clusters) { n_clusters = 1; ret = ocfs2_new_clusters(fs, 1, new_clusters, &blkno, &n_clusters); if (ret) break; ret = ocfs2_cached_inode_insert_extent(ci, cpos, blkno, n_clusters, 0); if (ret) { /* XXX: We don't wan't to overwrite the error * from insert_extent(). But we probably need * to BE LOUDLY UPSET. */ ocfs2_free_clusters(fs, n_clusters, blkno); break; } new_clusters -= n_clusters; cpos += n_clusters; } return ret; } errcode_t ocfs2_extend_allocation(ocfs2_filesys *fs, uint64_t ino, uint32_t new_clusters) { errcode_t ret; ocfs2_cached_inode *ci = NULL; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto bail; ret = ocfs2_cached_inode_extend_allocation(ci, new_clusters); if (ret) goto bail; ret = ocfs2_write_cached_inode(fs, ci); bail: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } errcode_t ocfs2_extend_file(ocfs2_filesys *fs, uint64_t ino, uint64_t new_size) { errcode_t ret = 0; char *buf = NULL; struct ocfs2_dinode* di = NULL; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, ino, buf); if (ret) goto out_free_buf; di = (struct ocfs2_dinode *)buf; if (di->i_size >= new_size) { ret = EINVAL; goto out_free_buf; } di->i_size = new_size; ret = ocfs2_write_inode(fs, ino, buf); out_free_buf: if (buf) ocfs2_free(&buf); return ret; } errcode_t ocfs2_allocate_unwritten_extents(ocfs2_filesys *fs, uint64_t ino, uint64_t offset, uint64_t len) { errcode_t ret = 0; uint32_t n_clusters = 0, cpos; uint64_t p_blkno, v_blkno, v_end, contig_blocks, wanted_blocks; ocfs2_cached_inode *ci = NULL; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if (!ocfs2_writes_unwritten_extents(OCFS2_RAW_SB(fs->fs_super))) return OCFS2_ET_RO_UNSUPP_FEATURE; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto out; if (!(ci->ci_inode->i_flags & OCFS2_VALID_FL)) return OCFS2_ET_INODE_NOT_VALID; if (ci->ci_inode->i_flags & OCFS2_SYSTEM_FL) return OCFS2_ET_INVALID_ARGUMENT; if (!S_ISREG(ci->ci_inode->i_mode)) return OCFS2_ET_INVALID_ARGUMENT; v_blkno = offset / fs->fs_blocksize; v_end = (offset + len - 1) / fs->fs_blocksize; while (v_blkno <= v_end) { ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, &contig_blocks, NULL); if (p_blkno) { v_blkno += contig_blocks; continue; } /* * There is a hole, so we have to allocate the space and * insert the unwritten extents. */ wanted_blocks = ocfs2_min(contig_blocks, v_end - v_blkno + 1); n_clusters = ocfs2_clusters_in_blocks(fs, wanted_blocks); ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_blkno, &n_clusters); if (ret || n_clusters == 0) break; cpos = ocfs2_blocks_to_clusters(fs, v_blkno); ret = ocfs2_cached_inode_insert_extent(ci, cpos, p_blkno, n_clusters, OCFS2_EXT_UNWRITTEN); if (ret) { /* * XXX: We don't wan't to overwrite the error * from insert_extent(). But we probably need * to BE LOUDLY UPSET. */ ocfs2_free_clusters(fs, n_clusters, p_blkno); goto out; } /* save up what we have done. */ ret = ocfs2_write_cached_inode(fs, ci); if (ret) goto out; v_blkno = ocfs2_clusters_to_blocks(fs, cpos + n_clusters); } if (ci->ci_inode->i_size <= offset + len) { ci->ci_inode->i_size = offset + len; ret = ocfs2_write_cached_inode(fs, ci); } out: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } /* * Mark the already-existing extent at cpos as written for len clusters. * * If the existing extent is larger than the request, initiate a * split. An attempt will be made at merging with adjacent extents. * */ int ocfs2_mark_extent_written(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t cpos, uint32_t len, uint64_t p_blkno) { struct ocfs2_extent_tree et; if (!ocfs2_writes_unwritten_extents(OCFS2_RAW_SB(fs->fs_super))) return OCFS2_ET_UNSUPP_FEATURE; ocfs2_init_dinode_extent_tree(&et, fs, (char *)di, di->i_blkno); return ocfs2_change_extent_flag(fs, &et, cpos, len, p_blkno, 0, OCFS2_EXT_UNWRITTEN); } #ifdef DEBUG_EXE #include #include #include #include static void print_usage(void) { fprintf(stdout, "debug_extend_file -i -c \n"); } static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; char *filename; ocfs2_filesys *fs; uint64_t ino = 0; uint32_t new_clusters = 0; int c; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:c:")) != EOF) { switch (c) { case 'i': ino = read_number(optarg); if (ino <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; case 'c': new_clusters = read_number(optarg); if (!new_clusters) { fprintf(stderr, "Invalid cluster count: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (!ino) { fprintf(stderr, "You must specify an inode block\n"); print_usage(); return 1; } if (!new_clusters) { fprintf(stderr, "You must specify how many clusters to extend\n"); print_usage(); return 1; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RW, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_extend_allocation(fs, ino, new_clusters); if (ret) { com_err(argv[0], ret, "while extending inode %"PRIu64, ino); } ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return !!ret; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/extents.c0000644000176100017610000005636111515637016014337 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extents.c * * Iterate over the extents in an inode. Part of the OCFS2 userspace * library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/block.c * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" static void ocfs2_swap_extent_list_primary(struct ocfs2_extent_list *el) { el->l_tree_depth = bswap_16(el->l_tree_depth); el->l_count = bswap_16(el->l_count); el->l_next_free_rec = bswap_16(el->l_next_free_rec); } static void ocfs2_swap_extent_list_secondary(ocfs2_filesys *fs, void *obj, struct ocfs2_extent_list *el) { uint16_t i; for(i = 0; i < el->l_next_free_rec; i++) { struct ocfs2_extent_rec *rec = &el->l_recs[i]; if (ocfs2_swap_barrier(fs, obj, rec, sizeof(struct ocfs2_extent_rec))) break; rec->e_cpos = bswap_32(rec->e_cpos); if (el->l_tree_depth) rec->e_int_clusters = bswap_32(rec->e_int_clusters); else rec->e_leaf_clusters = bswap_16(rec->e_leaf_clusters); rec->e_blkno = bswap_64(rec->e_blkno); } } void ocfs2_swap_extent_list_from_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_extent_list *el) { if (cpu_is_little_endian) return; ocfs2_swap_extent_list_secondary(fs, obj, el); ocfs2_swap_extent_list_primary(el); } void ocfs2_swap_extent_list_to_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_extent_list *el) { if (cpu_is_little_endian) return; ocfs2_swap_extent_list_primary(el); ocfs2_swap_extent_list_secondary(fs, obj, el); } static void ocfs2_swap_extent_block_header(struct ocfs2_extent_block *eb) { eb->h_suballoc_slot = bswap_16(eb->h_suballoc_slot); eb->h_suballoc_bit = bswap_16(eb->h_suballoc_bit); eb->h_fs_generation = bswap_32(eb->h_fs_generation); eb->h_blkno = bswap_64(eb->h_blkno); eb->h_next_leaf_blk = bswap_64(eb->h_next_leaf_blk); eb->h_suballoc_loc = bswap_64(eb->h_suballoc_loc); } void ocfs2_swap_extent_block_from_cpu(ocfs2_filesys *fs, struct ocfs2_extent_block *eb) { if (cpu_is_little_endian) return; ocfs2_swap_extent_block_header(eb); ocfs2_swap_extent_list_from_cpu(fs, eb, &eb->h_list); } void ocfs2_swap_extent_block_to_cpu(ocfs2_filesys *fs, struct ocfs2_extent_block *eb) { if (cpu_is_little_endian) return; ocfs2_swap_extent_block_header(eb); ocfs2_swap_extent_list_to_cpu(fs, eb, &eb->h_list); } errcode_t ocfs2_read_extent_block_nocheck(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf) { errcode_t ret; char *blk; struct ocfs2_extent_block *eb; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; eb = (struct ocfs2_extent_block *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &eb->h_check); if (ret) goto out; if (memcmp(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE, strlen(OCFS2_EXTENT_BLOCK_SIGNATURE))) { ret = OCFS2_ET_BAD_EXTENT_BLOCK_MAGIC; goto out; } memcpy(eb_buf, blk, fs->fs_blocksize); eb = (struct ocfs2_extent_block *) eb_buf; ocfs2_swap_extent_block_to_cpu(fs, eb); out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_read_extent_block(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf) { errcode_t ret; struct ocfs2_extent_block *eb = (struct ocfs2_extent_block *)eb_buf; ret = ocfs2_read_extent_block_nocheck(fs, blkno, eb_buf); if (ret == 0 && eb->h_list.l_next_free_rec > eb->h_list.l_count) ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; return ret; } errcode_t ocfs2_write_extent_block(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf) { errcode_t ret; char *blk; struct ocfs2_extent_block *eb; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; memcpy(blk, eb_buf, fs->fs_blocksize); eb = (struct ocfs2_extent_block *) blk; ocfs2_swap_extent_block_from_cpu(fs, eb); ocfs2_compute_meta_ecc(fs, blk, &eb->h_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; } struct extent_context { ocfs2_filesys *fs; int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data); uint32_t ccount; int flags; errcode_t errcode; char **eb_bufs; void *priv_data; uint64_t last_eb_blkno; uint64_t last_eb_cpos; }; static int extent_iterate_eb(struct ocfs2_extent_rec *eb_rec, int tree_depth, uint64_t ref_blkno, int ref_recno, struct extent_context *ctxt); static int update_leaf_rec(struct extent_context *ctxt, struct ocfs2_extent_rec *before, struct ocfs2_extent_rec *current) { return 0; } static int update_eb_rec(struct extent_context *ctxt, struct ocfs2_extent_rec *before, struct ocfs2_extent_rec *current) { return 0; } static int extent_iterate_el(struct ocfs2_extent_list *el, uint64_t ref_blkno, struct extent_context *ctxt) { struct ocfs2_extent_rec before; int iret = 0; int i; for (i = 0; i < el->l_next_free_rec; i++) { /* XXX we could put some constraints on how the rec * is allowed to change.. */ before = el->l_recs[i]; if (el->l_tree_depth) { iret |= extent_iterate_eb(&el->l_recs[i], el->l_tree_depth, ref_blkno, i, ctxt); if (iret & OCFS2_EXTENT_CHANGED) iret |= update_eb_rec(ctxt, &before, &el->l_recs[i]); if (el->l_recs[i].e_int_clusters && (el->l_recs[i].e_cpos >= ctxt->last_eb_cpos)) { /* * Only set last_eb_blkno if current extent * list point to leaf blocks. */ if (el->l_tree_depth == 1) ctxt->last_eb_blkno = el->l_recs[i].e_blkno; ctxt->last_eb_cpos = el->l_recs[i].e_cpos; } } else { /* * For a sparse file, we may find an empty record * in the left most record. Just skip it. */ if (!i && !el->l_recs[i].e_leaf_clusters) continue; iret |= (*ctxt->func)(ctxt->fs, &el->l_recs[i], el->l_tree_depth, ctxt->ccount, ref_blkno, i, ctxt->priv_data); if (iret & OCFS2_EXTENT_CHANGED) iret |= update_leaf_rec(ctxt, &before, &el->l_recs[i]); ctxt->ccount += ocfs2_rec_clusters(el->l_tree_depth, &el->l_recs[i]); } if (iret & (OCFS2_EXTENT_ABORT | OCFS2_EXTENT_ERROR)) break; } if (iret & OCFS2_EXTENT_CHANGED) { for (i = 0; i < el->l_count; i++) { if (ocfs2_rec_clusters(el->l_tree_depth, &el->l_recs[i])) continue; el->l_next_free_rec = i; break; } } return iret; } static int extent_iterate_eb(struct ocfs2_extent_rec *eb_rec, int ref_tree_depth, uint64_t ref_blkno, int ref_recno, struct extent_context *ctxt) { int iret = 0, changed = 0, flags; int tree_depth = ref_tree_depth - 1; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; if (!(ctxt->flags & OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE) && !(ctxt->flags & OCFS2_EXTENT_FLAG_DATA_ONLY)) iret = (*ctxt->func)(ctxt->fs, eb_rec, ref_tree_depth, ctxt->ccount, ref_blkno, ref_recno, ctxt->priv_data); if (!eb_rec->e_blkno || (iret & OCFS2_EXTENT_ABORT)) goto out; if ((eb_rec->e_blkno < OCFS2_SUPER_BLOCK_BLKNO) || (eb_rec->e_blkno > ctxt->fs->fs_blocks)) { ctxt->errcode = OCFS2_ET_BAD_BLKNO; iret |= OCFS2_EXTENT_ERROR; goto out; } ctxt->errcode = ocfs2_read_extent_block(ctxt->fs, eb_rec->e_blkno, ctxt->eb_bufs[tree_depth]); if (ctxt->errcode) { iret |= OCFS2_EXTENT_ERROR; goto out; } eb = (struct ocfs2_extent_block *)ctxt->eb_bufs[tree_depth]; el = &eb->h_list; if ((el->l_tree_depth != tree_depth) || (eb->h_blkno != eb_rec->e_blkno)) { ctxt->errcode = OCFS2_ET_CORRUPT_EXTENT_BLOCK; iret |= OCFS2_EXTENT_ERROR; goto out; } flags = extent_iterate_el(el, eb_rec->e_blkno, ctxt); changed |= flags; if (flags & (OCFS2_EXTENT_ABORT | OCFS2_EXTENT_ERROR)) iret |= flags & (OCFS2_EXTENT_ABORT | OCFS2_EXTENT_ERROR); /* * If the list was changed, we should write the changes to disk. * Note: * For a sparse file, we may have an empty extent block. */ if (changed & OCFS2_EXTENT_CHANGED) { ctxt->errcode = ocfs2_write_extent_block(ctxt->fs, eb_rec->e_blkno, ctxt->eb_bufs[tree_depth]); if (ctxt->errcode) { iret |= OCFS2_EXTENT_ERROR; goto out; } } if ((ctxt->flags & OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE) && !(ctxt->flags & OCFS2_EXTENT_FLAG_DATA_ONLY) && !(iret & (OCFS2_EXTENT_ABORT|OCFS2_EXTENT_ERROR))) iret = (*ctxt->func)(ctxt->fs, eb_rec, ref_tree_depth, ctxt->ccount, ref_blkno, ref_recno, ctxt->priv_data); out: return iret; } errcode_t ocfs2_extent_iterate_xattr(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t last_eb_blk, int flags, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data, int *changed) { int i; int iret = 0; errcode_t ret; struct extent_context ctxt; if (el->l_tree_depth) { ret = ocfs2_malloc0(sizeof(char *) * el->l_tree_depth, &ctxt.eb_bufs); if (ret) goto out; ret = ocfs2_malloc0(fs->fs_blocksize * el->l_tree_depth, &ctxt.eb_bufs[0]); if (ret) goto out_eb_bufs; for (i = 1; i < el->l_tree_depth; i++) { ctxt.eb_bufs[i] = ctxt.eb_bufs[0] + i * fs->fs_blocksize; } } else ctxt.eb_bufs = NULL; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ctxt.flags = flags; ctxt.ccount = 0; ctxt.last_eb_blkno = 0; ctxt.last_eb_cpos = 0; ret = 0; iret |= extent_iterate_el(el, 0, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_ABORT) goto out_abort; if (last_eb_blk != ctxt.last_eb_blkno) { last_eb_blk = ctxt.last_eb_blkno; iret |= OCFS2_EXTENT_CHANGED; } out_abort: if (!ret && (iret & OCFS2_EXTENT_CHANGED)) *changed = 1; out_eb_bufs: if (ctxt.eb_bufs) { if (ctxt.eb_bufs[0]) ocfs2_free(&ctxt.eb_bufs[0]); ocfs2_free(&ctxt.eb_bufs); } out: return ret; } errcode_t ocfs2_extent_iterate_inode(ocfs2_filesys *fs, struct ocfs2_dinode *inode, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data) { int i; int iret = 0; struct ocfs2_extent_list *el; errcode_t ret; struct extent_context ctxt; ret = OCFS2_ET_INODE_NOT_VALID; if (!(inode->i_flags & OCFS2_VALID_FL)) goto out; ret = OCFS2_ET_INODE_CANNOT_BE_ITERATED; if (inode->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_CHAIN_FL)) goto out; if (inode->i_dyn_features & OCFS2_INLINE_DATA_FL) goto out; el = &inode->id2.i_list; if (el->l_tree_depth) { ret = ocfs2_malloc0(sizeof(char *) * el->l_tree_depth, &ctxt.eb_bufs); if (ret) goto out; if (block_buf) { ctxt.eb_bufs[0] = block_buf; } else { ret = ocfs2_malloc0(fs->fs_blocksize * el->l_tree_depth, &ctxt.eb_bufs[0]); if (ret) goto out_eb_bufs; } for (i = 1; i < el->l_tree_depth; i++) { ctxt.eb_bufs[i] = ctxt.eb_bufs[0] + i * fs->fs_blocksize; } } else ctxt.eb_bufs = NULL; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ctxt.flags = flags; ctxt.ccount = 0; ctxt.last_eb_blkno = 0; ctxt.last_eb_cpos = 0; ret = 0; iret |= extent_iterate_el(el, 0, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_ABORT) goto out_abort; /* we can only trust ctxt.last_eb_blkno if we walked the whole tree */ if (inode->i_last_eb_blk != ctxt.last_eb_blkno) { inode->i_last_eb_blk = ctxt.last_eb_blkno; iret |= OCFS2_EXTENT_CHANGED; } out_abort: if (!ret && (iret & OCFS2_EXTENT_CHANGED)) ret = ocfs2_write_inode(fs, inode->i_blkno, (char *)inode); out_eb_bufs: if (ctxt.eb_bufs) { if (!block_buf && ctxt.eb_bufs[0]) ocfs2_free(&ctxt.eb_bufs[0]); ocfs2_free(&ctxt.eb_bufs); } out: return ret; } errcode_t ocfs2_extent_iterate_dx_root(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data) { int i; int iret = 0; struct ocfs2_extent_list *el; errcode_t ret; struct extent_context ctxt; if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) return OCFS2_ET_INODE_CANNOT_BE_ITERATED; el = &dx_root->dr_list; if (el->l_tree_depth) { ret = ocfs2_malloc0(sizeof(char *) * el->l_tree_depth, &ctxt.eb_bufs); if (ret) goto out; if (block_buf) { ctxt.eb_bufs[0] = block_buf; } else { ret = ocfs2_malloc0(fs->fs_blocksize * el->l_tree_depth, &ctxt.eb_bufs[0]); if (ret) goto out_eb_bufs; } for (i = 1; i < el->l_tree_depth; i++) { ctxt.eb_bufs[i] = ctxt.eb_bufs[0] + i * fs->fs_blocksize; } } else ctxt.eb_bufs = NULL; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ctxt.flags = flags; ctxt.ccount = 0; ctxt.last_eb_blkno = 0; ctxt.last_eb_cpos = 0; ret = 0; iret |= extent_iterate_el(el, 0, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_ABORT) goto out_abort; /* we can only trust ctxt.last_eb_blkno if we walked the whole tree */ if (dx_root->dr_last_eb_blk != ctxt.last_eb_blkno) { dx_root->dr_last_eb_blk = ctxt.last_eb_blkno; iret |= OCFS2_EXTENT_CHANGED; } out_abort: #if 0 /* * This block needs to be fixed up for write support. */ if (!ret && (iret & OCFS2_EXTENT_CHANGED)) ret = ocfs2_write_inode(fs, inode->i_blkno, (char *)inode); #endif out_eb_bufs: if (ctxt.eb_bufs) { if (!block_buf && ctxt.eb_bufs[0]) ocfs2_free(&ctxt.eb_bufs[0]); ocfs2_free(&ctxt.eb_bufs); } out: return ret; } errcode_t ocfs2_extent_iterate(ocfs2_filesys *fs, uint64_t blkno, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data) { char *buf = NULL; struct ocfs2_dinode *inode; errcode_t ret; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto out_buf; inode = (struct ocfs2_dinode *)buf; ret = ocfs2_extent_iterate_inode(fs, inode, flags, block_buf, func, priv_data); out_buf: if (buf) ocfs2_free(&buf); return ret; } struct block_context { int (*func)(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data); int flags; struct ocfs2_dinode *inode; errcode_t errcode; void *priv_data; }; static int block_iterate_func(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { struct block_context *ctxt = priv_data; uint64_t blkno, bcount, bend; int iret = 0; bcount = ocfs2_clusters_to_blocks(fs, rec->e_cpos); bend = bcount + ocfs2_clusters_to_blocks(fs, ocfs2_rec_clusters(tree_depth, rec)); for (blkno = rec->e_blkno; bcount < bend; blkno++, bcount++) { if (((bcount * fs->fs_blocksize) >= ctxt->inode->i_size) && !(ctxt->flags & OCFS2_BLOCK_FLAG_APPEND)) break; iret = (*ctxt->func)(fs, blkno, bcount, rec->e_flags, ctxt->priv_data); if (iret & OCFS2_BLOCK_ABORT) break; } return iret; } errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs, struct ocfs2_dinode *inode, int flags, int (*func)(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data), void *priv_data) { errcode_t ret; struct block_context ctxt; ctxt.inode = inode; ctxt.flags = flags; ctxt.func = func; ctxt.errcode = 0; ctxt.priv_data = priv_data; ret = ocfs2_extent_iterate_inode(fs, inode, OCFS2_EXTENT_FLAG_DATA_ONLY, NULL, block_iterate_func, &ctxt); return ret; } errcode_t ocfs2_block_iterate(ocfs2_filesys *fs, uint64_t blkno, int flags, int (*func)(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data), void *priv_data) { struct ocfs2_dinode *inode; errcode_t ret; char *buf; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto out_buf; inode = (struct ocfs2_dinode *)buf; ret = ocfs2_block_iterate_inode(fs, inode, flags, func, priv_data); out_buf: ocfs2_free(&buf); return ret; } #ifdef DEBUG_EXE #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: extents -i [-e] [-b] \n"); } struct walk_it { struct ocfs2_dinode *di; }; static int walk_extents_func(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { struct walk_it *wi = priv_data; int pad_amount = wi->di->id2.i_list.l_tree_depth - tree_depth; int i; if (!ccount && !pad_amount) fprintf(stdout, "EXTENTS:\n"); fprintf(stdout, "0x%08"PRIX64":%02u ", ref_blkno, ref_recno); for (i = 0; i < pad_amount; i++) fprintf(stdout, " "); fprintf(stdout, "(%08"PRIu32", %08"PRIu32", %08"PRIu64") |" " + %08"PRIu32" = %08"PRIu32" / %08"PRIu32"\n", rec->e_cpos, ocfs2_rec_clusters(tree_depth, rec), rec->e_blkno, ccount, ccount + ocfs2_rec_clusters(tree_depth, rec), wi->di->i_clusters); if (!tree_depth && ((ccount + ocfs2_rec_clusters(tree_depth, rec)) == wi->di->i_clusters)) fprintf(stdout, "TOTAL: %u\n", wi->di->i_clusters); return 0; } struct walk_block { struct ocfs2_dinode *di; uint64_t last_block; uint64_t run_first_blkno; uint64_t run_first_bcount; uint64_t run_prev_blkno; }; static int walk_blocks_func(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data) { struct walk_block *wb = priv_data; /* Very first block */ if (!wb->run_prev_blkno) { wb->run_prev_blkno = blkno; wb->run_first_blkno = blkno; fprintf(stdout, "BLOCKS:\n"); } else if ((wb->run_prev_blkno + 1) != blkno) { if (wb->run_first_bcount) fprintf(stdout, ", "); if ((wb->run_first_bcount + 1) == bcount) { fprintf(stdout, "(%"PRIu64"):%"PRIu64"", wb->run_first_bcount, wb->run_first_blkno); } else { fprintf(stdout, "(%"PRIu64"-%"PRIu64"):%"PRIu64"-%"PRIu64"", wb->run_first_bcount, bcount - 1, wb->run_first_blkno, wb->run_prev_blkno); } wb->run_first_bcount = bcount; wb->run_first_blkno = blkno; } if ((bcount + 1) == wb->last_block) { if (wb->run_first_bcount) fprintf(stdout, ", "); if ((wb->run_prev_blkno + 1) != blkno) { fprintf(stdout, "(%"PRIu64"):%"PRIu64"\n", bcount, blkno); } else { fprintf(stdout, "(%"PRIu64"-%"PRIu64"):%"PRIu64"-%"PRIu64"\n", wb->run_first_bcount, bcount, wb->run_first_blkno, blkno); } fprintf(stdout, "TOTAL: %"PRIu64"\n", bcount + 1); } wb->run_prev_blkno = blkno; return 0; } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno; int c; int walk_blocks = 0, walk_extents = 0; char *filename, *buf, *eb_buf = NULL; ocfs2_filesys *fs; struct ocfs2_dinode *di; struct walk_it wi; struct walk_block wb; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "bei:")) != EOF) { switch (c) { case 'b': walk_blocks = 1; break; case 'e': walk_extents = 1; break; case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; if (!(walk_blocks + walk_extents)) { fprintf(stderr, "No operation specified\n"); print_usage(); return 1; } ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } ret = ocfs2_read_inode(fs, blkno, buf); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_free; } di = (struct ocfs2_dinode *)buf; fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\" has depth %"PRId16"\n", blkno, filename, di->id2.i_list.l_tree_depth); if (walk_extents) { if (di->id2.i_list.l_tree_depth) { ret = ocfs2_malloc_blocks(fs->fs_io, di->id2.i_list.l_tree_depth, &eb_buf); if (ret) { com_err(argv[0], ret, "while allocating eb buffer"); goto out_free; } } wi.di = di; ret = ocfs2_extent_iterate(fs, blkno, 0, eb_buf, walk_extents_func, &wi); if (ret) { com_err(argv[0], ret, "while walking extents"); goto out_free; } } if (walk_blocks) { wb.di = di; wb.run_first_blkno = wb.run_first_bcount = wb.run_prev_blkno = 0; wb.last_block = (wb.di->i_size + (fs->fs_blocksize - 1)) / fs->fs_blocksize; ret = ocfs2_block_iterate(fs, blkno, 0, walk_blocks_func, &wb); if (ret) { com_err(argv[0], ret, "while walking blocks"); goto out_free; } } out_free: if (eb_buf) ocfs2_free(&eb_buf); ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/extent_map.c0000644000176100017610000002503711453177334015010 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extent_map.c * * In-memory extent map for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include "ocfs2/ocfs2.h" #include "extent_map.h" /* * Return the 1st index within el which contains an extent start * larger than v_cluster. */ static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el, uint32_t v_cluster) { int i; struct ocfs2_extent_rec *rec; for(i = 0; i < el->l_next_free_rec; i++) { rec = &el->l_recs[i]; if (v_cluster < rec->e_cpos) break; } return i; } /* * Figure out the size of a hole which starts at v_cluster within the given * extent list. * * If there is no more allocation past v_cluster, we return the maximum * cluster size minus v_cluster. * * If we have in-inode extents, then el points to the dinode list and * eb_buf is NULL. Otherwise, eb_buf should point to the extent block * containing el. */ static int ocfs2_figure_hole_clusters(ocfs2_cached_inode *cinode, struct ocfs2_extent_list *el, char *eb_buf, uint32_t v_cluster, uint32_t *num_clusters) { int ret, i; char *next_eb_buf = NULL; struct ocfs2_extent_block *eb, *next_eb; i = ocfs2_search_for_hole_index(el, v_cluster); if (i == el->l_next_free_rec && eb_buf) { eb = (struct ocfs2_extent_block *)eb_buf; /* * Check the next leaf for any extents. */ if (eb->h_next_leaf_blk == 0) goto no_more_extents; ret = ocfs2_malloc_block(cinode->ci_fs->fs_io, &next_eb_buf); if (ret) goto out; ret = ocfs2_read_extent_block(cinode->ci_fs, eb->h_next_leaf_blk, next_eb_buf); if (ret) goto out; next_eb = (struct ocfs2_extent_block *)next_eb_buf; el = &next_eb->h_list; i = ocfs2_search_for_hole_index(el, v_cluster); if (i > 0) { if ((i > 1) || ocfs2_rec_clusters(el->l_tree_depth, &el->l_recs[0])) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } } no_more_extents: if (i == el->l_next_free_rec) { /* * We're at the end of our existing allocation. Just * return the maximum number of clusters we could * possibly allocate. */ *num_clusters = UINT32_MAX - v_cluster; } else *num_clusters = el->l_recs[i].e_cpos - v_cluster; ret = 0; out: if (next_eb_buf) ocfs2_free(&next_eb_buf); return ret; } errcode_t ocfs2_get_clusters(ocfs2_cached_inode *cinode, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags) { int i; uint16_t flags = 0; errcode_t ret = 0; ocfs2_filesys *fs = cinode->ci_fs; struct ocfs2_dinode *di; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *rec; char *eb_buf = NULL; uint32_t coff; di = cinode->ci_inode; el = &di->id2.i_list; if (el->l_tree_depth) { ret = ocfs2_find_leaf(fs, di, v_cluster, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *) eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } i = ocfs2_search_extent_list(el, v_cluster); if (i == -1) { /* * A hole was found. Return some canned values that * callers can key on. If asked for, num_clusters will * be populated with the size of the hole. */ *p_cluster = 0; if (num_clusters) { ret = ocfs2_figure_hole_clusters(cinode, el, eb_buf, v_cluster, num_clusters); if (ret) goto out; } } else { rec = &el->l_recs[i]; assert(v_cluster >= rec->e_cpos); if (!rec->e_blkno) { ret = OCFS2_ET_BAD_BLKNO; goto out; } coff = v_cluster - rec->e_cpos; *p_cluster = ocfs2_blocks_to_clusters(fs, rec->e_blkno); *p_cluster = *p_cluster + coff; if (num_clusters) *num_clusters = ocfs2_rec_clusters(el->l_tree_depth, rec) - coff; flags = rec->e_flags; } if (extent_flags) *extent_flags = flags; out: if (eb_buf) ocfs2_free(&eb_buf); return ret; } errcode_t ocfs2_xattr_get_clusters(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t el_blkno, char *el_blk, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags) { int i; errcode_t ret = 0; struct ocfs2_extent_block *eb; struct ocfs2_extent_rec *rec; char *eb_buf = NULL; uint32_t coff; if (el->l_tree_depth) { ret = ocfs2_tree_find_leaf(fs, el, el_blkno, el_blk, v_cluster, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } i = ocfs2_search_extent_list(el, v_cluster); if (i == -1) { ret = -1; goto out; } else { rec = &el->l_recs[i]; assert(v_cluster >= rec->e_cpos); if (!rec->e_blkno) { ret = OCFS2_ET_BAD_BLKNO; goto out; } coff = v_cluster - rec->e_cpos; *p_cluster = ocfs2_blocks_to_clusters(fs, rec->e_blkno); *p_cluster = *p_cluster + coff; if (num_clusters) *num_clusters = ocfs2_rec_clusters(el->l_tree_depth, rec) - coff; if (extent_flags) *extent_flags = rec->e_flags; } out: if (eb_buf) ocfs2_free(&eb_buf); return ret; } errcode_t ocfs2_extent_map_get_blocks(ocfs2_cached_inode *cinode, uint64_t v_blkno, int count, uint64_t *p_blkno, uint64_t *ret_count, uint16_t *extent_flags) { errcode_t ret; int bpc; uint32_t cpos, num_clusters = -1, p_cluster = -1; uint64_t boff = 0; ocfs2_filesys *fs = cinode->ci_fs; bpc = ocfs2_clusters_to_blocks(fs, 1); cpos = ocfs2_blocks_to_clusters(fs, v_blkno); ret = ocfs2_get_clusters(cinode, cpos, &p_cluster, &num_clusters, extent_flags); if (ret) goto out; /* * p_cluster == 0 indicates a hole. */ if (p_cluster) { boff = ocfs2_clusters_to_blocks(fs, p_cluster); boff += (v_blkno & (uint64_t)(bpc - 1)); } *p_blkno = boff; if (ret_count) { *ret_count = ocfs2_clusters_to_blocks(fs, num_clusters); *ret_count -= v_blkno & (uint64_t)(bpc - 1); } out: return ret; } errcode_t ocfs2_get_last_cluster_offset(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t *v_cluster) { errcode_t ret = 0; char *buf = NULL; struct ocfs2_extent_list *el = NULL; struct ocfs2_extent_rec *er = NULL; el = &di->id2.i_list; *v_cluster = 0; if (!el->l_next_free_rec) return 0; if (el->l_tree_depth) { ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_read_extent_block(fs, di->i_last_eb_blk, buf); if (ret) goto bail; el = &((struct ocfs2_extent_block *)buf)->h_list; if (!el->l_next_free_rec || (el->l_next_free_rec == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto bail; } } er = &el->l_recs[el->l_next_free_rec - 1]; *v_cluster = er->e_cpos + er->e_leaf_clusters - 1; bail: if (buf) ocfs2_free(&buf); return ret; } #ifdef DEBUG_EXE #include #include #include enum debug_op { OP_NONE = 0, OP_LOOKUP_BLOCK, }; static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static int read_b_numbers(const char *num, uint64_t *blkno, int *count) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr) return 1; if (*ptr != ':') return 1; *blkno = val; ptr++; val = strtoull(ptr, &ptr, 0); if (!ptr || *ptr) return 1; if (val > INT_MAX) return 1; *count = (int)val; return 0; } static void print_usage(void) { fprintf(stderr, "Usage: extent_map -i -b : \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno, contig, blkoff = 0; uint16_t ext_flags; int count = 0; int c, op = 0; char *filename; ocfs2_filesys *fs; ocfs2_cached_inode *cinode; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:b:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; case 'b': if (op) { fprintf(stderr, "Cannot specify more than one operation\n"); print_usage(); return 1; } if (read_b_numbers(optarg, &blkoff, &count)) { fprintf(stderr, "Invalid block range: %s\n", optarg); print_usage(); return 1; } op = OP_LOOKUP_BLOCK; break; default: print_usage(); return 1; break; } } if (!op) { fprintf(stderr, "Missing operation\n"); print_usage(); return 1; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_read_cached_inode(fs, blkno, &cinode); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_close; } fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\" has depth %"PRId16"\n", blkno, filename, cinode->ci_inode->id2.i_list.l_tree_depth); ret = ocfs2_extent_map_get_blocks(cinode, blkoff, count, &blkno, &contig, &ext_flags); if (ret) { com_err(argv[0], ret, "looking up block range %"PRIu64":%d", blkoff, count); goto out_free; } fprintf(stdout, "Lookup of block range %"PRIu64":%d returned %"PRIu64":%"PRIu64"\n", blkoff, count, blkno, contig); out_free: ocfs2_free_cached_inode(fs, cinode); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/getsectsize.c0000664000176100017610000000337311170734140015164 00000000000000/* * getsectsize.c --- get the sector size of a device. * * Copyright (C) 1995, 1995 Theodore Ts'o. * Copyright (C) 2003 VMware, Inc. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public * License. * %End-Header% */ /* Modified for OCFS2 by Manish Singh */ #define HAVE_UNISTD_H 1 #define HAVE_ERRNO_H 1 #define HAVE_LINUX_FD_H 1 #define HAVE_OPEN64 1 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE #include #if HAVE_UNISTD_H #include #endif #if HAVE_ERRNO_H #include #endif #include #ifdef HAVE_LINUX_FD_H #include #include #endif #if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET) #define BLKSSZGET _IO(0x12,104)/* get block device sector size */ #endif #include "ocfs2/ocfs2.h" /* * Returns the number of blocks in a partition */ errcode_t ocfs2_get_device_sectsize(const char *file, int *sectsize) { int fd; int ret; #ifdef HAVE_OPEN64 fd = open64(file, O_RDONLY); #else fd = open(file, O_RDONLY); #endif if (fd < 0) { if (errno == ENOENT) return OCFS2_ET_NAMED_DEVICE_NOT_FOUND; else return OCFS2_ET_IO; } ret = OCFS2_ET_CANNOT_DETERMINE_SECTOR_SIZE; #ifdef BLKSSZGET if (ioctl(fd, BLKSSZGET, sectsize) >= 0) ret = 0; #endif close(fd); return ret; } #ifdef DEBUG_EXE int main(int argc, char **argv) { int sectsize; int retval; if (argc < 2) { fprintf(stderr, "Usage: %s device\n", argv[0]); exit(1); } retval = ocfs2_get_device_sectsize(argv[1], §size); if (retval) { com_err(argv[0], retval, "while calling ocfs2_get_device_sectsize"); exit(1); } printf("Device %s has a hardware sector size of %d.\n", argv[1], sectsize); exit(0); } #endif ./ocfs2-tools-1.6.4/libocfs2/getsize.c0000644000176100017610000001522511115551036014302 00000000000000/* * getsize.c --- get the size of a partition. * * Copyright (C) 1995, 1995 Theodore Ts'o. * Copyright (C) 2003 VMware, Inc. * * Windows version of ext2fs_get_device_size by Chris Li, VMware. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public * License. * %End-Header% */ /* Modified for OCFS2 by Manish Singh */ #define HAVE_UNISTD_H 1 #define HAVE_ERRNO_H 1 #define HAVE_LINUX_FD_H 1 #define HAVE_OPEN64 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_FSTAT64 1 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE #include #if HAVE_UNISTD_H #include #endif #if HAVE_ERRNO_H #include #endif #include #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_LINUX_FD_H #include #endif #ifdef HAVE_SYS_DISKLABEL_H #include #endif #ifdef HAVE_SYS_DISK_H #ifdef HAVE_SYS_QUEUE_H #include /* for LIST_HEAD */ #endif #include #endif #ifdef __linux__ #include #endif #if HAVE_SYS_STAT_H #include #endif #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) #define BLKGETSIZE _IO(0x12,96) /* return device size */ #endif #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ #endif #ifdef APPLE_DARWIN #define BLKGETSIZE DKIOCGETBLOCKCOUNT32 #endif /* APPLE_DARWIN */ #include "ocfs2/ocfs2.h" #if defined(__CYGWIN__) || defined (WIN32) #include "windows.h" #include "winioctl.h" #if (_WIN32_WINNT >= 0x0500) #define HAVE_GET_FILE_SIZE_EX 1 #endif errcode_t ocfs2_get_device_size(const char *file, int blocksize, uint64_t *retblocks) { HANDLE dev; PARTITION_INFORMATION pi; DISK_GEOMETRY gi; DWORD retbytes; #ifdef HAVE_GET_FILE_SIZE_EX LARGE_INTEGER filesize; #else DWORD filesize; #endif /* HAVE_GET_FILE_SIZE_EX */ dev = CreateFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (dev == INVALID_HANDLE_VALUE) return EBADF; if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, &pi, sizeof(PARTITION_INFORMATION), &pi, sizeof(PARTITION_INFORMATION), &retbytes, NULL)) { *retblocks = pi.PartitionLength.QuadPart / blocksize; } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, &gi, sizeof(DISK_GEOMETRY), &gi, sizeof(DISK_GEOMETRY), &retbytes, NULL)) { *retblocks = gi.BytesPerSector * gi.SectorsPerTrack * gi.TracksPerCylinder * gi.Cylinders.QuadPart / blocksize; #ifdef HAVE_GET_FILE_SIZE_EX } else if (GetFileSizeEx(dev, &filesize)) { *retblocks = filesize.QuadPart / blocksize; } #else } else { filesize = GetFileSize(dev, NULL); if (INVALID_FILE_SIZE != filesize) { *retblocks = filesize / blocksize; } } #endif /* HAVE_GET_FILE_SIZE_EX */ CloseHandle(dev); return 0; } #else static int valid_offset (int fd, off64_t offset) { char ch; if (lseek64 (fd, offset, 0) < 0) return 0; if (read (fd, &ch, 1) < 1) return 0; return 1; } /* * Returns the number of blocks in a partition */ errcode_t ocfs2_get_device_size(const char *file, int blocksize, uint64_t *retblocks) { int fd, rc = 0; int valid_blkgetsize64 = 1; #ifdef __linux__ struct utsname ut; #endif unsigned long long size64; unsigned long size; off64_t high, low; #ifdef FDGETPRM struct floppy_struct this_floppy; #endif #ifdef HAVE_SYS_DISKLABEL_H int part; struct disklabel lab; struct partition *pp; char ch; #endif /* HAVE_SYS_DISKLABEL_H */ #ifdef HAVE_OPEN64 fd = open64(file, O_RDONLY); #else fd = open(file, O_RDONLY); #endif if (fd < 0) return errno; #ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */ if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) { if ((sizeof(*retblocks) < sizeof(unsigned long long)) && ((size64 / (blocksize / 512)) > 0xFFFFFFFF)) return EFBIG; *retblocks = size64 / (blocksize / 512); goto out; } #endif #ifdef BLKGETSIZE64 #ifdef __linux__ if ((uname(&ut) == 0) && ((ut.release[0] == '2') && (ut.release[1] == '.') && (ut.release[2] < '6') && (ut.release[3] == '.'))) valid_blkgetsize64 = 0; #endif if (valid_blkgetsize64 && ioctl(fd, BLKGETSIZE64, &size64) >= 0) { if ((sizeof(*retblocks) < sizeof(unsigned long long)) && ((size64 / blocksize) > 0xFFFFFFFF)) { rc = EFBIG; goto out; } *retblocks = size64 / blocksize; goto out; } #endif #ifdef BLKGETSIZE if (ioctl(fd, BLKGETSIZE, &size) >= 0) { *retblocks = size / (blocksize / 512); goto out; } #endif #ifdef FDGETPRM if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { *retblocks = this_floppy.size / (blocksize / 512); goto out; } #endif #ifdef HAVE_SYS_DISKLABEL_H #if defined(DIOCGMEDIASIZE) { off_t ms; u_int bs; if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) { *retblocks = ms / blocksize; goto out; } } #elif defined(DIOCGDINFO) /* old disklabel interface */ part = strlen(file) - 1; if (part >= 0) { ch = file[part]; if (isdigit(ch)) part = 0; else if (ch >= 'a' && ch <= 'h') part = ch - 'a'; else part = -1; } if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { pp = &lab.d_partitions[part]; if (pp->p_size) { *retblocks = pp->p_size / (blocksize / 512); goto out; } } #endif /* defined(DIOCG*) */ #endif /* HAVE_SYS_DISKLABEL_H */ { #ifdef HAVE_FSTAT64 struct stat64 st; if (fstat64(fd, &st) == 0) #else struct stat st; if (fstat(fd, &st) == 0) #endif if (S_ISREG(st.st_mode)) { *retblocks = st.st_size / blocksize; goto out; } } /* * OK, we couldn't figure it out by using a specialized ioctl, * which is generally the best way. So do binary search to * find the size of the partition. */ low = 0; for (high = 1024; valid_offset (fd, high); high *= 2) low = high; while (low < high - 1) { const off64_t mid = (low + high) / 2; if (valid_offset (fd, mid)) low = mid; else high = mid; } valid_offset (fd, 0); size64 = low + 1; if ((sizeof(*retblocks) < sizeof(unsigned long long)) && ((size64 / blocksize) > 0xFFFFFFFF)) return EFBIG; *retblocks = size64 / blocksize; out: close(fd); return rc; } #endif /* WIN32 */ #ifdef DEBUG_EXE #include int main(int argc, char **argv) { uint64_t blocks; int retval; if (argc < 2) { fprintf(stderr, "Usage: %s device\n", argv[0]); exit(1); } retval = ocfs2_get_device_size(argv[1], 1024, &blocks); if (retval) { com_err(argv[0], retval, "while calling ocfs2_get_device_size"); exit(1); } printf("Device %s has %"PRIu64" 1k blocks.\n", argv[1], blocks); exit(0); } #endif ./ocfs2-tools-1.6.4/libocfs2/heartbeat.c0000644000176100017610000000572111341355440014571 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * heartbeat.c * * Interface the OCFS2 userspace library to the userspace heartbeat * functionality * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Mark Fasheh, Zach Brown */ #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" void ocfs2_swap_disk_heartbeat_block(struct o2hb_disk_heartbeat_block *hb) { if (cpu_is_little_endian) return; hb->hb_seq = bswap_64(hb->hb_seq); hb->hb_cksum = bswap_32(hb->hb_cksum); hb->hb_generation = bswap_64(hb->hb_generation); } errcode_t ocfs2_fill_heartbeat_desc(ocfs2_filesys *fs, struct o2cb_region_desc *desc) { errcode_t ret; char *filename; char *buf = NULL; uint64_t blkno, blocks, start_block; uint32_t block_bits, cluster_bits; int sectsize, sectsize_bits; struct ocfs2_dinode *di; struct ocfs2_extent_rec *rec; ret = ocfs2_get_device_sectsize(fs->fs_devname, §size); if (ret) { if (ret == OCFS2_ET_CANNOT_DETERMINE_SECTOR_SIZE) sectsize = OCFS2_MIN_BLOCKSIZE; else goto leave; } sectsize_bits = ffs(sectsize) - 1; filename = ocfs2_system_inodes[HEARTBEAT_SYSTEM_INODE].si_name; ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, filename, strlen(filename), NULL, &blkno); if (ret) goto leave; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto leave; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto leave; di = (struct ocfs2_dinode *)buf; if (di->id2.i_list.l_tree_depth || di->id2.i_list.l_next_free_rec != 1) { ret = OCFS2_ET_BAD_HEARTBEAT_FILE; goto leave; } rec = &(di->id2.i_list.l_recs[0]); block_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; cluster_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; if (block_bits < sectsize_bits) { ret = OCFS2_ET_BLOCK_SIZE_TOO_SMALL_FOR_HARDWARE; goto leave; } blocks = ocfs2_rec_clusters(0, rec) << cluster_bits; blocks >>= block_bits; if (blocks > O2NM_MAX_NODES) blocks = O2NM_MAX_NODES; start_block = rec->e_blkno << block_bits; start_block >>= sectsize_bits; desc->r_name = fs->uuid_str; desc->r_device_name = fs->fs_devname; desc->r_block_bytes = sectsize; desc->r_start_block = start_block; desc->r_blocks = blocks; leave: if (buf) ocfs2_free(&buf); return ret; } ./ocfs2-tools-1.6.4/libocfs2/inode.c0000644000176100017610000003016711500500544013724 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * inode.c * * Inode operations for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/inode.c * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" errcode_t ocfs2_check_directory(ocfs2_filesys *fs, uint64_t dir) { struct ocfs2_dinode *inode; char *buf; errcode_t ret; if ((dir < OCFS2_SUPER_BLOCK_BLKNO) || (dir > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, dir, buf); if (ret) goto out_buf; inode = (struct ocfs2_dinode *)buf; if (!S_ISDIR(inode->i_mode)) ret = OCFS2_ET_NO_DIRECTORY; out_buf: ocfs2_free(&buf); return ret; } static void ocfs2_swap_inode_third(ocfs2_filesys *fs, struct ocfs2_dinode *di) { if (di->i_flags & OCFS2_CHAIN_FL) { struct ocfs2_chain_list *cl = &di->id2.i_chain; uint16_t i; for (i = 0; i < cl->cl_next_free_rec; i++) { struct ocfs2_chain_rec *rec = &cl->cl_recs[i]; if (ocfs2_swap_barrier(fs, di, rec, sizeof(struct ocfs2_chain_rec))) break; rec->c_free = bswap_32(rec->c_free); rec->c_total = bswap_32(rec->c_total); rec->c_blkno = bswap_64(rec->c_blkno); } } else if (di->i_flags & OCFS2_DEALLOC_FL) { struct ocfs2_truncate_log *tl = &di->id2.i_dealloc; uint16_t i; for(i = 0; i < tl->tl_count; i++) { struct ocfs2_truncate_rec *rec = &tl->tl_recs[i]; if (ocfs2_swap_barrier(fs, di, rec, sizeof(struct ocfs2_truncate_rec))) break; rec->t_start = bswap_32(rec->t_start); rec->t_clusters = bswap_32(rec->t_clusters); } } } static void ocfs2_swap_inode_second(struct ocfs2_dinode *di) { if (S_ISCHR(di->i_mode) || S_ISBLK(di->i_mode)) di->id1.dev1.i_rdev = bswap_64(di->id1.dev1.i_rdev); else if (di->i_flags & OCFS2_BITMAP_FL) { di->id1.bitmap1.i_used = bswap_32(di->id1.bitmap1.i_used); di->id1.bitmap1.i_total = bswap_32(di->id1.bitmap1.i_total); } else if (di->i_flags & OCFS2_JOURNAL_FL) { di->id1.journal1.ij_flags = bswap_32(di->id1.journal1.ij_flags); di->id1.journal1.ij_recovery_generation = bswap_32(di->id1.journal1.ij_recovery_generation); } /* we need to be careful to swap the union member that is in use. * first the ones that are explicitly marked with flags.. */ if (di->i_flags & OCFS2_SUPER_BLOCK_FL) { struct ocfs2_super_block *sb = &di->id2.i_super; sb->s_major_rev_level = bswap_16(sb->s_major_rev_level); sb->s_minor_rev_level = bswap_16(sb->s_minor_rev_level); sb->s_mnt_count = bswap_16(sb->s_mnt_count); sb->s_max_mnt_count = bswap_16(sb->s_max_mnt_count); sb->s_state = bswap_16(sb->s_state); sb->s_errors = bswap_16(sb->s_errors); sb->s_checkinterval = bswap_32(sb->s_checkinterval); sb->s_lastcheck = bswap_64(sb->s_lastcheck); sb->s_creator_os = bswap_32(sb->s_creator_os); sb->s_feature_compat = bswap_32(sb->s_feature_compat); sb->s_feature_ro_compat = bswap_32(sb->s_feature_ro_compat); sb->s_feature_incompat = bswap_32(sb->s_feature_incompat); sb->s_root_blkno = bswap_64(sb->s_root_blkno); sb->s_system_dir_blkno = bswap_64(sb->s_system_dir_blkno); sb->s_blocksize_bits = bswap_32(sb->s_blocksize_bits); sb->s_clustersize_bits = bswap_32(sb->s_clustersize_bits); sb->s_max_slots = bswap_16(sb->s_max_slots); sb->s_tunefs_flag = bswap_16(sb->s_tunefs_flag); sb->s_uuid_hash = bswap_32(sb->s_uuid_hash); sb->s_first_cluster_group = bswap_64(sb->s_first_cluster_group); sb->s_xattr_inline_size = bswap_16(sb->s_xattr_inline_size); sb->s_dx_seed[0] = bswap_32(sb->s_dx_seed[0]); sb->s_dx_seed[1] = bswap_32(sb->s_dx_seed[1]); sb->s_dx_seed[2] = bswap_32(sb->s_dx_seed[2]); } else if (di->i_flags & OCFS2_LOCAL_ALLOC_FL) { struct ocfs2_local_alloc *la = &di->id2.i_lab; la->la_bm_off = bswap_32(la->la_bm_off); la->la_size = bswap_16(la->la_size); } else if (di->i_flags & OCFS2_CHAIN_FL) { struct ocfs2_chain_list *cl = &di->id2.i_chain; cl->cl_cpg = bswap_16(cl->cl_cpg); cl->cl_bpc = bswap_16(cl->cl_bpc); cl->cl_count = bswap_16(cl->cl_count); cl->cl_next_free_rec = bswap_16(cl->cl_next_free_rec); } else if (di->i_flags & OCFS2_DEALLOC_FL) { struct ocfs2_truncate_log *tl = &di->id2.i_dealloc; tl->tl_count = bswap_16(tl->tl_count); tl->tl_used = bswap_16(tl->tl_used); } else if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { struct ocfs2_inline_data *id = &di->id2.i_data; id->id_count = bswap_16(id->id_count); } else if (di->i_dyn_features & OCFS2_INDEXED_DIR_FL) { di->i_dx_root = bswap_64(di->i_dx_root); } } static void ocfs2_swap_inode_first(struct ocfs2_dinode *di) { di->i_generation = bswap_32(di->i_generation); di->i_suballoc_slot = bswap_16(di->i_suballoc_slot); di->i_suballoc_bit = bswap_16(di->i_suballoc_bit); di->i_xattr_inline_size = bswap_16(di->i_xattr_inline_size); di->i_clusters = bswap_32(di->i_clusters); di->i_uid = bswap_32(di->i_uid); di->i_gid = bswap_32(di->i_gid); di->i_size = bswap_64(di->i_size); di->i_mode = bswap_16(di->i_mode); di->i_links_count = bswap_16(di->i_links_count); di->i_flags = bswap_32(di->i_flags); di->i_atime = bswap_64(di->i_atime); di->i_ctime = bswap_64(di->i_ctime); di->i_mtime = bswap_64(di->i_mtime); di->i_dtime = bswap_64(di->i_dtime); di->i_blkno = bswap_64(di->i_blkno); di->i_last_eb_blk = bswap_64(di->i_last_eb_blk); di->i_fs_generation = bswap_32(di->i_fs_generation); di->i_atime_nsec = bswap_32(di->i_atime_nsec); di->i_ctime_nsec = bswap_32(di->i_ctime_nsec); di->i_mtime_nsec = bswap_32(di->i_mtime_nsec); di->i_attr = bswap_32(di->i_attr); di->i_orphaned_slot = bswap_16(di->i_orphaned_slot); di->i_dyn_features = bswap_16(di->i_dyn_features); di->i_xattr_loc = bswap_64(di->i_xattr_loc); di->i_refcount_loc = bswap_64(di->i_refcount_loc); di->i_suballoc_loc = bswap_64(di->i_suballoc_loc); } static int has_extents(struct ocfs2_dinode *di) { /* inodes flagged with other stuff in id2 */ if (di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL)) return 0; /* i_flags doesn't indicate when id2 is a fast symlink */ if (S_ISLNK(di->i_mode) && di->i_size && di->i_clusters == 0) return 0; if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) return 0; return 1; } static inline void ocfs2_swap_inline_dir(ocfs2_filesys *fs, struct ocfs2_dinode *di, int to_cpu) { void *de_buf = di->id2.i_data.id_data; uint64_t bytes = di->id2.i_data.id_count; int max_inline = ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di); /* Just in case i_xattr_inline_size is garbage */ if (max_inline < 0) max_inline = 0; if (bytes > max_inline) bytes = max_inline; if (to_cpu) ocfs2_swap_dir_entries_to_cpu(de_buf, bytes); else ocfs2_swap_dir_entries_from_cpu(de_buf, bytes); } void ocfs2_swap_inode_from_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di) { if (cpu_is_little_endian) return; if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) { struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *) ((void *)di + fs->fs_blocksize - di->i_xattr_inline_size); ocfs2_swap_xattrs_from_cpu(fs, di, xh); } if (has_extents(di)) ocfs2_swap_extent_list_from_cpu(fs, di, &di->id2.i_list); if (di->i_dyn_features & OCFS2_INLINE_DATA_FL && S_ISDIR(di->i_mode)) ocfs2_swap_inline_dir(fs, di, 0); ocfs2_swap_inode_third(fs, di); ocfs2_swap_inode_second(di); ocfs2_swap_inode_first(di); } void ocfs2_swap_inode_to_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di) { if (cpu_is_little_endian) return; ocfs2_swap_inode_first(di); ocfs2_swap_inode_second(di); ocfs2_swap_inode_third(fs, di); if (di->i_dyn_features & OCFS2_INLINE_DATA_FL && S_ISDIR(di->i_mode)) ocfs2_swap_inline_dir(fs, di, 1); if (has_extents(di)) ocfs2_swap_extent_list_to_cpu(fs, di, &di->id2.i_list); if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) { struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *) ((void *)di + fs->fs_blocksize - di->i_xattr_inline_size); ocfs2_swap_xattrs_to_cpu(fs, di, xh); } } errcode_t ocfs2_read_inode(ocfs2_filesys *fs, uint64_t blkno, char *inode_buf) { errcode_t ret; char *blk; struct ocfs2_dinode *di; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; di = (struct ocfs2_dinode *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &di->i_check); if (ret) goto out; ret = OCFS2_ET_BAD_INODE_MAGIC; if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) goto out; memcpy(inode_buf, blk, fs->fs_blocksize); di = (struct ocfs2_dinode *) inode_buf; ocfs2_swap_inode_to_cpu(fs, di); ret = 0; out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_write_inode(ocfs2_filesys *fs, uint64_t blkno, char *inode_buf) { errcode_t ret; char *blk; struct ocfs2_dinode *di; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; memcpy(blk, inode_buf, fs->fs_blocksize); di = (struct ocfs2_dinode *)blk; ocfs2_swap_inode_from_cpu(fs, di); ocfs2_compute_meta_ecc(fs, blk, &di->i_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; } #ifdef DEBUG_EXE #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: inode \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno; char *filename, *buf; ocfs2_filesys *fs; struct ocfs2_dinode *di; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); if (argc < 2) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[1]; if (argc > 2) { blkno = read_number(argv[2]); if (blkno < OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid blockno: %"PRIu64"\n", blkno); print_usage(); return 1; } } ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } ret = ocfs2_read_inode(fs, blkno, buf); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_free; } di = (struct ocfs2_dinode *)buf; fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\"\n", blkno, filename); out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/inode_scan.c0000644000176100017610000002613711500500544014732 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * inode_scan.c * * Scan all inodes in an OCFS2 filesystem. For the OCFS2 userspace * library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/inode_scan.c * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include "ocfs2/ocfs2.h" #include "extent_map.h" struct _ocfs2_inode_scan { ocfs2_filesys *fs; int num_inode_alloc; int next_inode_file; ocfs2_cached_inode *cur_inode_alloc; ocfs2_cached_inode **inode_alloc; struct ocfs2_chain_rec *cur_rec; int next_rec; struct ocfs2_group_desc *cur_desc; unsigned int count; uint64_t cur_blkno; char *group_buffer; char *cur_block; int buffer_blocks; int blocks_in_buffer; unsigned int blocks_left; uint64_t b_offset; /* bit offset in the group bitmap. */ uint16_t cur_discontig_rec; /* Only valid in discontig group. */ }; /* * This function is called by fill_group_buffer when an alloc group has * been completely read. It must not be called from the last group. * ocfs2_get_next_inode() should have detected that condition. */ static errcode_t get_next_group(ocfs2_inode_scan *scan) { errcode_t ret; if (!scan->cur_desc) { if (scan->b_offset) abort(); ret = ocfs2_malloc_block(scan->fs->fs_io, &scan->cur_desc); if (ret) return ret; } if (scan->b_offset) scan->cur_blkno = scan->cur_desc->bg_next_group; /* * scan->cur_blkno better be nonzero, either set by * get_next_chain() or valid from bg_next_group */ if (!scan->cur_blkno) abort(); ret = ocfs2_read_group_desc(scan->fs, scan->cur_blkno, (char *)scan->cur_desc); if (ret) return (ret); if (scan->cur_desc->bg_blkno != scan->cur_blkno) return OCFS2_ET_CORRUPT_GROUP_DESC; /* Skip past group descriptor block */ scan->cur_blkno++; scan->count++; scan->blocks_left--; scan->b_offset = 1; scan->cur_discontig_rec = 0; return 0; } /* * This function is called by fill_group_buffer when an alloc chain * has been completely read. It must not be called when the current * inode alloc file has been read in its entirety. This condition * should have been detected by ocfs2_get_next_inode(). */ static errcode_t get_next_chain(ocfs2_inode_scan *scan) { struct ocfs2_dinode *di = scan->cur_inode_alloc->ci_inode; if (scan->next_rec == di->id2.i_chain.cl_next_free_rec) { if (!scan->next_rec) { /* * The only way we can get here with next_rec * == cl_next_free_rec == 0 is if * bitmap1.i_total was non-zero. But if i_total * was non-zero and we have no chains, we're * corrupt. */ return OCFS2_ET_CORRUPT_CHAIN; } else abort(); } scan->cur_rec = &di->id2.i_chain.cl_recs[scan->next_rec]; scan->next_rec++; scan->count = 0; scan->b_offset = 0; scan->cur_blkno = scan->cur_rec->c_blkno; return 0; } /* * Get the number of blocks we will read next. * In case of discontiguous group, we will set scan->cur_blkno in case * we need to read next extent record. */ static int get_next_read_blocks(ocfs2_inode_scan *scan) { int num_blocks, rec_end; struct ocfs2_extent_rec *rec; if (!scan->cur_desc) abort(); if (!scan->cur_desc->bg_list.l_next_free_rec) { /* Contiguous group. Just set num_blocks. */ num_blocks = scan->cur_desc->bg_bits - scan->b_offset; goto out; } /* We shouldn't arrived here. */ if (scan->cur_discontig_rec == scan->cur_desc->bg_list.l_next_free_rec) abort(); rec = &scan->cur_desc->bg_list.l_recs[scan->cur_discontig_rec]; rec_end = ocfs2_clusters_to_blocks(scan->fs, rec->e_cpos + rec->e_leaf_clusters); if (rec_end < scan->b_offset) abort(); else if (rec_end > scan->b_offset) { /* OK, we have more blocks to read in this rec. */ num_blocks = rec_end - scan->b_offset; } else { /* We have to read the next rec now. */ scan->cur_discontig_rec++; rec = &scan->cur_desc->bg_list.l_recs[scan->cur_discontig_rec]; scan->cur_blkno = rec->e_blkno; num_blocks = ocfs2_clusters_to_blocks(scan->fs, rec->e_leaf_clusters); } out: if (num_blocks > scan->buffer_blocks) num_blocks = scan->buffer_blocks; return num_blocks; } /* * This function is called by ocfs2_get_next_inode when it needs * to read in more clusters from the current inode alloc file. It * must not be called when the current inode alloc file has been read * in its entirety. This condition is detected by * ocfs2_get_next_inode(). */ static errcode_t fill_group_buffer(ocfs2_inode_scan *scan) { errcode_t ret; int num_blocks; if (scan->cur_rec && (scan->count > scan->cur_rec->c_total)) abort(); if (scan->cur_rec && (scan->b_offset > scan->cur_desc->bg_bits)) abort(); if (!scan->cur_rec || (scan->count == scan->cur_rec->c_total)) { ret = get_next_chain(scan); if (ret) return ret; } if (!scan->b_offset || (scan->b_offset == scan->cur_desc->bg_bits)) { ret = get_next_group(scan); if (ret) return ret; } num_blocks = get_next_read_blocks(scan); ret = ocfs2_read_blocks(scan->fs, scan->cur_blkno, num_blocks, scan->group_buffer); if (ret) return ret; scan->b_offset += num_blocks; scan->blocks_in_buffer = num_blocks; scan->cur_block = scan->group_buffer; return 0; } /* This function sets the starting points for a given cached inode */ static int get_next_inode_alloc(ocfs2_inode_scan *scan) { ocfs2_cached_inode *cinode = scan->cur_inode_alloc; if (cinode && scan->blocks_left) abort(); do { if (scan->next_inode_file == scan->num_inode_alloc) return 1; /* Out of files */ scan->cur_inode_alloc = scan->inode_alloc[scan->next_inode_file]; cinode = scan->cur_inode_alloc; scan->next_inode_file++; } while (!cinode->ci_inode->id1.bitmap1.i_total); scan->next_rec = 0; scan->count = 0; scan->cur_blkno = 0; scan->cur_rec = NULL; scan->blocks_left = cinode->ci_inode->id1.bitmap1.i_total; return 0; } errcode_t ocfs2_get_next_inode(ocfs2_inode_scan *scan, uint64_t *blkno, char *inode) { errcode_t ret; if (!scan->blocks_left) { if (scan->blocks_in_buffer) abort(); if (get_next_inode_alloc(scan)) { *blkno = 0; return 0; } } if (!scan->blocks_in_buffer) { ret = fill_group_buffer(scan); if (ret) return ret; } /* the caller swap after verifying the inode's signature */ memcpy(inode, scan->cur_block, scan->fs->fs_blocksize); scan->cur_block += scan->fs->fs_blocksize; scan->blocks_in_buffer--; scan->blocks_left--; *blkno = scan->cur_blkno; scan->cur_blkno++; scan->count++; return 0; } errcode_t ocfs2_open_inode_scan(ocfs2_filesys *fs, ocfs2_inode_scan **ret_scan) { ocfs2_inode_scan *scan; uint64_t blkno; errcode_t ret; int i, slot_num; ret = ocfs2_malloc0(sizeof(struct _ocfs2_inode_scan), &scan); if (ret) return ret; scan->fs = fs; /* One inode alloc per slot, one global inode alloc */ scan->num_inode_alloc = OCFS2_RAW_SB(fs->fs_super)->s_max_slots + 1; ret = ocfs2_malloc0(sizeof(ocfs2_cached_inode *) * scan->num_inode_alloc, &scan->inode_alloc); if (ret) goto out_scan; /* Minimum 8 inodes in the buffer */ scan->buffer_blocks = fs->fs_clustersize / fs->fs_blocksize; if (scan->buffer_blocks < 8) { scan->buffer_blocks = ((8 * fs->fs_blocksize) + (fs->fs_clustersize - 1)) / fs->fs_clustersize; scan->buffer_blocks = ocfs2_clusters_to_blocks(fs, scan->buffer_blocks); } ret = ocfs2_malloc_blocks(fs->fs_io, scan->buffer_blocks, &scan->group_buffer); if (ret) goto out_inode_files; ret = ocfs2_lookup_system_inode(fs, GLOBAL_INODE_ALLOC_SYSTEM_INODE, 0, &blkno); if (ret) goto out_cleanup; ret = ocfs2_read_cached_inode(fs, blkno, &scan->inode_alloc[0]); if (ret) goto out_cleanup; for (i = 1; i < scan->num_inode_alloc; i++) { slot_num = i - 1; ret = ocfs2_lookup_system_inode(fs, INODE_ALLOC_SYSTEM_INODE, slot_num, &blkno); if (ret) goto out_cleanup; ret = ocfs2_read_cached_inode(fs, blkno, &scan->inode_alloc[i]); if (ret) goto out_cleanup; } /* * FIXME: Should this pre-read all the group descriptors like * the old code read all the extent maps? */ *ret_scan = scan; return 0; out_inode_files: ocfs2_free(&scan->inode_alloc); out_scan: ocfs2_free(&scan); out_cleanup: if (scan) ocfs2_close_inode_scan(scan); return ret; } void ocfs2_close_inode_scan(ocfs2_inode_scan *scan) { int i; if (!scan) return; for (i = 0; i < scan->num_inode_alloc; i++) { if (scan->inode_alloc[i]) { ocfs2_free_cached_inode(scan->fs, scan->inode_alloc[i]); } } ocfs2_free(&scan->group_buffer); ocfs2_free(&scan->cur_desc); ocfs2_free(&scan->inode_alloc); ocfs2_free(&scan); return; } #ifdef DEBUG_EXE #include #include static void print_usage(void) { fprintf(stderr, "Usage: debug_inode_scan \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; int done; uint64_t blkno; char *filename, *buf; ocfs2_filesys *fs; struct ocfs2_dinode *di; ocfs2_inode_scan *scan; initialize_ocfs_error_table(); if (argc < 2) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[1]; ret = ocfs2_open(filename, OCFS2_FLAG_RO|OCFS2_FLAG_BUFFERED, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } di = (struct ocfs2_dinode *)buf; ret = ocfs2_open_inode_scan(fs, &scan); if (ret) { com_err(argv[0], ret, "while opening inode scan"); goto out_free; } done = 0; while (!done) { ret = ocfs2_get_next_inode(scan, &blkno, buf); if (ret) { com_err(argv[0], ret, "while getting next inode"); goto out_close_scan; } if (blkno) { if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) continue; if (!(di->i_flags & OCFS2_VALID_FL)) continue; fprintf(stdout, "%snode %"PRIu64" with size %"PRIu64"\n", (di->i_flags & OCFS2_SYSTEM_FL) ? "System i" : "I", blkno, di->i_size); } else done = 1; } out_close_scan: ocfs2_close_inode_scan(scan); out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/ismounted.c0000644000176100017610000002242111115551036014633 00000000000000/* * ismounted.c --- Check to see if the filesystem was mounted * * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public * License. * %End-Header% */ /* Modified for OCFS2 by Manish Singh */ #define HAVE_UNISTD_H 1 #define HAVE_ERRNO_H 1 #define HAVE_LINUX_FD_H 1 #define HAVE_MNTENT_H 1 #include #if HAVE_UNISTD_H #include #endif #if HAVE_ERRNO_H #include #endif #include #ifdef HAVE_LINUX_FD_H #include #endif #ifdef HAVE_MNTENT_H #include #endif #ifdef HAVE_GETMNTINFO #include #include #include #endif /* HAVE_GETMNTINFO */ #include #include #include "ocfs2/ocfs2.h" #ifdef HAVE_MNTENT_H /* * Helper function which checks a file in /etc/mtab format to see if a * filesystem is mounted. Returns an error if the file doesn't exist * or can't be opened. */ static errcode_t check_mntent_file(const char *mtab_file, const char *file, int *mount_flags, char *mtpt, int mtlen) { struct mntent *mnt; struct stat st_buf; errcode_t retval = 0; dev_t file_dev=0, file_rdev=0; ino_t file_ino=0; FILE *f; int fd; *mount_flags = 0; if ((f = setmntent (mtab_file, "r")) == NULL) return errno; if (stat(file, &st_buf) == 0) { if (S_ISBLK(st_buf.st_mode)) { #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ file_rdev = st_buf.st_rdev; #endif /* __GNU__ */ } else { file_dev = st_buf.st_dev; file_ino = st_buf.st_ino; } } while ((mnt = getmntent (f)) != NULL) { if (strcmp(file, mnt->mnt_fsname) == 0) break; if (stat(mnt->mnt_fsname, &st_buf) == 0) { if (S_ISBLK(st_buf.st_mode)) { #ifndef __GNU__ if (file_rdev && (file_rdev == st_buf.st_rdev)) break; #endif /* __GNU__ */ } else { if (file_dev && ((file_dev == st_buf.st_dev) && (file_ino == st_buf.st_ino))) break; } } } if (mnt == 0) { #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ /* * Do an extra check to see if this is the root device. We * can't trust /etc/mtab, and /proc/mounts will only list * /dev/root for the root filesystem. Argh. Instead we * check if the given device has the same major/minor number * as the device that the root directory is on. */ if (file_rdev && stat("/", &st_buf) == 0) { if (st_buf.st_dev == file_rdev) { *mount_flags = OCFS2_MF_MOUNTED; if (mtpt) strncpy(mtpt, "/", mtlen); goto is_root; } } #endif /* __GNU__ */ goto errout; } #ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ /* Validate the entry in case /etc/mtab is out of date */ /* * We need to be paranoid, because some broken distributions * (read: Slackware) don't initialize /etc/mtab before checking * all of the non-root filesystems on the disk. */ if (stat(mnt->mnt_dir, &st_buf) < 0) { retval = errno; if (retval == ENOENT) { #ifdef DEBUG printf("Bogus entry in %s! (%s does not exist)\n", mtab_file, mnt->mnt_dir); #endif /* DEBUG */ retval = 0; } goto errout; } if (file_rdev && (st_buf.st_dev != file_rdev)) { #ifdef DEBUG printf("Bogus entry in %s! (%s not mounted on %s)\n", mtab_file, file, mnt->mnt_dir); #endif /* DEBUG */ goto errout; } #endif /* __GNU__ */ *mount_flags = OCFS2_MF_MOUNTED; #ifdef MNTOPT_RO /* Check to see if the ro option is set */ if (hasmntopt(mnt, MNTOPT_RO)) *mount_flags |= OCFS2_MF_READONLY; #endif if (mtpt) strncpy(mtpt, mnt->mnt_dir, mtlen); /* * Check to see if we're referring to the root filesystem. * If so, do a manual check to see if we can open /etc/mtab * read/write, since if the root is mounted read/only, the * contents of /etc/mtab may not be accurate. */ if (!strcmp(mnt->mnt_dir, "/")) { is_root: #define TEST_FILE "/.ismount-test-file" *mount_flags |= OCFS2_MF_ISROOT; fd = open(TEST_FILE, O_RDWR|O_CREAT, 0600); if (fd < 0) { if (errno == EROFS) *mount_flags |= OCFS2_MF_READONLY; } else close(fd); (void) unlink(TEST_FILE); } retval = 0; errout: endmntent (f); return retval; } static errcode_t check_mntent(const char *file, int *mount_flags, char *mtpt, int mtlen) { errcode_t retval; #ifdef DEBUG retval = check_mntent_file("/tmp/mtab", file, mount_flags, mtpt, mtlen); if (retval == 0) return 0; #endif /* DEBUG */ #ifdef __linux__ retval = check_mntent_file("/proc/mounts", file, mount_flags, mtpt, mtlen); if (retval == 0 && (*mount_flags != 0)) return 0; #endif /* __linux__ */ #if defined(MOUNTED) || defined(_PATH_MOUNTED) #ifndef MOUNTED #define MOUNTED _PATH_MOUNTED #endif /* MOUNTED */ retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); return retval; #else *mount_flags = 0; return 0; #endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */ } #else #if defined(HAVE_GETMNTINFO) static errcode_t check_getmntinfo(const char *file, int *mount_flags, char *mtpt, int mtlen) { struct statfs *mp; int len, n; const char *s1; char *s2; n = getmntinfo(&mp, MNT_NOWAIT); if (n == 0) return errno; len = sizeof(_PATH_DEV) - 1; s1 = file; if (strncmp(_PATH_DEV, s1, len) == 0) s1 += len; *mount_flags = 0; while (--n >= 0) { s2 = mp->f_mntfromname; if (strncmp(_PATH_DEV, s2, len) == 0) { s2 += len - 1; *s2 = 'r'; } if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { *mount_flags = OCFS2_MF_MOUNTED; break; } ++mp; } if (mtpt) strncpy(mtpt, mp->f_mntonname, mtlen); return 0; } #endif /* HAVE_GETMNTINFO */ #endif /* HAVE_MNTENT_H */ /* * Check to see if we're dealing with the swap device. */ static int is_swap_device(const char *file) { FILE *f; char buf[1024], *cp; dev_t file_dev; struct stat st_buf; int ret = 0; file_dev = 0; #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ if ((stat(file, &st_buf) == 0) && S_ISBLK(st_buf.st_mode)) file_dev = st_buf.st_rdev; #endif /* __GNU__ */ if (!(f = fopen("/proc/swaps", "r"))) return 0; /* Skip the first line */ fgets(buf, sizeof(buf), f); while (!feof(f)) { if (!fgets(buf, sizeof(buf), f)) break; if ((cp = strchr(buf, ' ')) != NULL) *cp = 0; if ((cp = strchr(buf, '\t')) != NULL) *cp = 0; if (strcmp(buf, file) == 0) { ret++; break; } #ifndef __GNU__ if (file_dev && (stat(buf, &st_buf) == 0) && S_ISBLK(st_buf.st_mode) && file_dev == st_buf.st_rdev) { ret++; break; } #endif /* __GNU__ */ } fclose(f); return ret; } /* * ocfs2_check_mount_point() fills determines if the device is * mounted or otherwise busy, and fills in mount_flags with one or * more of the following flags: OCFS2_MF_MOUNTED, OCFS2_MF_ISROOT, * OCFS2_MF_READONLY, OCFS2_MF_SWAP, and OCFS2_MF_BUSY. If mtpt is * non-NULL, the directory where the device is mounted is copied to * where mtpt is pointing, up to mtlen characters. */ #ifdef __TURBOC__ #pragma argsused #endif errcode_t ocfs2_check_mount_point(const char *device, int *mount_flags, char *mtpt, int mtlen) { struct stat st_buf; errcode_t retval = 0; int fd; if (is_swap_device(device)) { *mount_flags = OCFS2_MF_MOUNTED | OCFS2_MF_SWAP; strncpy(mtpt, "", mtlen); } else { #ifdef HAVE_MNTENT_H retval = check_mntent(device, mount_flags, mtpt, mtlen); #else #ifdef HAVE_GETMNTINFO retval = check_getmntinfo(device, mount_flags, mtpt, mtlen); #else #ifdef __GNUC__ #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" #endif *mount_flags = 0; #endif /* HAVE_GETMNTINFO */ #endif /* HAVE_MNTENT_H */ } if (retval) return retval; #ifdef __linux__ /* This only works on Linux 2.6+ systems */ if ((stat(device, &st_buf) != 0) || !S_ISBLK(st_buf.st_mode)) return 0; fd = open(device, O_RDONLY | O_EXCL); if (fd < 0) { if (errno == EBUSY) *mount_flags |= OCFS2_MF_BUSY; } else close(fd); return 0; #endif } /* * ocfs2_check_if_mounted() sets the mount_flags OCFS2_MF_MOUNTED, * OCFS2_MF_READONLY, and OCFS2_MF_ROOT * */ errcode_t ocfs2_check_if_mounted(const char *file, int *mount_flags) { return ocfs2_check_mount_point(file, mount_flags, NULL, 0); } #ifdef DEBUG_EXE int main(int argc, char **argv) { int retval, mount_flags; char mntpt[80]; if (argc < 2) { fprintf(stderr, "Usage: %s device\n", argv[0]); exit(1); } mntpt[0] = 0; retval = ocfs2_check_mount_point(argv[1], &mount_flags, mntpt, sizeof(mntpt)); if (retval) { com_err(argv[0], retval, "while calling ocfs2_check_if_mounted"); exit(1); } printf("Device %s reports flags %02x\n", argv[1], mount_flags); if (mount_flags & OCFS2_MF_BUSY) printf("\t%s is apparently in use.\n", argv[1]); if (mount_flags & OCFS2_MF_MOUNTED) printf("\t%s is mounted.\n", argv[1]); if (mount_flags & OCFS2_MF_SWAP) printf("\t%s is a swap device.\n", argv[1]); if (mount_flags & OCFS2_MF_READONLY) printf("\t%s is read-only.\n", argv[1]); if (mount_flags & OCFS2_MF_ISROOT) printf("\t%s is the root filesystem.\n", argv[1]); if (mntpt[0]) printf("\t%s is mounted on %s.\n", argv[1], mntpt); exit(0); } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/kernel-rbtree.c0000644000176100017610000002157711115551036015400 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * kernel-rbtree.c * * This is imported from the Linux kernel to give us a tested and * portable tree library. */ /* Red Black Trees (C) 1999 Andrea Arcangeli (C) 2002 David Woodhouse 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/lib/rbtree.c */ #include "ocfs2/kernel-rbtree.h" static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) { struct rb_node *right = node->rb_right; if ((node->rb_right = right->rb_left)) right->rb_left->rb_parent = node; right->rb_left = node; if ((right->rb_parent = node->rb_parent)) { if (node == node->rb_parent->rb_left) node->rb_parent->rb_left = right; else node->rb_parent->rb_right = right; } else root->rb_node = right; node->rb_parent = right; } static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) { struct rb_node *left = node->rb_left; if ((node->rb_left = left->rb_right)) left->rb_right->rb_parent = node; left->rb_right = node; if ((left->rb_parent = node->rb_parent)) { if (node == node->rb_parent->rb_right) node->rb_parent->rb_right = left; else node->rb_parent->rb_left = left; } else root->rb_node = left; node->rb_parent = left; } void rb_insert_color(struct rb_node *node, struct rb_root *root) { struct rb_node *parent, *gparent; while ((parent = node->rb_parent) && parent->rb_color == RB_RED) { gparent = parent->rb_parent; if (parent == gparent->rb_left) { { register struct rb_node *uncle = gparent->rb_right; if (uncle && uncle->rb_color == RB_RED) { uncle->rb_color = RB_BLACK; parent->rb_color = RB_BLACK; gparent->rb_color = RB_RED; node = gparent; continue; } } if (parent->rb_right == node) { register struct rb_node *tmp; __rb_rotate_left(parent, root); tmp = parent; parent = node; node = tmp; } parent->rb_color = RB_BLACK; gparent->rb_color = RB_RED; __rb_rotate_right(gparent, root); } else { { register struct rb_node *uncle = gparent->rb_left; if (uncle && uncle->rb_color == RB_RED) { uncle->rb_color = RB_BLACK; parent->rb_color = RB_BLACK; gparent->rb_color = RB_RED; node = gparent; continue; } } if (parent->rb_left == node) { register struct rb_node *tmp; __rb_rotate_right(parent, root); tmp = parent; parent = node; node = tmp; } parent->rb_color = RB_BLACK; gparent->rb_color = RB_RED; __rb_rotate_left(gparent, root); } } root->rb_node->rb_color = RB_BLACK; } static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, struct rb_root *root) { struct rb_node *other; while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node) { if (parent->rb_left == node) { other = parent->rb_right; if (other->rb_color == RB_RED) { other->rb_color = RB_BLACK; parent->rb_color = RB_RED; __rb_rotate_left(parent, root); other = parent->rb_right; } if ((!other->rb_left || other->rb_left->rb_color == RB_BLACK) && (!other->rb_right || other->rb_right->rb_color == RB_BLACK)) { other->rb_color = RB_RED; node = parent; parent = node->rb_parent; } else { if (!other->rb_right || other->rb_right->rb_color == RB_BLACK) { register struct rb_node *o_left; if ((o_left = other->rb_left)) o_left->rb_color = RB_BLACK; other->rb_color = RB_RED; __rb_rotate_right(other, root); other = parent->rb_right; } other->rb_color = parent->rb_color; parent->rb_color = RB_BLACK; if (other->rb_right) other->rb_right->rb_color = RB_BLACK; __rb_rotate_left(parent, root); node = root->rb_node; break; } } else { other = parent->rb_left; if (other->rb_color == RB_RED) { other->rb_color = RB_BLACK; parent->rb_color = RB_RED; __rb_rotate_right(parent, root); other = parent->rb_left; } if ((!other->rb_left || other->rb_left->rb_color == RB_BLACK) && (!other->rb_right || other->rb_right->rb_color == RB_BLACK)) { other->rb_color = RB_RED; node = parent; parent = node->rb_parent; } else { if (!other->rb_left || other->rb_left->rb_color == RB_BLACK) { register struct rb_node *o_right; if ((o_right = other->rb_right)) o_right->rb_color = RB_BLACK; other->rb_color = RB_RED; __rb_rotate_left(other, root); other = parent->rb_left; } other->rb_color = parent->rb_color; parent->rb_color = RB_BLACK; if (other->rb_left) other->rb_left->rb_color = RB_BLACK; __rb_rotate_right(parent, root); node = root->rb_node; break; } } } if (node) node->rb_color = RB_BLACK; } void rb_erase(struct rb_node *node, struct rb_root *root) { struct rb_node *child, *parent; int color; if (!node->rb_left) child = node->rb_right; else if (!node->rb_right) child = node->rb_left; else { struct rb_node *old = node, *left; node = node->rb_right; while ((left = node->rb_left) != NULL) node = left; child = node->rb_right; parent = node->rb_parent; color = node->rb_color; if (child) child->rb_parent = parent; if (parent) { if (parent->rb_left == node) parent->rb_left = child; else parent->rb_right = child; } else root->rb_node = child; if (node->rb_parent == old) parent = node; node->rb_parent = old->rb_parent; node->rb_color = old->rb_color; node->rb_right = old->rb_right; node->rb_left = old->rb_left; if (old->rb_parent) { if (old->rb_parent->rb_left == old) old->rb_parent->rb_left = node; else old->rb_parent->rb_right = node; } else root->rb_node = node; old->rb_left->rb_parent = node; if (old->rb_right) old->rb_right->rb_parent = node; goto color; } parent = node->rb_parent; color = node->rb_color; if (child) child->rb_parent = parent; if (parent) { if (parent->rb_left == node) parent->rb_left = child; else parent->rb_right = child; } else root->rb_node = child; color: if (color == RB_BLACK) __rb_erase_color(child, parent, root); } /* * This function returns the first node (in sort order) of the tree. */ struct rb_node *rb_first(struct rb_root *root) { struct rb_node *n; n = root->rb_node; if (!n) return NULL; while (n->rb_left) n = n->rb_left; return n; } struct rb_node *rb_last(struct rb_root *root) { struct rb_node *n; n = root->rb_node; if (!n) return NULL; while (n->rb_right) n = n->rb_right; return n; } struct rb_node *rb_next(struct rb_node *node) { /* If we have a right-hand child, go down and then left as far as we can. */ if (node->rb_right) { node = node->rb_right; while (node->rb_left) node=node->rb_left; return node; } /* No right-hand children. Everything down and left is smaller than us, so any 'next' node must be in the general direction of our parent. Go up the tree; any time the ancestor is a right-hand child of its parent, keep going up. First time it's a left-hand child of its parent, said parent is our 'next' node. */ while (node->rb_parent && node == node->rb_parent->rb_right) node = node->rb_parent; return node->rb_parent; } struct rb_node *rb_prev(struct rb_node *node) { /* If we have a left-hand child, go down and then right as far as we can. */ if (node->rb_left) { node = node->rb_left; while (node->rb_right) node=node->rb_right; return node; } /* No left-hand children. Go up till we find an ancestor which is a right-hand child of its parent */ while (node->rb_parent && node == node->rb_parent->rb_left) node = node->rb_parent; return node->rb_parent; } void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root) { struct rb_node *parent = victim->rb_parent; /* Set the surrounding nodes to point to the replacement */ if (parent) { if (victim == parent->rb_left) parent->rb_left = new; else parent->rb_right = new; } else { root->rb_node = new; } if (victim->rb_left) victim->rb_left->rb_parent = new; if (victim->rb_right) victim->rb_right->rb_parent = new; /* Copy the pointers/colour from the victim to the replacement */ *new = *victim; } ./ocfs2-tools-1.6.4/libocfs2/link.c0000644000176100017610000001166311500500544013563 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * link.c * * Create links in OCFS2 directories. For the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/link.c * Copyright (C) 1993, 1994 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/ocfs2.h" struct link_struct { const char *name; int namelen; uint64_t inode; int flags; int done; int blockend; /* What to consider the end of the block. This handles the directory trailer if it exists */ int blkno; struct ocfs2_dinode *sb; }; static int link_proc(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct link_struct *ls = (struct link_struct *) priv_data; struct ocfs2_dir_entry *next; int rec_len, min_rec_len; int ret = 0; rec_len = OCFS2_DIR_REC_LEN(ls->namelen); /* * See if the following directory entry (if any) is unused; * if so, absorb it into this one. */ next = (struct ocfs2_dir_entry *) (buf + offset + dirent->rec_len); if ((offset + dirent->rec_len < ls->blockend - 8) && (next->inode == 0) && (offset + dirent->rec_len + next->rec_len <= ls->blockend)) { dirent->rec_len += next->rec_len; ret = OCFS2_DIRENT_CHANGED; } /* * If the directory entry is used, see if we can split the * directory entry to make room for the new name. If so, * truncate it and return. */ if (dirent->inode) { min_rec_len = OCFS2_DIR_REC_LEN(dirent->name_len & 0xFF); if (dirent->rec_len < (min_rec_len + rec_len)) return ret; rec_len = dirent->rec_len - min_rec_len; dirent->rec_len = min_rec_len; next = (struct ocfs2_dir_entry *) (buf + offset + dirent->rec_len); next->inode = 0; next->name_len = 0; next->rec_len = rec_len; return OCFS2_DIRENT_CHANGED; } /* * If we get this far, then the directory entry is not used. * See if we can fit the request entry in. If so, do it. */ if (dirent->rec_len < rec_len) return ret; dirent->inode = ls->inode; dirent->name_len = ls->namelen; strncpy(dirent->name, ls->name, ls->namelen); dirent->file_type = ls->flags; ls->blkno = blocknr; ls->done++; return OCFS2_DIRENT_ABORT|OCFS2_DIRENT_CHANGED; } /* * Note: the low 3 bits of the flags field are used as the directory * entry filetype. */ errcode_t ocfs2_link(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, int flags) { errcode_t retval; struct link_struct ls; char *buf; struct ocfs2_dinode *di; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((ino < OCFS2_SUPER_BLOCK_BLKNO) || (ino > fs->fs_blocks)) return OCFS2_ET_INVALID_ARGUMENT; retval = ocfs2_malloc_block(fs->fs_io, &buf); if (retval) return retval; retval = ocfs2_read_inode(fs, dir, buf); if (retval) goto out_free; di = (struct ocfs2_dinode *)buf; ls.name = name; ls.namelen = name ? strlen(name) : 0; ls.inode = ino; ls.flags = flags; ls.done = 0; ls.sb = fs->fs_super; if (ocfs2_dir_has_trailer(fs, di)) ls.blockend = ocfs2_dir_trailer_blk_off(fs); else ls.blockend = fs->fs_blocksize; retval = ocfs2_dir_iterate(fs, dir, OCFS2_DIRENT_FLAG_INCLUDE_EMPTY, NULL, link_proc, &ls); if (retval) goto out_free; if (!ls.done) { retval = ocfs2_expand_dir(fs, dir); if (retval) goto out_free; /* Gotta refresh */ retval = ocfs2_read_inode(fs, dir, buf); if (retval) goto out_free; if (ocfs2_dir_has_trailer(fs, di)) ls.blockend = ocfs2_dir_trailer_blk_off(fs); else ls.blockend = fs->fs_blocksize; retval = ocfs2_dir_iterate(fs, dir, OCFS2_DIRENT_FLAG_INCLUDE_EMPTY, NULL, link_proc, &ls); if (!retval && !ls.done) retval = OCFS2_ET_INTERNAL_FAILURE; } if (ls.done) { if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)) && (di->i_dyn_features & OCFS2_INDEXED_DIR_FL)) retval = ocfs2_dx_dir_insert_entry(fs, dir, ls.name, ls.inode, ls.blkno); } out_free: ocfs2_free(&buf); return retval; } ./ocfs2-tools-1.6.4/libocfs2/lookup.c0000644000176100017610000001357011500500544014136 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * lookup.c * * Directory lookup routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/lookup.c * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include "ocfs2/ocfs2.h" struct lookup_struct { const char *name; int len; uint64_t *inode; int found; }; #ifdef __TURBOC__ #pragma argsused #endif static int lookup_proc(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct lookup_struct *ls = (struct lookup_struct *) priv_data; if (ls->len != (dirent->name_len & 0xFF)) return 0; if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF))) return 0; *ls->inode = dirent->inode; ls->found++; return OCFS2_DIRENT_ABORT; } static errcode_t ocfs2_find_entry_dx(ocfs2_filesys *fs, struct ocfs2_dinode *di, char *buf, struct lookup_struct *ls) { char *dx_root_buf = NULL; struct ocfs2_dx_root_block *dx_root; struct ocfs2_dir_lookup_result lookup; errcode_t ret; ret = ocfs2_malloc_block(fs->fs_io, &dx_root_buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, di->i_dx_root, dx_root_buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)dx_root_buf; memset(&lookup, 0, sizeof(struct ocfs2_dir_lookup_result)); ocfs2_dx_dir_name_hash(fs, ls->name, ls->len, &lookup.dl_hinfo); ret = ocfs2_dx_dir_search(fs, ls->name, ls->len, dx_root, &lookup); if (ret) goto out; *ls->inode = lookup.dl_entry->inode; ls->found++; ret = 0; out: release_lookup_res(&lookup); if (dx_root_buf) ocfs2_free(&dx_root_buf); return ret; } errcode_t ocfs2_lookup(ocfs2_filesys *fs, uint64_t dir, const char *name, int namelen, char *buf, uint64_t *inode) { errcode_t ret; struct lookup_struct ls; char *di_buf = NULL; struct ocfs2_dinode *di; ls.name = name; ls.len = namelen; ls.inode = inode; ls.found = 0; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)) && ocfs2_dir_indexed(di)) { ret = ocfs2_find_entry_dx(fs, di, buf, &ls); } else { ret = ocfs2_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls); } if (ret) goto out; ret = (ls.found) ? 0 : OCFS2_ET_FILE_NOT_FOUND; out: if(di_buf) ocfs2_free(&di_buf); return ret; } #ifdef DEBUG_EXE #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: lookup [-i ] \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno, result_blkno; int c, indent; char *filename, *lookup_path, *buf; char *p; char lookup_name[256]; ocfs2_filesys *fs; blkno = 0; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; optind++; if (optind >= argc) { fprintf(stdout, "Missing path to lookup\n"); print_usage(); return 1; } lookup_path = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } if (!blkno) blkno = OCFS2_RAW_SB(fs->fs_super)->s_root_blkno; for (p = lookup_path; *p == '/'; p++); lookup_path = p; fprintf(stdout, "/ (%"PRIu64")\n", blkno); indent = 0; for (p = lookup_path; ; p++) { if (*p && *p != '/') continue; memcpy(lookup_name, lookup_path, p - lookup_path); lookup_name[p - lookup_path] = '\0'; ret = ocfs2_lookup(fs, blkno, lookup_name, strlen(lookup_name), NULL, &result_blkno); if (ret) { com_err(argv[0], ret, "while looking up \"%s\" in inode %"PRIu64" on" " \"%s\"\n", lookup_name, blkno, filename); goto out_free; } indent += 4; for (c = 0; c < indent; c++) fprintf(stdout, " "); fprintf(stdout, "%s (%"PRIu64")\n", lookup_name, result_blkno); blkno = result_blkno; for (; *p == '/'; p++); lookup_path = p; if (!*p) break; } out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/memory.c0000644000176100017610000000561111341355440014140 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * memory.c * * Memory routines for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Portions of this code from e2fsprogs/lib/ext2fs/ext2fs.h * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, * 2002 by Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include "ocfs2/ocfs2.h" errcode_t ocfs2_malloc(unsigned long size, void *ptr) { void **pp = (void **)ptr; *pp = malloc(size); if (!*pp) return OCFS2_ET_NO_MEMORY; return 0; } errcode_t ocfs2_malloc0(unsigned long size, void *ptr) { errcode_t ret; void **pp = (void **)ptr; ret = ocfs2_malloc(size, ptr); if (ret) return ret; memset(*pp, 0, size); return 0; } errcode_t ocfs2_free(void *ptr) { void **pp = (void **)ptr; free(*pp); *pp = NULL; return 0; } errcode_t ocfs2_realloc(unsigned long size, void *ptr) { void *p; void **pp = (void **)ptr; p = realloc(*pp, size); if (!p) return OCFS2_ET_NO_MEMORY; *pp = p; return 0; } errcode_t ocfs2_realloc0(unsigned long size, void *ptr, unsigned long old_size) { errcode_t ret; char *p; void **pp = (void **)ptr; ret = ocfs2_realloc(size, ptr); if (ret) return ret; if (size > old_size) { p = (char *)(*pp); memset(p + old_size, 0, size - old_size); } return 0; } errcode_t ocfs2_malloc_blocks(io_channel *channel, int num_blocks, void *ptr) { errcode_t ret; int blksize; size_t bytes; void **pp = (void **)ptr; void *tmp; blksize = io_get_blksize(channel); if (((unsigned long long)num_blocks * blksize) > SIZE_MAX) return OCFS2_ET_NO_MEMORY; bytes = num_blocks * blksize; /* * Older glibcs abort when they can't memalign() something. * Ugh! Check with malloc() first. */ tmp = malloc(bytes); if (!tmp) return OCFS2_ET_NO_MEMORY; free(tmp); ret = posix_memalign(pp, blksize, bytes); if (!ret) return 0; if (errno == ENOMEM) return OCFS2_ET_NO_MEMORY; /* blksize better be valid */ abort(); } errcode_t ocfs2_malloc_block(io_channel *channel, void *ptr) { return ocfs2_malloc_blocks(channel, 1, ptr); } ./ocfs2-tools-1.6.4/libocfs2/mkjournal.c0000644000176100017610000003066611500500544014634 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * mkjournal.c * * Journal creation for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Portions of the code from e2fsprogs/lib/ext2fs/mkjournal.c * Copyright (C) 2000 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" size_t ocfs2_journal_tag_bytes(journal_superblock_t *jsb) { if (JBD2_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_64BIT)) return JBD2_TAG_SIZE64; else return JBD2_TAG_SIZE32; } uint64_t ocfs2_journal_tag_block(journal_block_tag_t *tag, size_t tag_bytes) { uint64_t blockno = be32_to_cpu(tag->t_blocknr); if (tag_bytes > JBD2_TAG_SIZE32) blockno |= (uint64_t)be32_to_cpu(tag->t_blocknr_high) << 32; return blockno; } /* Returns true if we support these journal features */ static int ocfs2_journal_check_available_features(journal_superblock_t *jsb, ocfs2_fs_options *features) { /* ocfs2 has never supported a superblock other than _V2 */ if (jsb->s_header.h_blocktype != JBD2_SUPERBLOCK_V2) return 0; if ((features->opt_compat & JBD2_KNOWN_COMPAT_FEATURES) != features->opt_compat) return 0; /* * ocfs2 will never use jbd2 checksums. If a jbd2 checksum fails, * the transaction is not replayed. This means that some parts of * the transaction may have checkpointed while other parts have not. * This inconsistent state requires fsck to repair. ocfs2, being * clustered, can't tolerate that situation. Instead, ocfs2 * prefers to replay the journal. This allows the cluster to * remain running. Using the METAECC feature allows ocfs2 to * detect and isolate any corrupted blocks. */ if (features->opt_compat & JBD2_FEATURE_COMPAT_CHECKSUM) return 0; if ((features->opt_ro_compat & JBD2_KNOWN_ROCOMPAT_FEATURES) != features->opt_ro_compat) return 0; if ((features->opt_incompat & JBD2_KNOWN_INCOMPAT_FEATURES) != features->opt_incompat) return 0; return 1; } errcode_t ocfs2_journal_set_features(journal_superblock_t *jsb, ocfs2_fs_options *features) { if (!ocfs2_journal_check_available_features(jsb, features)) return OCFS2_ET_UNSUPP_FEATURE; jsb->s_feature_compat |= features->opt_compat; jsb->s_feature_ro_compat |= features->opt_ro_compat; jsb->s_feature_incompat |= features->opt_incompat; return 0; } errcode_t ocfs2_journal_clear_features(journal_superblock_t *jsb, ocfs2_fs_options *features) { if (!ocfs2_journal_check_available_features(jsb, features)) return OCFS2_ET_UNSUPP_FEATURE; jsb->s_feature_compat &= ~(features->opt_compat); jsb->s_feature_ro_compat &= ~(features->opt_ro_compat); jsb->s_feature_incompat &= ~(features->opt_incompat); return 0; } void ocfs2_swap_journal_superblock(journal_superblock_t *jsb) { if (cpu_is_big_endian) return; jsb->s_header.h_magic = bswap_32(jsb->s_header.h_magic); jsb->s_header.h_blocktype = bswap_32(jsb->s_header.h_blocktype); jsb->s_header.h_sequence = bswap_32(jsb->s_header.h_sequence); jsb->s_blocksize = bswap_32(jsb->s_blocksize); jsb->s_maxlen = bswap_32(jsb->s_maxlen); jsb->s_first = bswap_32(jsb->s_first); jsb->s_sequence = bswap_32(jsb->s_sequence); jsb->s_start = bswap_32(jsb->s_start); jsb->s_errno = bswap_32(jsb->s_errno); jsb->s_feature_compat = bswap_32(jsb->s_feature_compat); jsb->s_feature_incompat = bswap_32(jsb->s_feature_incompat); jsb->s_feature_ro_compat = bswap_32(jsb->s_feature_ro_compat); jsb->s_nr_users = bswap_32(jsb->s_nr_users); jsb->s_dynsuper = bswap_32(jsb->s_dynsuper); jsb->s_max_transaction = bswap_32(jsb->s_max_transaction); jsb->s_max_trans_data = bswap_32(jsb->s_max_trans_data); } errcode_t ocfs2_init_journal_superblock(ocfs2_filesys *fs, char *buf, int buflen, uint32_t jrnl_size_in_blks) { journal_superblock_t *jsb = (journal_superblock_t *)buf; if (buflen < fs->fs_blocksize) return OCFS2_ET_INTERNAL_FAILURE; if (jrnl_size_in_blks < 1024) return OCFS2_ET_JOURNAL_TOO_SMALL; memset(buf, 0, buflen); jsb->s_header.h_magic = JBD2_MAGIC_NUMBER; jsb->s_header.h_blocktype = JBD2_SUPERBLOCK_V2; jsb->s_blocksize = fs->fs_blocksize; jsb->s_maxlen = jrnl_size_in_blks; if (fs->fs_blocksize == 512) jsb->s_first = 2; else jsb->s_first = 1; jsb->s_start = 1; jsb->s_sequence = 1; jsb->s_errno = 0; jsb->s_nr_users = 1; memcpy(jsb->s_uuid, OCFS2_RAW_SB(fs->fs_super)->s_uuid, sizeof(jsb->s_uuid)); return 0; } /* * This function automatically sets up the journal superblock and * returns it as an allocated block. */ static errcode_t ocfs2_create_journal_superblock(ocfs2_filesys *fs, uint32_t size, ocfs2_fs_options *features, char **ret_jsb) { errcode_t retval; char *buf = NULL; journal_superblock_t *jsb; *ret_jsb = NULL; if ((retval = ocfs2_malloc_block(fs->fs_io, &buf))) goto bail; retval = ocfs2_init_journal_superblock(fs, buf, fs->fs_blocksize, size); if (retval) goto bail; jsb = (journal_superblock_t *)buf; retval = ocfs2_journal_set_features(jsb, features); if (retval) goto bail; #if 0 /* Someday */ /* * If we're creating an external journal device, we need to * adjust these fields. */ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { jsb->s_nr_users = 0; if (fs->blocksize == 1024) jsb->s_first = 3; else jsb->s_first = 2; } #endif *ret_jsb = buf; bail: if (retval && buf) ocfs2_free(&buf); return retval; } errcode_t ocfs2_read_journal_superblock(ocfs2_filesys *fs, uint64_t blkno, char *jsb_buf) { errcode_t ret; char *blk; journal_superblock_t *disk, *jsb; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; disk = (journal_superblock_t *)blk; jsb = (journal_superblock_t *)jsb_buf; if (disk->s_header.h_magic != htonl(JBD2_MAGIC_NUMBER)) { ret = OCFS2_ET_BAD_JOURNAL_SUPERBLOCK_MAGIC; goto out; } memcpy(jsb_buf, blk, fs->fs_blocksize); ocfs2_swap_journal_superblock(jsb); if (JBD2_HAS_INCOMPAT_FEATURE(jsb, ~JBD2_KNOWN_INCOMPAT_FEATURES)) { ret = OCFS2_ET_UNSUPP_FEATURE; goto out; } if (JBD2_HAS_RO_COMPAT_FEATURE(jsb, ~JBD2_KNOWN_ROCOMPAT_FEATURES)) { ret = OCFS2_ET_RO_UNSUPP_FEATURE; goto out; } ret = 0; out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_write_journal_superblock(ocfs2_filesys *fs, uint64_t blkno, char *jsb_buf) { errcode_t ret; char *blk; journal_superblock_t *disk, *jsb; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; disk = (journal_superblock_t *)blk; jsb = (journal_superblock_t *)jsb_buf; memcpy(blk, jsb_buf, fs->fs_blocksize); ocfs2_swap_journal_superblock(disk); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; } static errcode_t ocfs2_format_journal(ocfs2_filesys *fs, ocfs2_cached_inode *ci, ocfs2_fs_options *features) { errcode_t ret = 0; char *buf = NULL, *jsb_buf = NULL; int bs_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; uint64_t offset = 0; uint32_t wrote, count, jrnl_blocks; #define BUFLEN 1048576 ret = ocfs2_malloc_blocks(fs->fs_io, (BUFLEN >> bs_bits), &buf); if (ret) goto out; memset(buf, 0, BUFLEN); io_set_nocache(fs->fs_io, true); count = (uint32_t) ci->ci_inode->i_size; while (count) { ret = ocfs2_file_write(ci, buf, ocfs2_min((uint32_t) BUFLEN, count), offset, &wrote); if (ret) break; offset += wrote; count -= wrote; } io_set_nocache(fs->fs_io, false); if (ret) goto out; jrnl_blocks = ocfs2_clusters_to_blocks(fs, ci->ci_inode->i_clusters); ret = ocfs2_create_journal_superblock(fs, jrnl_blocks, features, &jsb_buf); if (ret) goto out; /* re-use offset here for 1st journal block. */ ret = ocfs2_extent_map_get_blocks(ci, 0, 1, &offset, NULL, NULL); if (ret) goto out; ret = ocfs2_write_journal_superblock(fs, offset, jsb_buf); out: if (buf) ocfs2_free(&buf); if (jsb_buf) ocfs2_free(&jsb_buf); return ret; } errcode_t ocfs2_make_journal(ocfs2_filesys *fs, uint64_t blkno, uint32_t clusters, ocfs2_fs_options *features) { errcode_t ret = 0; ocfs2_cached_inode *ci = NULL; struct ocfs2_dinode *di; if ((clusters << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits) < OCFS2_MIN_JOURNAL_SIZE) { ret = OCFS2_ET_JOURNAL_TOO_SMALL; goto out; } ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) goto out; /* verify it is a journal file */ if (!(ci->ci_inode->i_flags & OCFS2_VALID_FL) || !(ci->ci_inode->i_flags & OCFS2_SYSTEM_FL) || !(ci->ci_inode->i_flags & OCFS2_JOURNAL_FL)) { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } di = ci->ci_inode; if (clusters > di->i_clusters) { ret = ocfs2_extend_allocation(fs, blkno, (clusters - di->i_clusters)); if (ret) goto out; /* We don't cache in the library right now, so any * work done in extend_allocation won't be reflected * in our now stale copy. */ ocfs2_free_cached_inode(fs, ci); ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) { ci = NULL; goto out; } di = ci->ci_inode; di->i_size = di->i_clusters << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; di->i_mtime = time(NULL); ret = ocfs2_write_inode(fs, blkno, (char *)di); if (ret) goto out; } else if (clusters < di->i_clusters) { uint64_t new_size = clusters << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; ret = ocfs2_truncate(fs, blkno, new_size); if (ret) goto out; ocfs2_free_cached_inode(fs, ci); ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) { ci = NULL; goto out; } } ret = ocfs2_format_journal(fs, ci, features); out: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } #ifdef DEBUG_EXE #if 0 static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: mkjournal \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno; char *filename, *buf; ocfs2_filesys *fs; ocfs2_dinode *di; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); if (argc < 2) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[1]; if (argc > 2) { blkno = read_number(argv[2]); if (blkno < OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid blockno: %s\n", blkno); print_usage(); return 1; } } ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } di = (ocfs2_dinode *)buf; ret = ocfs2_read_inode(fs, blkno, di); if (ret) { com_err(argv[0], ret, "while reading inode %llu", blkno); goto out_free; } fprintf(stdout, "OCFS2 inode %llu on \"%s\"\n", blkno, filename); out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif #include int main(int argc, char *argv[]) { fprintf(stdout, "Does nothing for now\n"); return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/namei.c0000644000176100017610000001321411115551036013715 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * namei.c * * ocfs2 directory lookup operations * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/namei.c * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #if HAVE_UNISTD_H #include #endif #include "ocfs2/ocfs2.h" static errcode_t open_namei(ocfs2_filesys *fs, uint64_t root, uint64_t base, const char *pathname, size_t pathlen, int follow, int link_count, char *buf, uint64_t *res_inode); /* * follow_link() * */ static errcode_t follow_link(ocfs2_filesys *fs, uint64_t root, uint64_t dir, uint64_t inode, int link_count, char *buf, uint64_t *res_inode) { char *pathname; char *buffer = NULL; errcode_t ret; struct ocfs2_dinode *di = NULL; struct ocfs2_extent_list *el; uint64_t blkno; #ifdef NAMEI_DEBUG printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n", root, dir, inode, link_count); #endif ret = ocfs2_malloc_block(fs->fs_io, &di); if (ret) goto bail; ret = ocfs2_read_inode(fs, inode, (char *)di); if (ret) goto bail; if (!S_ISLNK(di->i_mode)) { *res_inode = inode; ret = 0; goto bail; } if (link_count++ > 5) { ret = OCFS2_ET_SYMLINK_LOOP; goto bail; } el = &(di->id2.i_list); if (!di->i_clusters || !el->l_next_free_rec) { ret = OCFS2_ET_INTERNAL_FAILURE; goto bail; } blkno = el->l_recs[0].e_blkno; ret = ocfs2_malloc_block(fs->fs_io, &buffer); if (ret) goto bail; ret = ocfs2_read_blocks(fs, blkno, 1, buffer); if (ret) goto bail; pathname = buffer; ret = open_namei(fs, root, dir, pathname, di->i_size, 1, link_count, buf, res_inode); bail: if (buffer) ocfs2_free(&buffer); if (di) ocfs2_free(&di); return ret; } /* * dir_namei() * * This routine interprets a pathname in the context of the current * directory and the root directory, and returns the inode of the * containing directory, and a pointer to the filename of the file * (pointing into the pathname) and the length of the filename. */ static errcode_t dir_namei(ocfs2_filesys *fs, uint64_t root, uint64_t dir, const char *pathname, int pathlen, int link_count, char *buf, const char **name, int *namelen, uint64_t *res_inode) { char c; const char *thisname; int len; uint64_t inode; errcode_t ret; if ((c = *pathname) == '/') { dir = root; pathname++; pathlen--; } while (1) { thisname = pathname; for (len=0; --pathlen >= 0;len++) { c = *(pathname++); if (c == '/') break; } if (pathlen < 0) break; ret = ocfs2_lookup (fs, dir, thisname, len, buf, &inode); if (ret) return ret; ret = follow_link (fs, root, dir, inode, link_count, buf, &dir); if (ret) return ret; } *name = thisname; *namelen = len; *res_inode = dir; return 0; } /* * open_namei() * */ static errcode_t open_namei(ocfs2_filesys *fs, uint64_t root, uint64_t base, const char *pathname, size_t pathlen, int follow, int link_count, char *buf, uint64_t *res_inode) { const char *basename; int namelen; uint64_t dir, inode; errcode_t ret; #ifdef NAMEI_DEBUG printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n", root, base, pathlen, pathname, link_count); #endif ret = dir_namei(fs, root, base, pathname, pathlen, link_count, buf, &basename, &namelen, &dir); if (ret) return ret; if (!namelen) { /* special case: '/usr/' etc */ *res_inode=dir; return 0; } ret = ocfs2_lookup (fs, dir, basename, namelen, buf, &inode); if (ret) return ret; if (follow) { ret = follow_link(fs, root, dir, inode, link_count, buf, &inode); if (ret) return ret; } #ifdef NAMEI_DEBUG printf("open_namei: (link_count=%d) returns %lu\n", link_count, inode); #endif *res_inode = inode; return 0; } /* * ocfs2_namei() * */ errcode_t ocfs2_namei(ocfs2_filesys *fs, uint64_t root, uint64_t cwd, const char *name, uint64_t *inode) { char *buf; errcode_t ret; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = open_namei(fs, root, cwd, name, strlen(name), 0, 0, buf, inode); ocfs2_free(&buf); return ret; } /* * ocfs2_namei_follow() * */ errcode_t ocfs2_namei_follow(ocfs2_filesys *fs, uint64_t root, uint64_t cwd, const char *name, uint64_t *inode) { char *buf; errcode_t ret; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = open_namei(fs, root, cwd, name, strlen(name), 1, 0, buf, inode); ocfs2_free(&buf); return ret; } /* * ocfs2_follow_link() * */ errcode_t ocfs2_follow_link(ocfs2_filesys *fs, uint64_t root, uint64_t cwd, uint64_t inode, uint64_t *res_inode) { char *buf; errcode_t ret; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = follow_link(fs, root, cwd, inode, 0, buf, res_inode); ocfs2_free(&buf); return ret; } ./ocfs2-tools-1.6.4/libocfs2/openfs.c0000644000176100017610000003230611346242240014121 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * openfs.c * * Open an OCFS2 filesystem. Part of the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Ideas taken from e2fsprogs/lib/ext2fs/openfs.c * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include /* I hate glibc and gcc */ #ifndef ULLONG_MAX # define ULLONG_MAX 18446744073709551615ULL #endif #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include "ocfs2-kernel/ocfs1_fs_compat.h" #include "ocfs2/image.h" /* * if the file is an o2image file, this routine maps the actual blockno to * relative block number in image file and then calls the underlying IO * function. At this point this function returns EIO if image file has any * holes */ static errcode_t __ocfs2_read_blocks(ocfs2_filesys *fs, int64_t blkno, int count, char *data, bool nocache) { int i; errcode_t err; if (fs->fs_flags & OCFS2_FLAG_IMAGE_FILE) { /* * o2image copies all meta blocks. If a caller asks for * N contiguous metadata blocks, all N should be in the * image file. However we check for any holes and * return -EIO if any. */ for (i = 0; i < count; i++) if (!ocfs2_image_test_bit(fs, blkno+i)) return OCFS2_ET_IO; /* translate the block number */ blkno = ocfs2_image_get_blockno(fs, blkno); } if (nocache) err = io_read_block_nocache(fs->fs_io, blkno, count, data); else err = io_read_block(fs->fs_io, blkno, count, data); return err; } errcode_t ocfs2_read_blocks_nocache(ocfs2_filesys *fs, int64_t blkno, int count, char *data) { return __ocfs2_read_blocks(fs, blkno, count, data, true); } errcode_t ocfs2_read_blocks(ocfs2_filesys *fs, int64_t blkno, int count, char *data) { return __ocfs2_read_blocks(fs, blkno, count, data, false); } static errcode_t ocfs2_validate_ocfs1_header(ocfs2_filesys *fs) { errcode_t ret; char *blk; struct ocfs1_vol_disk_hdr *hdr; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, 0, 1, blk); if (ret) goto out; hdr = (struct ocfs1_vol_disk_hdr *)blk; ret = OCFS2_ET_OCFS_REV; if (le32_to_cpu(hdr->major_version) == OCFS1_MAJOR_VERSION) goto out; if (!memcmp(hdr->signature, OCFS1_VOLUME_SIGNATURE, strlen(OCFS1_VOLUME_SIGNATURE))) goto out; ret = 0; out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_read_super(ocfs2_filesys *fs, uint64_t superblock, char *sb) { errcode_t ret; char *blk, *swapblk; struct ocfs2_dinode *di, *orig_super; int orig_blocksize; int blocksize = io_get_blksize(fs->fs_io); ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, superblock, 1, blk); if (ret) goto out_blk; di = (struct ocfs2_dinode *)blk; ret = OCFS2_ET_BAD_MAGIC; if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE, strlen(OCFS2_SUPER_BLOCK_SIGNATURE))) goto out_blk; /* * We want to use the latest superblock to validate. We need * a local-endian copy in fs->fs_super, and the unswapped copy to * check in blk. ocfs2_validate_meta_ecc() uses fs->fs_super and * fs->fs_blocksize. */ ret = ocfs2_malloc_block(fs->fs_io, &swapblk); if (ret) goto out_blk; memcpy(swapblk, blk, blocksize); orig_super = fs->fs_super; orig_blocksize = fs->fs_blocksize; fs->fs_super = (struct ocfs2_dinode *)swapblk; fs->fs_blocksize = blocksize; ocfs2_swap_inode_to_cpu(fs, fs->fs_super); ret = ocfs2_validate_meta_ecc(fs, blk, &di->i_check); fs->fs_super = orig_super; fs->fs_blocksize = orig_blocksize; ocfs2_free(&swapblk); if (ret) goto out_blk; ocfs2_swap_inode_to_cpu(fs, di); if (!sb) fs->fs_super = di; else { memcpy(sb, blk, fs->fs_blocksize); ocfs2_free(&blk); } return 0; out_blk: ocfs2_free(&blk); return ret; } errcode_t ocfs2_write_primary_super(ocfs2_filesys *fs) { errcode_t ret; char *blk; struct ocfs2_dinode *di; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; blk = (char *)fs->fs_super; di = (struct ocfs2_dinode *)blk; ret = OCFS2_ET_BAD_MAGIC; if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE, strlen(OCFS2_SUPER_BLOCK_SIGNATURE))) goto out_blk; ret = ocfs2_write_inode(fs, OCFS2_SUPER_BLOCK_BLKNO, blk); if (ret) goto out_blk; return 0; out_blk: return ret; } errcode_t ocfs2_write_super(ocfs2_filesys *fs) { errcode_t ret; ret = ocfs2_write_primary_super(fs); if (!ret) ret = ocfs2_refresh_backup_supers(fs); return ret; } errcode_t ocfs2_write_backup_super(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out_blk; memcpy(buf, (char *)fs->fs_super, fs->fs_blocksize); di = (struct ocfs2_dinode *)buf; ret = OCFS2_ET_BAD_MAGIC; if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE, strlen(OCFS2_SUPER_BLOCK_SIGNATURE))) goto out_blk; di->i_blkno = blkno; OCFS2_SET_COMPAT_FEATURE(OCFS2_RAW_SB(di), OCFS2_FEATURE_COMPAT_BACKUP_SB); ret = ocfs2_write_inode(fs, blkno, buf); if (ret) goto out_blk; ret = 0; out_blk: if (buf) ocfs2_free(&buf); return ret; } int ocfs2_mount_local(ocfs2_filesys *fs) { return OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT; } errcode_t ocfs2_open(const char *name, int flags, unsigned int superblock, unsigned int block_size, ocfs2_filesys **ret_fs) { ocfs2_filesys *fs; errcode_t ret; int i, len; char *ptr; unsigned char *raw_uuid; ret = ocfs2_malloc0(sizeof(ocfs2_filesys), &fs); if (ret) return ret; fs->fs_flags = flags; fs->fs_umask = 022; ret = io_open(name, (flags & (OCFS2_FLAG_RO | OCFS2_FLAG_RW | OCFS2_FLAG_BUFFERED)), &fs->fs_io); if (ret) goto out; ret = ocfs2_malloc(strlen(name)+1, &fs->fs_devname); if (ret) goto out; strcpy(fs->fs_devname, name); /* * If OCFS2_FLAG_IMAGE_FILE is specified, it needs to be handled * differently */ if (flags & OCFS2_FLAG_IMAGE_FILE) { ret = ocfs2_image_load_bitmap(fs); if (ret) goto out; if (!superblock) superblock = fs->ost->ost_superblocks[0]; if (!block_size) block_size = fs->ost->ost_fsblksz; } /* * If OCFS2_FLAG_NO_REV_CHECK is specified, fsck (or someone * like it) is asking to ignore the OCFS vol_header at * block 0. */ if (!(flags & OCFS2_FLAG_NO_REV_CHECK)) { ret = ocfs2_validate_ocfs1_header(fs); if (ret) goto out; } if (superblock) { ret = OCFS2_ET_INVALID_ARGUMENT; if (!block_size) goto out; io_set_blksize(fs->fs_io, block_size); ret = ocfs2_read_super(fs, (uint64_t)superblock, NULL); } else { superblock = OCFS2_SUPER_BLOCK_BLKNO; if (block_size) { io_set_blksize(fs->fs_io, block_size); ret = ocfs2_read_super(fs, (uint64_t)superblock, NULL); } else { for (block_size = io_get_blksize(fs->fs_io); block_size <= OCFS2_MAX_BLOCKSIZE; block_size <<= 1) { io_set_blksize(fs->fs_io, block_size); ret = ocfs2_read_super(fs, (uint64_t)superblock, NULL); if ((ret == OCFS2_ET_BAD_MAGIC) || (ret == OCFS2_ET_IO)) continue; break; } } } if (ret) goto out; fs->fs_blocksize = block_size; if (superblock == OCFS2_SUPER_BLOCK_BLKNO) { ret = ocfs2_malloc_block(fs->fs_io, &fs->fs_orig_super); if (ret) goto out; memcpy((char *)fs->fs_orig_super, (char *)fs->fs_super, fs->fs_blocksize); } #if 0 ret = OCFS2_ET_REV_TOO_HIGH; if (fs->fs_super->id2.i_super.s_major_rev_level > OCFS2_LIB_CURRENT_REV) goto out; #endif if (flags & OCFS2_FLAG_STRICT_COMPAT_CHECK) { ret = OCFS2_ET_UNSUPP_FEATURE; if (OCFS2_RAW_SB(fs->fs_super)->s_feature_compat & ~OCFS2_LIB_FEATURE_COMPAT_SUPP) goto out; /* We need to check s_tunefs_flag also to make sure * fsck.ocfs2 won't try to clean up an aborted tunefs * that it doesn't know. */ if (OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG) && (OCFS2_RAW_SB(fs->fs_super)->s_tunefs_flag & ~OCFS2_LIB_ABORTED_TUNEFS_SUPP)) goto out; } ret = OCFS2_ET_UNSUPP_FEATURE; if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & ~OCFS2_LIB_FEATURE_INCOMPAT_SUPP) goto out; ret = OCFS2_ET_RO_UNSUPP_FEATURE; if ((flags & OCFS2_FLAG_RW) && (OCFS2_RAW_SB(fs->fs_super)->s_feature_ro_compat & ~OCFS2_LIB_FEATURE_RO_COMPAT_SUPP)) goto out; ret = OCFS2_ET_UNSUPP_FEATURE; if (!(flags & OCFS2_FLAG_HEARTBEAT_DEV_OK) && (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV)) goto out; ret = OCFS2_ET_CORRUPT_SUPERBLOCK; if (!OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits) goto out; if (fs->fs_super->i_blkno != superblock) goto out; if ((OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits < 12) || (OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits > 20)) goto out; if (!OCFS2_RAW_SB(fs->fs_super)->s_root_blkno || !OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno) goto out; if (OCFS2_RAW_SB(fs->fs_super)->s_max_slots > OCFS2_MAX_SLOTS) goto out; ret = ocfs2_malloc0(OCFS2_RAW_SB(fs->fs_super)->s_max_slots * sizeof(ocfs2_cached_inode *), &fs->fs_inode_allocs); if (ret) goto out; ret = ocfs2_malloc0(OCFS2_RAW_SB(fs->fs_super)->s_max_slots * sizeof(ocfs2_cached_inode *), &fs->fs_eb_allocs); if (ret) goto out; ret = OCFS2_ET_UNEXPECTED_BLOCK_SIZE; if (block_size != (1U << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits)) goto out; fs->fs_clustersize = 1 << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; /* FIXME: Read the system dir */ fs->fs_root_blkno = OCFS2_RAW_SB(fs->fs_super)->s_root_blkno; fs->fs_sysdir_blkno = OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno; fs->fs_clusters = fs->fs_super->i_clusters; fs->fs_blocks = ocfs2_clusters_to_blocks(fs, fs->fs_clusters); fs->fs_first_cg_blkno = OCFS2_RAW_SB(fs->fs_super)->s_first_cluster_group; raw_uuid = OCFS2_RAW_SB(fs->fs_super)->s_uuid; for (i = 0, ptr = fs->uuid_str; i < OCFS2_VOL_UUID_LEN; i++) { /* print with null */ len = snprintf(ptr, 3, "%02X", raw_uuid[i]); if (len != 2) { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } /* then only advace past the last char */ ptr += 2; } *ret_fs = fs; return 0; out: if (fs->fs_inode_allocs) ocfs2_free(&fs->fs_inode_allocs); ocfs2_freefs(fs); return ret; } #ifdef DEBUG_EXE #include #include #include static int64_t read_number(const char *num) { int64_t val; char *ptr; val = strtoll(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: openfs [-s ] [-B ]\n" " \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; int c; int64_t blkno, blksize; char *filename; ocfs2_filesys *fs; /* These mean "autodetect" */ blksize = 0; blkno = 0; initialize_ocfs_error_table(); while((c = getopt(argc, argv, "s:B:")) != EOF) { switch (c) { case 's': blkno = read_number(optarg); if (blkno < OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid blkno: %s\n", optarg); print_usage(); return 1; } break; case 'B': blksize = read_number(optarg); if (blksize < OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blksize: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (blksize % OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blocksize: %"PRId64"\n", blksize); print_usage(); return 1; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, blkno, blksize, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } fprintf(stdout, "OCFS2 filesystem on \"%s\":\n", filename); fprintf(stdout, "\tblocksize = %d\n" "\tclustersize = %d\n" "\tclusters = %u\n" "\tblocks = %"PRIu64"\n" "\troot_blkno = %"PRIu64"\n" "\tsystem_dir_blkno = %"PRIu64"\n", fs->fs_blocksize, fs->fs_clustersize, fs->fs_clusters, fs->fs_blocks, fs->fs_root_blkno, fs->fs_sysdir_blkno); ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/slot_map.c0000664000176100017610000002711411170734140014450 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" /* Just so we can pass it about */ union ocfs2_slot_map_wrapper { struct ocfs2_slot_map *mw_map; struct ocfs2_slot_map_extended *mw_map_extended; }; void ocfs2_swap_slot_map(struct ocfs2_slot_map *sm, int num_slots) { int i; if (!cpu_is_big_endian) return; for (i = 0; i < num_slots; i++) sm->sm_slots[i] = bswap_16(sm->sm_slots[i]); } void ocfs2_swap_slot_map_extended(struct ocfs2_slot_map_extended *se, int num_slots) { int i; if (!cpu_is_big_endian) return; for (i = 0; i < num_slots; i++) se->se_slots[i].es_node_num = bswap_32(se->se_slots[i].es_node_num); } static errcode_t __ocfs2_read_slot_map(ocfs2_filesys *fs, int num_slots, union ocfs2_slot_map_wrapper *wrap) { errcode_t ret; uint64_t blkno; char *slot_map_buf; struct ocfs2_slot_map *sm; struct ocfs2_slot_map_extended *se; int bytes_needed, len; int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super)); ret = ocfs2_lookup_system_inode(fs, SLOT_MAP_SYSTEM_INODE, 0, &blkno); if (ret) return ret; ret = ocfs2_read_whole_file(fs, blkno, &slot_map_buf, &len); if (ret) return ret; if (extended) bytes_needed = num_slots * sizeof(struct ocfs2_extended_slot); else bytes_needed = num_slots * sizeof(__le16); if (bytes_needed > len) { ocfs2_free(&slot_map_buf); return OCFS2_ET_SHORT_READ; } if (extended) { se = (struct ocfs2_slot_map_extended *)slot_map_buf; ocfs2_swap_slot_map_extended(se, num_slots); wrap->mw_map_extended = se; } else { sm = (struct ocfs2_slot_map *)slot_map_buf; ocfs2_swap_slot_map(sm, num_slots); wrap->mw_map = sm; } return 0; } errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map **map_ret) { errcode_t ret; union ocfs2_slot_map_wrapper wrap = { .mw_map = NULL, }; ret = __ocfs2_read_slot_map(fs, num_slots, &wrap); if (ret) return ret; *map_ret = wrap.mw_map; return 0; } errcode_t ocfs2_read_slot_map_extended(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map_extended **map_ret) { errcode_t ret; union ocfs2_slot_map_wrapper wrap = { .mw_map_extended = NULL, }; ret = __ocfs2_read_slot_map(fs, num_slots, &wrap); if (ret) return ret; *map_ret = wrap.mw_map_extended; return 0; } static errcode_t __ocfs2_write_slot_map(ocfs2_filesys *fs, int num_slots, union ocfs2_slot_map_wrapper *wrap) { errcode_t ret, tret; ocfs2_cached_inode *ci = NULL; uint64_t blkno; unsigned int size, bytes, wrote, blocks; void *buf = NULL; int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super)); ret = ocfs2_lookup_system_inode(fs, SLOT_MAP_SYSTEM_INODE, 0, &blkno); if (ret) goto out; if (extended) size = num_slots * sizeof(struct ocfs2_extended_slot); else size = num_slots * sizeof(__le16); blocks = ocfs2_blocks_in_bytes(fs, size); bytes = blocks << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; ret = ocfs2_malloc_blocks(fs->fs_io, blocks, &buf); if (ret) goto out; memset(buf, 0, bytes); if (extended) { memcpy(buf, wrap->mw_map_extended, size); ocfs2_swap_slot_map_extended(buf, num_slots); } else { memcpy(buf, wrap->mw_map, size); ocfs2_swap_slot_map(buf, num_slots); } ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) goto out; ret = ocfs2_file_write(ci, buf, bytes, 0, &wrote); if (ret) goto out; /* * This is wacky. We have to write a block (bytes), but &wrote * might return only i_size (size). Handle both. */ if ((wrote != bytes) && (wrote != size)) ret = OCFS2_ET_SHORT_WRITE; out: if (ci) { tret = ocfs2_free_cached_inode(fs, ci); /* * The error from free_cached_inode() is only important if * there were no other problems. */ if (!ret) ret = tret; } if (buf) ocfs2_free(&buf); return ret; } errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map *sm) { union ocfs2_slot_map_wrapper wrap = { .mw_map = sm, }; return __ocfs2_write_slot_map(fs, num_slots, &wrap); } errcode_t ocfs2_write_slot_map_extended(ocfs2_filesys *fs, int num_slots, struct ocfs2_slot_map_extended *se) { union ocfs2_slot_map_wrapper wrap = { .mw_map_extended = se, }; return __ocfs2_write_slot_map(fs, num_slots, &wrap); } static void ocfs2_slot_map_to_data(ocfs2_filesys *fs, struct ocfs2_slot_map_data *md, union ocfs2_slot_map_wrapper *wrap) { int i; struct ocfs2_slot_map *sm = wrap->mw_map; struct ocfs2_slot_map_extended *se = wrap->mw_map_extended; int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super)); for (i = 0; i < md->md_num_slots; i++) { if (extended) { if (se->se_slots[i].es_valid) { md->md_slots[i].sd_valid = 1; md->md_slots[i].sd_node_num = se->se_slots[i].es_node_num; } else md->md_slots[i].sd_valid = 0; } else { if (sm->sm_slots[i] != (uint16_t)OCFS2_INVALID_SLOT) { md->md_slots[i].sd_valid = 1; md->md_slots[i].sd_node_num = sm->sm_slots[i]; } else md->md_slots[i].sd_valid = 0; } } } static void ocfs2_slot_data_to_map(ocfs2_filesys *fs, struct ocfs2_slot_map_data *md, union ocfs2_slot_map_wrapper *wrap) { int i; struct ocfs2_slot_map *sm = wrap->mw_map; struct ocfs2_slot_map_extended *se = wrap->mw_map_extended; int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super)); for (i = 0; i < md->md_num_slots; i++) { if (extended) { if (md->md_slots[i].sd_valid) { se->se_slots[i].es_valid = 1; se->se_slots[i].es_node_num = md->md_slots[i].sd_node_num; } else se->se_slots[i].es_valid = 0; } else { if (md->md_slots[i].sd_valid) sm->sm_slots[i] = (uint16_t)md->md_slots[i].sd_node_num; else sm->sm_slots[i] = (uint16_t)OCFS2_INVALID_SLOT; } } } static errcode_t ocfs2_alloc_slot_map_data(int num_slots, struct ocfs2_slot_map_data **md_ret) { errcode_t ret; struct ocfs2_slot_map_data *md; ret = ocfs2_malloc0(sizeof(struct ocfs2_slot_map_data) + (sizeof(struct ocfs2_slot_data) * num_slots), &md); if (ret) return ret; md->md_num_slots = num_slots; md->md_slots = (struct ocfs2_slot_data *)((char *)md + sizeof(struct ocfs2_slot_map_data)); *md_ret = md; return 0; } errcode_t ocfs2_load_slot_map(ocfs2_filesys *fs, struct ocfs2_slot_map_data **data_ret) { errcode_t ret; int num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;; struct ocfs2_slot_map_data *md; union ocfs2_slot_map_wrapper wrap = { .mw_map = NULL, }; ret = ocfs2_alloc_slot_map_data(num_slots, &md); if (ret) return ret; ret = __ocfs2_read_slot_map(fs, num_slots, &wrap); if (ret) { ocfs2_free(&md); return ret; } ocfs2_slot_map_to_data(fs, md, &wrap); *data_ret = md; return 0; } errcode_t ocfs2_store_slot_map(ocfs2_filesys *fs, struct ocfs2_slot_map_data *md) { errcode_t ret; char *slot_map_buf; int bytes; int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super)); union ocfs2_slot_map_wrapper wrap; if (extended) bytes = md->md_num_slots * sizeof(struct ocfs2_extended_slot); else bytes = md->md_num_slots * sizeof(__le16); ret = ocfs2_malloc0(bytes, &slot_map_buf); if (ret) return ret; wrap.mw_map = (struct ocfs2_slot_map *)slot_map_buf; ocfs2_slot_data_to_map(fs, md, &wrap); ret = __ocfs2_write_slot_map(fs, md->md_num_slots, &wrap); ocfs2_free(&slot_map_buf); return ret; } struct slotmap_format { int extended; int needed_slots; int actual_slots; unsigned int needed_bytes; ocfs2_cached_inode *ci; }; static errcode_t ocfs2_size_slot_map(ocfs2_filesys *fs, struct slotmap_format *sf) { errcode_t ret ; struct ocfs2_dinode *di; unsigned int clusters; uint64_t new_size; uint64_t blkno; di = sf->ci->ci_inode; blkno = sf->ci->ci_blkno; clusters = sf->needed_bytes + fs->fs_clustersize - 1; clusters = clusters >> OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; /* Zero slots not allowed - even local mounts have a slot */ if (!clusters) { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } /* * We ensure that slotmaps are formatted to the end of the * allocation. If the allocation hasn't changed, we don't have * anything to do. */ if (clusters == di->i_clusters) { ret = 0; goto out; } if (clusters > di->i_clusters) { ret = ocfs2_extend_allocation(fs, blkno, (clusters - di->i_clusters)); if (ret) goto out; /* We don't cache in the library right now, so any * work done in extend_allocation won't be reflected * in our now stale copy. */ ocfs2_free_cached_inode(fs, sf->ci); ret = ocfs2_read_cached_inode(fs, blkno, &sf->ci); if (ret) { sf->ci = NULL; goto out; } di = sf->ci->ci_inode; } else if (clusters < di->i_clusters) { new_size = clusters << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; ret = ocfs2_truncate(fs, blkno, new_size); if (ret) goto out; ocfs2_free_cached_inode(fs, sf->ci); ret = ocfs2_read_cached_inode(fs, blkno, &sf->ci); if (ret) { sf->ci = NULL; goto out; } di = sf->ci->ci_inode; } /* * Now that we've adjusted the allocation, write out the * correct i_size. By design, the slot map's i_size encompasses * the full allocation. */ di->i_size = di->i_clusters << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; di->i_mtime = time(NULL); ret = ocfs2_write_inode(fs, blkno, (char *)di); if (ret) goto out; out: return ret; } errcode_t ocfs2_format_slot_map(ocfs2_filesys *fs) { errcode_t ret; uint64_t blkno; struct slotmap_format sf; struct ocfs2_slot_map_data *md = NULL; ret = ocfs2_lookup_system_inode(fs, SLOT_MAP_SYSTEM_INODE, 0, &blkno); if (ret) goto out; ret = ocfs2_read_cached_inode(fs, blkno, &sf.ci); if (ret) goto out; /* verify it is a system file */ if (!(sf.ci->ci_inode->i_flags & OCFS2_VALID_FL) || !(sf.ci->ci_inode->i_flags & OCFS2_SYSTEM_FL)) { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } sf.extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super)); sf.needed_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; if (!sf.extended && (sf.needed_slots > OCFS2_MAX_SLOTS)) { ret = OCFS2_ET_TOO_MANY_SLOTS; goto out; } if (sf.extended) sf.needed_bytes = sf.needed_slots * sizeof(struct ocfs2_extended_slot); else sf.needed_bytes = sf.needed_slots * sizeof(__le16); ret = ocfs2_size_slot_map(fs, &sf); if (ret) goto out; if (sf.extended) sf.actual_slots = sf.ci->ci_inode->i_size / sizeof(struct ocfs2_extended_slot); else sf.actual_slots = sf.ci->ci_inode->i_size / sizeof(__le16); /* This returns an empty map that covers the entire allocation */ ret = ocfs2_alloc_slot_map_data(sf.actual_slots, &md); if (ret) return ret; ret = ocfs2_store_slot_map(fs, md); out: if (sf.ci) ocfs2_free_cached_inode(fs, sf.ci); if (md) ocfs2_free(&md); return ret; } ./ocfs2-tools-1.6.4/libocfs2/sysfile.c0000644000176100017610000000265611115551036014312 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * sysfile.c * * System inode operations for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include "ocfs2/ocfs2.h" errcode_t ocfs2_lookup_system_inode(ocfs2_filesys *fs, int type, int slot_num, uint64_t *blkno) { errcode_t ret; char *buf; ret = ocfs2_malloc0(sizeof(char) * (OCFS2_MAX_FILENAME_LEN + 1), &buf); if (ret) return ret; ocfs2_sprintf_system_inode_name(buf, OCFS2_MAX_FILENAME_LEN, type, slot_num); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, buf, strlen(buf), NULL, blkno); ocfs2_free(&buf); return ret; } ./ocfs2-tools-1.6.4/libocfs2/truncate.c0000644000176100017610000003174711500500544014460 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * truncate.c * * Truncate an OCFS2 inode. For the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #if HAVE_UNISTD_H #include #endif #include #include #include "ocfs2/ocfs2.h" struct truncate_ctxt { uint64_t ino; uint64_t new_size_in_clusters; uint32_t new_i_clusters; errcode_t (*free_clusters)(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno, void *free_data); void *free_data; }; static int ocfs2_truncate_clusters(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, uint64_t ino, uint32_t len, uint64_t start) { if (!ocfs2_refcount_tree(OCFS2_RAW_SB(fs->fs_super)) || !(rec->e_flags & OCFS2_EXT_REFCOUNTED)) return ocfs2_free_clusters(fs, len, start); assert(ino); return ocfs2_decrease_refcount(fs, ino, ocfs2_blocks_to_clusters(fs, start), len, 1); } /* * Delete and free clusters if needed. This only works with DEPTH_TRAVERSE. */ static int truncate_iterate(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { struct truncate_ctxt *ctxt = (struct truncate_ctxt *)priv_data; uint32_t len = 0, new_size_in_clusters = ctxt->new_size_in_clusters; uint64_t start = 0; errcode_t ret; int func_ret = OCFS2_EXTENT_ERROR; char *buf = NULL; struct ocfs2_extent_list *el = NULL; if ((rec->e_cpos + ocfs2_rec_clusters(tree_depth, rec)) <= new_size_in_clusters) return 0; if (rec->e_cpos >= new_size_in_clusters) { /* the rec is entirely outside the new size, free it */ if (!tree_depth) { start = rec->e_blkno; len = ocfs2_rec_clusters(tree_depth, rec); } else { /* here we meet with a full empty extent block, delete * it. The extent list it contains should already be * iterated and all the clusters have been freed. */ ret = ocfs2_delete_extent_block(fs, rec->e_blkno); if (ret) goto bail; } memset(rec, 0, sizeof(struct ocfs2_extent_rec)); } else { /* we're truncating into the middle of the rec */ len = rec->e_cpos + ocfs2_rec_clusters(tree_depth, rec); len -= new_size_in_clusters; if (!tree_depth) { ocfs2_set_rec_clusters(tree_depth, rec, new_size_in_clusters - rec->e_cpos); start = rec->e_blkno + ocfs2_clusters_to_blocks(fs, ocfs2_rec_clusters(tree_depth, rec)); } else { ocfs2_set_rec_clusters(tree_depth, rec, new_size_in_clusters - rec->e_cpos); /* * For a sparse file, we may meet with another * situation here: * The start of the left most extent rec is greater * than the new size we truncate the file to, but the * start of the extent block is less than that size. * In this case, actually all the extent records in * this extent block have been removed. So we have * to remove the extent block also. * In this function, we have to reread the extent list * to see whether the extent block is empty or not. */ ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_read_extent_block(fs, rec->e_blkno, buf); if (ret) goto bail; el = &((struct ocfs2_extent_block *)buf)->h_list; if (el->l_next_free_rec == 0) { ret = ocfs2_delete_extent_block(fs, rec->e_blkno); if (ret) goto bail; memset(rec, 0, sizeof(struct ocfs2_extent_rec)); } } } if (start) { if (ctxt->free_clusters) ret = ctxt->free_clusters(fs, len, start, ctxt->free_data); else ret = ocfs2_truncate_clusters(fs, rec, ctxt->ino, len, start); if (ret) goto bail; ctxt->new_i_clusters -= len; } func_ret = OCFS2_EXTENT_CHANGED; bail: if (buf) ocfs2_free(&buf); return func_ret; } /* * Zero the area past i_size but still within an allocated * cluster. This avoids exposing nonzero data on subsequent file * extends. */ static errcode_t ocfs2_zero_tail_for_truncate(ocfs2_cached_inode *ci, uint64_t new_size) { errcode_t ret; char *buf = NULL; ocfs2_filesys *fs = ci->ci_fs; uint64_t start_blk, p_blkno, contig_blocks, start_off; int count, byte_counts, bpc = fs->fs_clustersize /fs->fs_blocksize; uint16_t ext_flags; if (new_size == 0) return 0; start_blk = new_size / fs->fs_blocksize; ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1, &p_blkno, &contig_blocks, &ext_flags); if (ret) goto out; /* Tail is a hole. */ if (!p_blkno) goto out; if (ext_flags & OCFS2_EXT_REFCOUNTED) { uint32_t cpos = ocfs2_blocks_to_clusters(fs, start_blk); ret = ocfs2_refcount_cow(ci, cpos, 1, cpos + 1); if (ret) goto out; ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1, &p_blkno, &contig_blocks, &ext_flags); if (ret) goto out; assert(!(ext_flags & OCFS2_EXT_REFCOUNTED) && p_blkno); } /* calculate the total blocks we need to empty. */ count = bpc - (p_blkno & (bpc - 1)); ret = ocfs2_malloc_blocks(fs->fs_io, count, &buf); if (ret) goto out; ret = ocfs2_read_blocks(fs, p_blkno, count, buf); if (ret) goto out; /* empty the content after the new_size and within the same cluster. */ start_off = new_size % fs->fs_blocksize; byte_counts = count * fs->fs_blocksize - start_off; memset(buf + start_off, 0, byte_counts); ret = io_write_block(fs->fs_io, p_blkno, count, buf); out: if (buf) ocfs2_free(&buf); return ret; } /* * This function will truncate the file's cluster which exceeds * the cluster where new_size resides in and empty all the * bytes in the same cluster which exceeds new_size. */ static errcode_t ocfs2_zero_tail_and_truncate_full(ocfs2_filesys *fs, ocfs2_cached_inode *ci, uint64_t new_i_size, uint32_t *new_clusters, errcode_t (*free_clusters)(ocfs2_filesys *fs, uint32_t len, uint64_t start, void *free_data), void *free_data) { errcode_t ret; uint64_t new_size_in_blocks; struct truncate_ctxt ctxt; new_size_in_blocks = ocfs2_blocks_in_bytes(fs, new_i_size); ctxt.ino = ci->ci_blkno; ctxt.new_i_clusters = ci->ci_inode->i_clusters; ctxt.new_size_in_clusters = ocfs2_clusters_in_blocks(fs, new_size_in_blocks); ctxt.free_clusters = free_clusters; ctxt.free_data = free_data; ret = ocfs2_extent_iterate_inode(fs, ci->ci_inode, OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE, NULL, truncate_iterate, &ctxt); if (ret) goto out; ret = ocfs2_zero_tail_for_truncate(ci, new_i_size); if (ret) goto out; if (new_clusters) *new_clusters = ctxt.new_i_clusters; out: return ret; } errcode_t ocfs2_zero_tail_and_truncate(ocfs2_filesys *fs, ocfs2_cached_inode *ci, uint64_t new_i_size, uint32_t *new_clusters) { return ocfs2_zero_tail_and_truncate_full(fs, ci, new_i_size, new_clusters, NULL, NULL); } /* * NOTE: ocfs2_truncate_inline() also handles fast symlink, * since truncating for inline file and fasy symlink are * almost the same thing per se. */ errcode_t ocfs2_truncate_inline(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size) { errcode_t ret = 0; char *buf = NULL; struct ocfs2_dinode *di = NULL; struct ocfs2_inline_data *idata = NULL; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, ino, buf); if (ret) goto out_free_buf; di = (struct ocfs2_dinode *)buf; if (di->i_size < new_i_size) { ret = EINVAL; goto out_free_buf; } idata = &di->id2.i_data; if (!(di->i_dyn_features & OCFS2_INLINE_DATA_FL) && !(S_ISLNK(di->i_mode) && !di->i_clusters)) { ret = EINVAL; goto out_free_buf; } if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) memset(idata->id_data + new_i_size, 0, di->i_size - new_i_size); else memset(di->id2.i_symlink + new_i_size, 0, di->i_size - new_i_size); di->i_size = new_i_size; ret = ocfs2_write_inode(fs, ino, buf); out_free_buf: if (buf) ocfs2_free(&buf); return ret; } /* XXX care about zeroing new clusters and final partially truncated * clusters */ errcode_t ocfs2_truncate_full(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size, errcode_t (*free_clusters)(ocfs2_filesys *fs, uint32_t len, uint64_t start, void *free_data), void *free_data) { errcode_t ret; uint32_t new_clusters; ocfs2_cached_inode *ci = NULL; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto out; if (ci->ci_inode->i_size == new_i_size) goto out; if (ci->ci_inode->i_size < new_i_size) { ret = ocfs2_extend_file(fs, ino, new_i_size); goto out; } if ((S_ISLNK(ci->ci_inode->i_mode) && !ci->ci_inode->i_clusters) || (ci->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL)) ret = ocfs2_truncate_inline(fs, ino, new_i_size); else { ret = ocfs2_zero_tail_and_truncate_full(fs, ci, new_i_size, &new_clusters, free_clusters, free_data); if (ret) goto out; ci->ci_inode->i_clusters = new_clusters; /* now all the clusters and extent blocks are freed. * only when the file's content is empty, should the tree depth * change. */ if (new_clusters == 0) ci->ci_inode->id2.i_list.l_tree_depth = 0; ci->ci_inode->i_size = new_i_size; ret = ocfs2_write_cached_inode(fs, ci); } out: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } errcode_t ocfs2_truncate(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size) { return ocfs2_truncate_full(fs, ino, new_i_size, NULL, NULL); } errcode_t ocfs2_xattr_value_truncate(ocfs2_filesys *fs, uint64_t ino, struct ocfs2_xattr_value_root *xv) { struct truncate_ctxt ctxt; int changed; struct ocfs2_extent_list *el = &xv->xr_list; ctxt.ino = ino; ctxt.new_i_clusters = xv->xr_clusters; ctxt.new_size_in_clusters = 0; return ocfs2_extent_iterate_xattr(fs, el, xv->xr_last_eb_blk, OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE, truncate_iterate, &ctxt, &changed); } errcode_t ocfs2_xattr_tree_truncate(ocfs2_filesys *fs, struct ocfs2_xattr_tree_root *xt) { struct truncate_ctxt ctxt; int changed; struct ocfs2_extent_list *el = &xt->xt_list; /* * ino is used to find refcount tree, as we never use refcount * in xattr tree, so set it to 0. */ ctxt.ino = 0; ctxt.new_i_clusters = xt->xt_clusters; ctxt.new_size_in_clusters = 0; return ocfs2_extent_iterate_xattr(fs, el, xt->xt_last_eb_blk, OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE, truncate_iterate, &ctxt, &changed); } errcode_t ocfs2_dir_indexed_tree_truncate(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root) { struct truncate_ctxt ctxt; memset(&ctxt, 0, sizeof (struct truncate_ctxt)); ctxt.new_i_clusters = dx_root->dr_clusters; ctxt.new_size_in_clusters = 0; return ocfs2_extent_iterate_dx_root(fs, dx_root, OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE, NULL, truncate_iterate, &ctxt); } #ifdef DEBUG_EXE #include #include #include static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void print_usage(void) { fprintf(stderr, "Usage: debug_truncate -i -s device\n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; int c; uint64_t blkno = 0, new_size = 0; ocfs2_filesys *fs; char *device; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:s:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; case 's': new_size = read_number(optarg); break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing device name\n"); print_usage(); return 1; } device = argv[optind]; if (!blkno || !new_size) { print_usage(); return 1; } ret = ocfs2_open(device, OCFS2_FLAG_RW, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", device); return ret; } ret = ocfs2_truncate(fs, blkno, new_size); if (ret) com_err(argv[0], ret, "while truncating inode %"PRIu64, blkno); ocfs2_close(fs); return ret; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/unix_io.c0000644000176100017610000005505711453177334014323 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * unix_io.c * * I/O routines for the OCFS2 userspace library. * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Portions of this code from e2fsprogs/lib/ext2fs/unix_io.c * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, * 2002 by Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers ISOC99, UNIX98 in features.h */ #define _LARGEFILE64_SOURCE #define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */ #include #include #include #include #include #include #ifdef __linux__ #include #include #include #endif #include #include #include "ocfs2/kernel-rbtree.h" #include "ocfs2/ocfs2.h" /* * We do cached I/O in 1MB hunks, so we need this constant. */ #ifndef ONE_MEGABYTE # define ONE_MEGABYTE (1024 * 1024) #endif /* * The cache looks up blocks in two ways: * * 1) If it needs a new block, it gets one off of ic->ic_lru. The blocks * attach to that list via icb->icb_list. * * 2) If it wants to look up an existing block, it gets it from * ic->ic_lookup. The blocks are attached vai icb->icb_node. */ struct io_cache_block { struct rb_node icb_node; struct list_head icb_list; uint64_t icb_blkno; char *icb_buf; }; struct io_cache { size_t ic_nr_blocks; struct list_head ic_lru; struct rb_root ic_lookup; /* Housekeeping */ struct io_cache_block *ic_metadata_buffer; unsigned long ic_metadata_buffer_len; char *ic_data_buffer; unsigned long ic_data_buffer_len; int ic_locked; int ic_use_count; }; struct _io_channel { char *io_name; int io_blksize; int io_flags; int io_error; int io_fd; bool io_nocache; struct io_cache *io_cache; }; /* * We open code this because we don't have the ocfs2_filesys to call * ocfs2_blocks_in_bytes(). */ static inline int one_meg_of_blocks(io_channel *channel) { int count = ONE_MEGABYTE + channel->io_blksize - 1; return count / channel->io_blksize; } static errcode_t unix_io_read_block(io_channel *channel, int64_t blkno, int count, char *data) { int ret; ssize_t size, tot, rd; uint64_t location; /* -ative means count is in bytes */ size = (count < 0) ? -count : count * channel->io_blksize; location = blkno * channel->io_blksize; tot = 0; while (tot < size) { rd = pread64(channel->io_fd, data + tot, size - tot, location + tot); ret = OCFS2_ET_IO; if (rd < 0) { channel->io_error = errno; goto out; } if (!rd) goto out; tot += rd; } ret = 0; out: if (!ret && tot != size) { ret = OCFS2_ET_SHORT_READ; memset(data + tot, 0, size - tot); } return ret; } static errcode_t unix_io_write_block_full(io_channel *channel, int64_t blkno, int count, const char *data, int *completed) { int ret; ssize_t size, tot, wr; uint64_t location; /* -ative means count is in bytes */ size = (count < 0) ? -count : count * channel->io_blksize; location = blkno * channel->io_blksize; tot = 0; while (tot < size) { wr = pwrite64(channel->io_fd, data + tot, size - tot, location + tot); ret = OCFS2_ET_IO; if (wr < 0) { channel->io_error = errno; goto out; } if (!wr) goto out; tot += wr; } ret = 0; out: if (completed) *completed = tot / channel->io_blksize; if (!ret && (tot != size)) ret = OCFS2_ET_SHORT_WRITE; return ret; } static errcode_t unix_io_write_block(io_channel *channel, int64_t blkno, int count, const char *data) { return unix_io_write_block_full(channel, blkno, count, data, NULL); } /* * See if the rbtree has a block for the given block number. * * The rb_node garbage lets insertion share the search. Trivial callers * pass NULL. */ static struct io_cache_block *io_cache_lookup(struct io_cache *ic, uint64_t blkno) { struct rb_node *p = ic->ic_lookup.rb_node; struct io_cache_block *icb; while (p) { icb = rb_entry(p, struct io_cache_block, icb_node); if (blkno < icb->icb_blkno) { p = p->rb_left; } else if (blkno > icb->icb_blkno) { p = p->rb_right; } else return icb; } return NULL; } static void io_cache_insert(struct io_cache *ic, struct io_cache_block *insert_icb) { struct rb_node **p = &ic->ic_lookup.rb_node; struct rb_node *parent = NULL; struct io_cache_block *icb = NULL; while (*p) { parent = *p; icb = rb_entry(parent, struct io_cache_block, icb_node); if (insert_icb->icb_blkno < icb->icb_blkno) { p = &(*p)->rb_left; icb = NULL; } else if (insert_icb->icb_blkno > icb->icb_blkno) { p = &(*p)->rb_right; icb = NULL; } else assert(0); /* We erased it, remember? */ } rb_link_node(&insert_icb->icb_node, parent, p); rb_insert_color(&insert_icb->icb_node, &ic->ic_lookup); } static void io_cache_seen(struct io_cache *ic, struct io_cache_block *icb) { /* Move to the front of the LRU */ list_del(&icb->icb_list); list_add_tail(&icb->icb_list, &ic->ic_lru); } static void io_cache_unsee(struct io_cache *ic, struct io_cache_block *icb) { /* * Move to the end of the LRU. There's no point in removing an * "unseen" buffer from the cache. It's valid, but we want the * next I/O to steal it. */ list_del(&icb->icb_list); list_add(&icb->icb_list, &ic->ic_lru); } static void io_cache_disconnect(struct io_cache *ic, struct io_cache_block *icb) { /* * This icb should longer be looked up. * If icb->icb_blkno is UINT64_MAX, it's already disconnected. */ if (icb->icb_blkno != UINT64_MAX) { rb_erase(&icb->icb_node, &ic->ic_lookup); memset(&icb->icb_node, 0, sizeof(struct rb_node)); icb->icb_blkno = UINT64_MAX; } } static struct io_cache_block *io_cache_pop_lru(struct io_cache *ic) { struct io_cache_block *icb; icb = list_entry(ic->ic_lru.next, struct io_cache_block, icb_list); io_cache_disconnect(ic, icb); return icb; } /* * This relies on the fact that our cache is always up to date. If a * block is in the cache, the same thing is on disk. Even if we re-read * the disk block, we don't need to update the cache. This allows us * to look for optimal I/O sizes; it's better to call one read 1MB of * half-cached blocks than to read every other block. * * If the caller specifies "nocache", we still want to give them anything * we found in the cache, but we want cached blocks moved to the front * of the LRU. That way they get stolen first. */ static errcode_t io_cache_read_blocks(io_channel *channel, int64_t blkno, int count, char *data, bool nocache) { int i, good_blocks; errcode_t ret = 0; struct io_cache *ic = channel->io_cache; struct io_cache_block *icb; /* * Here we check two things: * * 1) Are all the blocks cached? If so, we can skip I/O. * 2) If they are not all cached, we want to start our read at the * first uncached blkno. */ for (good_blocks = 0; good_blocks < count; good_blocks++) { icb = io_cache_lookup(ic, blkno + good_blocks); if (!icb) break; } /* Read any blocks not in the cache */ if (good_blocks < count) { ret = unix_io_read_block(channel, blkno + good_blocks, count - good_blocks, data + (channel->io_blksize * good_blocks)); if (ret) goto out; } /* Now we sync up the cache with the data buffer */ for (i = 0; i < count; i++, data += channel->io_blksize) { icb = io_cache_lookup(ic, blkno + i); if (i < good_blocks) { /* * We skipped reading this because it was in the * cache. Copy it to the data buffer. */ assert(icb); memcpy(data, icb->icb_buf, channel->io_blksize); } else if (!icb) { if (nocache) continue; /* Steal the LRU buffer */ icb = io_cache_pop_lru(ic); icb->icb_blkno = blkno + i; io_cache_insert(ic, icb); /* * We did I/O into the data buffer, now update * the cache. */ memcpy(icb->icb_buf, data, channel->io_blksize); } /* * What about if ((i >= good_blocks) && icb)? That means * we had the buffer in the cache, but we read it anyway * to get a single I/O. Our cache guarantees that the * contents will match, so we just skip to marking the * buffer seen. */ if (nocache) io_cache_unsee(ic, icb); else io_cache_seen(ic, icb); } out: return ret; } static errcode_t io_cache_read_block(io_channel *channel, int64_t blkno, int count, char *data, bool nocache) { int todo = one_meg_of_blocks(channel); errcode_t ret = 0; /* * We do this in one meg hunks so that each hunk has an * opportunity to be in cache, but we get a good throughput. */ while (count) { if (todo > count) todo = count; ret = io_cache_read_blocks(channel, blkno, todo, data, nocache); if (ret) break; blkno += todo; count -= todo; data += (channel->io_blksize * todo); } return ret; } /* * This relies on the fact that our cache is always up to date. If a * block is in the cache, the same thing is on disk. So here we'll write * a whole stream and update the cache as needed. */ static errcode_t io_cache_write_blocks(io_channel *channel, int64_t blkno, int count, const char *data, bool nocache) { int i, completed = 0; errcode_t ret; struct io_cache *ic = channel->io_cache; struct io_cache_block *icb; /* Get the write out of the way */ ret = unix_io_write_block_full(channel, blkno, count, data, &completed); /* * Now we sync up the cache with the data buffer. We have * to sync up I/O that completed, even if the entire I/O did not. * * In the nocache case, we want to skip blocks that weren't in the * cache, but we want to update blocks that where. Even though * the caller specified "don't cache this", it's already in the * cache. We don't want stale data. */ for (i = 0; i < completed; i++, data += channel->io_blksize) { icb = io_cache_lookup(ic, blkno + i); if (!icb) { if (nocache) continue; /* * Steal the LRU buffer. We can't error here, so * we can safely insert it before we copy the data. */ icb = io_cache_pop_lru(ic); icb->icb_blkno = blkno + i; io_cache_insert(ic, icb); } memcpy(icb->icb_buf, data, channel->io_blksize); if (nocache) io_cache_unsee(ic, icb); else io_cache_seen(ic, icb); } return ret; } static errcode_t io_cache_write_block(io_channel *channel, int64_t blkno, int count, const char *data, bool nocache) { /* * Unlike io_read_cache_block(), we're going to do all of the * I/O no matter what. We keep the separation of * io_cache_write_block() and io_cache_write_blocks() for * consistency. */ return io_cache_write_blocks(channel, blkno, count, data, nocache); } static void io_free_cache(struct io_cache *ic) { if (ic) { if (ic->ic_data_buffer) { if (ic->ic_locked) munlock(ic->ic_data_buffer, ic->ic_data_buffer_len); ocfs2_free(&ic->ic_data_buffer); } if (ic->ic_metadata_buffer) { if (ic->ic_locked) munlock(ic->ic_metadata_buffer, ic->ic_metadata_buffer_len); ocfs2_free(&ic->ic_metadata_buffer); } ocfs2_free(&ic); } } void io_destroy_cache(io_channel *channel) { if (channel->io_cache) { if (!--channel->io_cache->ic_use_count) io_free_cache(channel->io_cache); channel->io_cache = NULL; } } /* * A cache is kind of pointless if it is swappable, right? Let's give * applications the ability to pin the cache memory. This is a separate * call from io_init_cache() because non-privileged users can't do it, and * they still want to create small caches. */ errcode_t io_mlock_cache(io_channel *channel) { int rc; struct io_cache *ic = channel->io_cache; long pages_wanted, avpages; if (!ic) return OCFS2_ET_INVALID_ARGUMENT; if (ic->ic_locked) return 0; /* * We're going to lock our cache pages. We don't want to * request more memory than the system has, though. */ pages_wanted = channel->io_blksize * ic->ic_nr_blocks / getpagesize(); avpages = sysconf(_SC_AVPHYS_PAGES); if (pages_wanted > avpages) return OCFS2_ET_NO_MEMORY; rc = mlock(ic->ic_data_buffer, ic->ic_data_buffer_len); if (!rc) { rc = mlock(ic->ic_metadata_buffer, ic->ic_metadata_buffer_len); if (rc) munlock(ic->ic_data_buffer, ic->ic_data_buffer_len); } if (rc) return OCFS2_ET_NO_MEMORY; ic->ic_locked = 1; return 0; } errcode_t io_init_cache(io_channel *channel, size_t nr_blocks) { int i; struct io_cache *ic; char *dbuf; struct io_cache_block *icb_list; errcode_t ret; ret = ocfs2_malloc0(sizeof(struct io_cache), &ic); if (ret) goto out; ic->ic_nr_blocks = nr_blocks; ic->ic_lookup = RB_ROOT; INIT_LIST_HEAD(&ic->ic_lru); ret = ocfs2_malloc_blocks(channel, nr_blocks, &ic->ic_data_buffer); if (ret) goto out; ic->ic_data_buffer_len = (unsigned long)nr_blocks * channel->io_blksize; ret = ocfs2_malloc0(sizeof(struct io_cache_block) * nr_blocks, &ic->ic_metadata_buffer); if (ret) goto out; ic->ic_metadata_buffer_len = (unsigned long)nr_blocks * sizeof(struct io_cache_block); icb_list = ic->ic_metadata_buffer; dbuf = ic->ic_data_buffer; for (i = 0; i < nr_blocks; i++) { icb_list[i].icb_blkno = UINT64_MAX; icb_list[i].icb_buf = dbuf; dbuf += channel->io_blksize; list_add_tail(&icb_list[i].icb_list, &ic->ic_lru); } ic->ic_use_count = 1; channel->io_cache = ic; out: if (ret) io_free_cache(ic); return ret; } errcode_t io_init_cache_size(io_channel *channel, size_t bytes) { size_t blocks; blocks = (bytes + (channel->io_blksize - 1)) / channel->io_blksize; return io_init_cache(channel, blocks); } errcode_t io_share_cache(io_channel *from, io_channel *to) { if (!from->io_cache) return OCFS2_ET_INTERNAL_FAILURE; if (to->io_cache) return OCFS2_ET_INTERNAL_FAILURE; to->io_cache = from->io_cache; from->io_cache->ic_use_count++; return 0; } static errcode_t io_validate_o_direct(io_channel *channel) { errcode_t ret = OCFS2_ET_UNEXPECTED_BLOCK_SIZE; int block_size; char *blk; for (block_size = io_get_blksize(channel); block_size <= OCFS2_MAX_BLOCKSIZE; block_size <<= 1) { io_set_blksize(channel, block_size); ret = ocfs2_malloc_block(channel, &blk); if (ret) break; ret = unix_io_read_block(channel, 0, 1, blk); ocfs2_free(&blk); if (!ret) break; } return ret; } errcode_t io_open(const char *name, int flags, io_channel **channel) { errcode_t ret; io_channel *chan = NULL; #ifdef __linux__ struct stat stat_buf; struct utsname ut; #endif if (!name || !*name) return OCFS2_ET_BAD_DEVICE_NAME; ret = ocfs2_malloc0(sizeof(struct _io_channel), &chan); if (ret) return ret; ret = ocfs2_malloc(strlen(name)+1, &chan->io_name); if (ret) goto out_chan; strcpy(chan->io_name, name); chan->io_blksize = OCFS2_MIN_BLOCKSIZE; chan->io_flags = (flags & OCFS2_FLAG_RW) ? O_RDWR : O_RDONLY; chan->io_nocache = false; if (!(flags & OCFS2_FLAG_BUFFERED)) chan->io_flags |= O_DIRECT; chan->io_error = 0; chan->io_fd = open64(name, chan->io_flags); if (chan->io_fd < 0) { /* chan will be freed, don't bother with chan->io_error */ if (errno == ENOENT) ret = OCFS2_ET_NAMED_DEVICE_NOT_FOUND; else ret = OCFS2_ET_IO; goto out_name; } if (!(flags & OCFS2_FLAG_BUFFERED)) { ret = io_validate_o_direct(chan); if (ret) goto out_close; /* FIXME: bindraw here */ } /* Workaround from e2fsprogs */ #ifdef __linux__ #undef RLIM_INFINITY #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) #define RLIM_INFINITY ((unsigned long)(~0UL>>1)) #else #define RLIM_INFINITY (~0UL) #endif /* * Work around a bug in 2.4.10-2.4.18 kernels where writes to * block devices are wrongly getting hit by the filesize * limit. This workaround isn't perfect, since it won't work * if glibc wasn't built against 2.2 header files. (Sigh.) * */ if ((flags & OCFS2_FLAG_RW) && (uname(&ut) == 0) && ((ut.release[0] == '2') && (ut.release[1] == '.') && (ut.release[2] == '4') && (ut.release[3] == '.') && (ut.release[4] == '1') && (ut.release[5] >= '0') && (ut.release[5] < '8')) && (fstat(chan->io_fd, &stat_buf) == 0) && (S_ISBLK(stat_buf.st_mode))) { struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; setrlimit(RLIMIT_FSIZE, &rlim); getrlimit(RLIMIT_FSIZE, &rlim); if (((unsigned long) rlim.rlim_cur) < ((unsigned long) rlim.rlim_max)) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_FSIZE, &rlim); } } #endif *channel = chan; return 0; out_close: /* Ignore the return, leave the original error */ close(chan->io_fd); out_name: ocfs2_free(&chan->io_name); out_chan: ocfs2_free(&chan); *channel = NULL; return ret; } errcode_t io_close(io_channel *channel) { errcode_t ret = 0; io_destroy_cache(channel); if (close(channel->io_fd) < 0) ret = errno; ocfs2_free(&channel->io_name); ocfs2_free(&channel); return ret; } int io_get_error(io_channel *channel) { return channel->io_error; } errcode_t io_set_blksize(io_channel *channel, int blksize) { if (blksize % OCFS2_MIN_BLOCKSIZE) return OCFS2_ET_INVALID_ARGUMENT; if (!blksize) blksize = OCFS2_MIN_BLOCKSIZE; if (channel->io_blksize != blksize) channel->io_blksize = blksize; return 0; } int io_get_blksize(io_channel *channel) { return channel->io_blksize; } int io_get_fd(io_channel *channel) { return channel->io_fd; } /* * If a channel is set to 'nocache', it will use the _nocache() functions * even if called via the regular functions. This allows control of * naive code that we don't want to have to carry nocache parameters * around. Smarter code can ignore this function and use the _nocache() * functions directly. */ void io_set_nocache(io_channel *channel, bool nocache) { channel->io_nocache = nocache; } errcode_t io_read_block(io_channel *channel, int64_t blkno, int count, char *data) { if (channel->io_cache) return io_cache_read_block(channel, blkno, count, data, channel->io_nocache); else return unix_io_read_block(channel, blkno, count, data); } errcode_t io_read_block_nocache(io_channel *channel, int64_t blkno, int count, char *data) { if (channel->io_cache) return io_cache_read_block(channel, blkno, count, data, true); else return unix_io_read_block(channel, blkno, count, data); } errcode_t io_write_block(io_channel *channel, int64_t blkno, int count, const char *data) { if (channel->io_cache) return io_cache_write_block(channel, blkno, count, data, channel->io_nocache); else return unix_io_write_block(channel, blkno, count, data); } errcode_t io_write_block_nocache(io_channel *channel, int64_t blkno, int count, const char *data) { if (channel->io_cache) return io_cache_write_block(channel, blkno, count, data, true); else return unix_io_write_block(channel, blkno, count, data); } #ifdef DEBUG_EXE #include #include #include #include static int64_t read_number(const char *num) { int64_t val; char *ptr; val = strtoll(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } static void dump_u32(uint32_t *val) { unsigned int i; uint8_t *bytes = (uint8_t *)val; for (i = 0; i < sizeof(uint32_t); i++) fprintf(stdout, "%02X", bytes[i]); } static void dump_block(int64_t blkno, int blksize, char *buf) { size_t i; uint32_t *vals = (uint32_t *)buf; fprintf(stdout, "Dumping block %"PRId64" (%d bytes):\n", blkno, blksize); for (i = 0; i < (blksize / sizeof(uint32_t)); i++) { if (!(i % 4)) { if (i) fprintf(stdout, "\n"); fprintf(stdout, "0x%08zu\t", i * sizeof(uint32_t)); } dump_u32(&vals[i]); fprintf(stdout, " "); } fprintf(stdout, "\n"); } static void print_usage(void) { fprintf(stderr, "Usage: unix_io [-b ] [-c ] [-B ]\n" " \n"); } extern int opterr, optind; extern char *optarg; int main(int argc, char *argv[]) { errcode_t ret; int c; int64_t blkno, count, blksize; char *filename; io_channel *channel; char *blks; /* Some simple defaults */ blksize = 512; blkno = 0; count = 1; initialize_ocfs_error_table(); while((c = getopt(argc, argv, "b:c:B:")) != EOF) { switch (c) { case 'b': blkno = read_number(optarg); if (blkno < 0) { fprintf(stderr, "Invalid blkno: %s\n", optarg); print_usage(); return 1; } break; case 'c': count = read_number(optarg); if (!count) { fprintf(stderr, "Invalid count: %s\n", optarg); print_usage(); return 1; } break; case 'B': blksize = read_number(optarg); if (!blksize) { fprintf(stderr, "Invalid blksize: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (blksize % OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blocksize: %"PRId64"\n", blksize); print_usage(); return 1; } if (count < 0) { if (-count > (int64_t)INT_MAX) { fprintf(stderr, "Count is too large: %"PRId64"\n", count); print_usage(); return 1; } count = -count / blksize; } else { if ((count * blksize) > INT_MAX) { fprintf(stderr, "Count is too large: %"PRId64"\n", count); print_usage(); return 1; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = io_open(filename, OCFS2_FLAG_RO, &channel); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_blocks(channel, (int)count, &blks); if (ret) { com_err(argv[0], ret, "while allocating %"PRId64" blocks", count); goto out_channel; } ret = io_read_block(channel, blkno, (int)count, blks); if (ret) { com_err(argv[0], ret, "while reading %"PRId64" blocks at block %"PRId64" (%s)", count, blkno, strerror(io_get_error(channel))); goto out_blocks; } for (c = 0; c < count; c++) dump_block(blkno + c, blksize, blks + (c * blksize)); out_blocks: ocfs2_free(&blks); out_channel: ret = io_close(channel); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/unlink.c0000644000176100017610000001336311500500544014125 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * unlink.c * * Remove an entry from an OCFS2 directory. For the OCFS2 userspace * library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * This code is a port of e2fsprogs/lib/ext2fs/unlink.c * Copyright (C) 1993, 1994, 1997 Theodore Ts'o. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/ocfs2.h" struct link_struct { const char *name; int namelen; uint64_t inode; int flags; int done; }; #ifdef __TURBOC__ #pragma argsused #endif static int unlink_proc(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct link_struct *ls = (struct link_struct *) priv_data; if (ls->name && ((dirent->name_len & 0xFF) != ls->namelen)) return 0; if (ls->name && strncmp(ls->name, dirent->name, dirent->name_len & 0xFF)) return 0; if (ls->inode && (dirent->inode != ls->inode)) return 0; dirent->inode = 0; ls->done++; return OCFS2_DIRENT_ABORT|OCFS2_DIRENT_CHANGED; } static errcode_t ocfs2_unlink_el(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, int flags) { errcode_t ret; struct link_struct ls; ls.name = name; ls.namelen = name ? strlen(name) : 0; ls.inode = ino; ls.flags = 0; ls.done = 0; ret = ocfs2_dir_iterate(fs, dir, 0, 0, unlink_proc, &ls); if (ret) goto out; if (!ls.done) ret = OCFS2_ET_DIR_NO_SPACE; out: return ret; } static errcode_t __ocfs2_delete_entry(ocfs2_filesys *fs, struct ocfs2_dir_entry *de_del, char *dir_buf) { struct ocfs2_dir_entry *de, *pde; int offset = 0; errcode_t ret = 0; pde = NULL; de = (struct ocfs2_dir_entry *)dir_buf; while( offset < fs->fs_blocksize) { if (!ocfs2_check_dir_entry(fs, de, dir_buf, offset)) { ret = OCFS2_ET_DIR_CORRUPTED; goto out; } if (de == de_del) { if (pde) pde->rec_len += de->rec_len; else de->inode = 0; goto out; } if (de->rec_len <= 0) { ret = OCFS2_ET_DIR_CORRUPTED; goto out; } pde = de; offset += de->rec_len; de = (struct ocfs2_dir_entry *)((char *)de + de->rec_len); } out: return ret; } static errcode_t ocfs2_unlink_dx(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, int flags) { char *di_buf = NULL, *dx_root_buf = NULL; struct ocfs2_dinode *di; struct ocfs2_dx_root_block *dx_root; struct ocfs2_dx_entry_list *entry_list; struct ocfs2_dir_block_trailer *trailer; int write_dx_leaf = 0; int add_to_free_list = 0; int max_rec_len = 0; struct ocfs2_dir_lookup_result lookup; errcode_t ret; assert(name); ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; ret = ocfs2_malloc_block(fs->fs_io, &dx_root_buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, di->i_dx_root, dx_root_buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)dx_root_buf; memset(&lookup, 0, sizeof(struct ocfs2_dir_lookup_result)); ret= ocfs2_dx_dir_search(fs, name, strlen(name), dx_root, &lookup); if (ret) goto out; trailer = ocfs2_dir_trailer_from_block(fs, lookup.dl_leaf); if (trailer->db_free_rec_len == 0) add_to_free_list = 1; ret = __ocfs2_delete_entry(fs, lookup.dl_entry, lookup.dl_leaf); if (ret) goto out; max_rec_len = ocfs2_find_max_rec_len(fs, lookup.dl_leaf); trailer->db_free_rec_len = max_rec_len; if (add_to_free_list) { trailer->db_free_next = dx_root->dr_free_blk; dx_root->dr_free_blk = lookup.dl_leaf_blkno; } ret = ocfs2_write_dir_block(fs, di, lookup.dl_leaf_blkno, lookup.dl_leaf); if (ret) goto out; if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) entry_list = &dx_root->dr_entries; else { entry_list = &(lookup.dl_dx_leaf->dl_list); write_dx_leaf = 1; } ocfs2_dx_list_remove_entry(entry_list, lookup.dl_dx_entry_idx); if (write_dx_leaf) { ret = ocfs2_write_dx_leaf(fs, lookup.dl_dx_leaf_blkno, lookup.dl_dx_leaf); if (ret) goto out; } dx_root->dr_num_entries --; ret = ocfs2_write_dx_root(fs, di->i_dx_root, dx_root_buf); if (ret) goto out; ret = ocfs2_write_inode(fs, di->i_blkno, di_buf); out: release_lookup_res(&lookup); if (dx_root_buf) ocfs2_free(&dx_root_buf); if (di_buf) ocfs2_free(&di_buf); return ret; } #ifdef __TURBOC__ #pragma argsused #endif errcode_t ocfs2_unlink(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, int flags) { errcode_t ret; char *di_buf = NULL; struct ocfs2_dinode *di; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)) && (ocfs2_dir_indexed(di))) ret = ocfs2_unlink_dx(fs, dir, name, ino, flags); else ret = ocfs2_unlink_el(fs, dir, name, ino, flags); out: if (di_buf) ocfs2_free(&di_buf); return ret; } ./ocfs2-tools-1.6.4/libocfs2/lockid.c0000664000176100017610000000743411336564244014114 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * lockid.c * * Encode and decode lockres name * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include #include enum ocfs2_lock_type ocfs2_get_lock_type(char c) { switch (c) { case 'M': return OCFS2_LOCK_TYPE_META; case 'D': return OCFS2_LOCK_TYPE_DATA; case 'S': return OCFS2_LOCK_TYPE_SUPER; case 'R': return OCFS2_LOCK_TYPE_RENAME; case 'W': return OCFS2_LOCK_TYPE_RW; case 'N': return OCFS2_LOCK_TYPE_DENTRY; case 'O': return OCFS2_LOCK_TYPE_OPEN; case 'F': return OCFS2_LOCK_TYPE_FLOCK; default: return OCFS2_NUM_LOCK_TYPES; } } /* * This function encodes the lockname just like the filesystem. Meaning * the dentry lock gets encoded in its binary form. */ errcode_t ocfs2_encode_lockres(enum ocfs2_lock_type type, uint64_t blkno, uint32_t generation, uint64_t parent, char *lockres) { uint64_t b; if (type >= OCFS2_NUM_LOCK_TYPES) return OCFS2_ET_INVALID_LOCKRES; blkno = (type == OCFS2_LOCK_TYPE_RENAME) ? 0 : blkno; generation = ((type == OCFS2_LOCK_TYPE_SUPER) || (type == OCFS2_LOCK_TYPE_RENAME)) ? 0 : generation; if (type != OCFS2_LOCK_TYPE_DENTRY) { snprintf(lockres, OCFS2_LOCK_ID_MAX_LEN, "%c%s%016"PRIx64"%08x", ocfs2_lock_type_char(type), OCFS2_LOCK_ID_PAD, blkno, generation); } else { snprintf(lockres, OCFS2_DENTRY_LOCK_INO_START, "%c%016llx", ocfs2_lock_type_char(OCFS2_LOCK_TYPE_DENTRY), (long long)parent); b = bswap_64(blkno); memcpy(&lockres[OCFS2_DENTRY_LOCK_INO_START], &b, sizeof(b)); } return 0; } errcode_t ocfs2_decode_lockres(char *lockres, enum ocfs2_lock_type *type, uint64_t *blkno, uint32_t *generation, uint64_t *parent) { int i = 0; enum ocfs2_lock_type t; char *l = lockres; uint64_t b = 0; uint64_t p = 0; uint32_t g = 0; if ((t = ocfs2_get_lock_type(*l)) >= OCFS2_NUM_LOCK_TYPES) return OCFS2_ET_INVALID_LOCKRES; if (t != OCFS2_LOCK_TYPE_DENTRY) { i = sscanf(l + 1, OCFS2_LOCK_ID_PAD"%016llx%08x", &b, &g); if (i != 2) return OCFS2_ET_INVALID_LOCKRES; } else { i = sscanf(l + 1, "%016llx", &p); if (i != 1) return OCFS2_ET_INVALID_LOCKRES; b = strtoull(&l[OCFS2_DENTRY_LOCK_INO_START], NULL, 16); } if (type) *type = t; if (blkno) *blkno = b; if (generation) *generation = g; if (parent) *parent = p; return 0; } /* * This function is useful when printing the dentry lock. It converts the * dentry lockname into a string using the same scheme as used in dlmglue. */ errcode_t ocfs2_printable_lockres(char *lockres, char *name, int len) { uint64_t b; memset(name, 0, len); if (ocfs2_get_lock_type(*lockres) >= OCFS2_NUM_LOCK_TYPES) return OCFS2_ET_INVALID_LOCKRES; if (ocfs2_get_lock_type(*lockres) == OCFS2_LOCK_TYPE_DENTRY) { memcpy((uint64_t *)&b, (char *)&lockres[OCFS2_DENTRY_LOCK_INO_START], sizeof(uint64_t)); snprintf(name, len, "%.*s%08x", OCFS2_DENTRY_LOCK_INO_START - 1, lockres, (unsigned int)bswap_64(b)); } else snprintf(name, len, "%s", lockres); return 0; } ./ocfs2-tools-1.6.4/libocfs2/backup_super.c0000664000176100017610000001250111170734140015307 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * backup_super.c * * Backup superblocks for an OCFS2 volume. * * Copyright (C) 2006 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #include #include "ocfs2/ocfs2.h" /* In case we don't have fs_blocksize, we will return * byte offsets and let the caller calculate them by itself. */ int ocfs2_get_backup_super_offsets(ocfs2_filesys *fs, uint64_t *offsets, size_t len) { size_t i; uint64_t blkno; uint32_t blocksize; memset(offsets, 0, sizeof(uint64_t) * len); len = ocfs2_min(len, (size_t)OCFS2_MAX_BACKUP_SUPERBLOCKS); if (fs) blocksize = fs->fs_blocksize; else blocksize = 1; for (i = 0; i < len; i++) { blkno = ocfs2_backup_super_blkno(blocksize, i); if (fs && fs->fs_blocks <= blkno) break; offsets[i] = blkno; } return i; } errcode_t ocfs2_clear_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len) { size_t i; errcode_t ret = 0; if (!len || !blocks || !*blocks) goto bail; len = ocfs2_min(len,(size_t)OCFS2_MAX_BACKUP_SUPERBLOCKS); /* * Don't clear anything if backup superblocks aren't enabled - * there might be real data there! If backup superblocks are * enabled, we know these blocks are backups, and we're * safe to clear them. */ if (!OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB)) goto bail; for (i = 0; i < len; i++) { ret = ocfs2_free_clusters(fs, 1, blocks[i]); if (ret) break; } bail: return ret; } static errcode_t check_cluster(ocfs2_filesys *fs, uint32_t cpos) { errcode_t ret; int val; ret = ocfs2_test_cluster_allocated(fs, cpos, &val); if (ret) goto bail; if (val) { ret = ENOSPC; goto bail; } ret = 0; bail: return ret; } errcode_t ocfs2_set_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len) { size_t i; errcode_t ret = 0; char *buf = NULL; uint64_t *blkno = blocks; uint32_t cluster, bpc = fs->fs_clustersize / fs->fs_blocksize; if (!len || !blocks || !*blocks) goto bail; len = ocfs2_min(len,(size_t)OCFS2_MAX_BACKUP_SUPERBLOCKS); if (!OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB)) { /* check all the blkno to see whether it is used. */ for (i = 0; i < len; i++, blkno++) { ret = check_cluster(fs, ocfs2_blocks_to_clusters(fs, *blkno)); if (ret) goto bail; } } ret = ocfs2_malloc_blocks(fs->fs_io, bpc, &buf); if (ret) goto bail; memset(buf, 0, fs->fs_clustersize); /* zero all the clusters at first */ blkno = blocks; for (i = 0; i < len; i++, blkno++) { cluster = ocfs2_blocks_to_clusters(fs, *blkno); ret = io_write_block(fs->fs_io, cluster*bpc, bpc, buf); if (ret) goto bail; } ret = ocfs2_refresh_backup_super_list(fs, blocks, len); if (ret) goto bail; /* We just tested the clusters, so the allocation can't fail */ blkno = blocks; for (i = 0; i < len; i++, blkno++) ocfs2_new_specific_cluster(fs, ocfs2_blocks_to_clusters(fs, *blkno)); bail: if (buf) ocfs2_free(&buf); return ret; } errcode_t ocfs2_refresh_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len) { errcode_t ret = 0; size_t i; for (i = 0; i < len; i++, blocks++) { ret = ocfs2_write_backup_super(fs, *blocks); if (ret) goto bail; } bail: return ret; } errcode_t ocfs2_refresh_backup_supers(ocfs2_filesys *fs) { int num; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; if (!OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB)) return 0; /* Do nothing */ num = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); return num ? ocfs2_refresh_backup_super_list(fs, blocks, num) : 0; } errcode_t ocfs2_read_backup_super(ocfs2_filesys *fs, int backup, char *sbbuf) { int numsb; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; if (!OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB)) return OCFS2_ET_NO_BACKUP_SUPER; numsb = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); if (backup < 1 || backup > numsb) return OCFS2_ET_NO_BACKUP_SUPER; return ocfs2_read_super(fs, blocks[backup], sbbuf); } /* These were terrible names, don't use them */ int ocfs2_get_backup_super_offset(ocfs2_filesys *fs, uint64_t *offsets, size_t len) { return ocfs2_get_backup_super_offsets(fs, offsets, len); } errcode_t ocfs2_refresh_backup_super(ocfs2_filesys *fs, uint64_t *blocks, size_t len) { return ocfs2_refresh_backup_super_list(fs, blocks, len); } errcode_t ocfs2_set_backup_super(ocfs2_filesys *fs, uint64_t *blocks, size_t len) { return ocfs2_set_backup_super_list(fs, blocks, len); } ./ocfs2-tools-1.6.4/libocfs2/feature_string.c0000664000176100017610000006152211506552637015670 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * feature_strings.c * * Routines for analyzing a feature string. * * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #include "ocfs2/ocfs2.h" struct fs_feature_flags { const char *ff_str; /* this flag is the feature's own flag. */ ocfs2_fs_options ff_own_flags; /* * this flag includes the feature's own flag and * all the other features' flag it depends on. */ ocfs2_fs_options ff_flags; }; /* Printable names for feature flags */ struct feature_name { const char *fn_name; ocfs2_fs_options fn_flag; /* Only the bit for this feature */ }; struct tunefs_flag_name { const char *tfn_name; uint16_t tfn_flag; }; /* Printable names for extent flags */ struct extent_flag_name { const char *efn_name; uint8_t efn_flag; }; /* Printable names for refcount flags */ struct refcount_flag_name { const char *rfn_name; uint32_t rfn_flag; }; struct feature_level_translation { const char *fl_str; enum ocfs2_feature_levels fl_type; }; static struct feature_level_translation ocfs2_feature_levels_table[] = { {"default", OCFS2_FEATURE_LEVEL_DEFAULT}, {"max-compat", OCFS2_FEATURE_LEVEL_MAX_COMPAT}, {"max-features", OCFS2_FEATURE_LEVEL_MAX_FEATURES}, {NULL, OCFS2_FEATURE_LEVEL_DEFAULT}, }; static ocfs2_fs_options feature_level_defaults[] = { {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | OCFS2_FEATURE_INCOMPAT_INLINE_DATA | OCFS2_FEATURE_INCOMPAT_XATTR, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_FEATURE_LEVEL_DEFAULT */ {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, 0, 0}, /* OCFS2_FEATURE_LEVEL_MAX_COMPAT */ {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP | OCFS2_FEATURE_INCOMPAT_INLINE_DATA | OCFS2_FEATURE_INCOMPAT_META_ECC | OCFS2_FEATURE_INCOMPAT_XATTR | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN | OCFS2_FEATURE_RO_COMPAT_USRQUOTA | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA }, /* OCFS2_FEATURE_LEVEL_MAX_FEATURES */ }; static ocfs2_fs_options mkfstypes_features_defaults[] = { {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | OCFS2_FEATURE_INCOMPAT_INLINE_DATA | OCFS2_FEATURE_INCOMPAT_XATTR, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_MKFSTYPE_DEFAULT */ {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | OCFS2_FEATURE_INCOMPAT_INLINE_DATA | OCFS2_FEATURE_INCOMPAT_XATTR, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_MKFSTYPE_DATAFILES */ {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | OCFS2_FEATURE_INCOMPAT_INLINE_DATA | OCFS2_FEATURE_INCOMPAT_XATTR, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_MKFSTYPE_MAIL */ {OCFS2_FEATURE_COMPAT_BACKUP_SB | OCFS2_FEATURE_COMPAT_JBD2_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | OCFS2_FEATURE_INCOMPAT_INLINE_DATA | OCFS2_FEATURE_INCOMPAT_XATTR | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_MKFSTYPE_VMSTORE */ }; /* These are the features we support in mkfs/tunefs via --fs-features */ static struct fs_feature_flags ocfs2_supported_features[] = { { "local", {0, OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT, 0}, {0, OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT, 0}, }, { "sparse", {0, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC, 0}, {0, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC, 0}, }, { "backup-super", {OCFS2_FEATURE_COMPAT_BACKUP_SB, 0, 0}, {OCFS2_FEATURE_COMPAT_BACKUP_SB, 0, 0}, }, { "unwritten", {0, 0, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, {0, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, }, { "extended-slotmap", {0, OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, 0}, {0, OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, 0}, }, { "inline-data", {0, OCFS2_FEATURE_INCOMPAT_INLINE_DATA, 0}, {0, OCFS2_FEATURE_INCOMPAT_INLINE_DATA, 0}, }, { "metaecc", {0, OCFS2_FEATURE_INCOMPAT_META_ECC, 0}, {0, OCFS2_FEATURE_INCOMPAT_META_ECC, 0}, }, { "xattr", {0, OCFS2_FEATURE_INCOMPAT_XATTR, 0}, {0, OCFS2_FEATURE_INCOMPAT_XATTR, 0}, }, { "indexed-dirs", {0, OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS, 0}, {0, OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS, 0}, }, { "usrquota", {0, 0, OCFS2_FEATURE_RO_COMPAT_USRQUOTA}, {0, 0, OCFS2_FEATURE_RO_COMPAT_USRQUOTA}, }, { "grpquota", {0, 0, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}, {0, 0, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}, }, { "refcount", {0, OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE, 0}, {0, OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE, 0}, }, { "discontig-bg", {0, OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG, 0}, {0, OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG, 0}, }, { NULL, {0, 0, 0}, {0, 0, 0} }, }; /* * These are the printable names of all flags in s_feature_compat, * s_feature_ro_compat, and s_feature_incompat. If libocfs2 supports this * feature, its printable name must be here. * * These MUST be kept in sync with the flags in ocfs2_fs.h. */ static struct feature_name ocfs2_feature_names[] = { { .fn_name = "heartbeat-device", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV, 0}, }, { .fn_name = "aborted-resize", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG, 0}, }, { .fn_name = "local", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT, 0}, }, { .fn_name = "sparse", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC, 0}, }, { .fn_name = "extended-slotmap", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, 0}, }, { .fn_name = "aborted-tunefs", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG, 0}, }, { .fn_name = "userspace-stack", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK, 0}, }, { .fn_name = "backup-super", .fn_flag = {OCFS2_FEATURE_COMPAT_BACKUP_SB, 0, 0}, }, { .fn_name = "unwritten", .fn_flag = {0, 0, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, }, { .fn_name = "inline-data", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_INLINE_DATA, 0}, }, { .fn_name = "strict-journal-super", .fn_flag = {OCFS2_FEATURE_COMPAT_JBD2_SB, 0, 0}, }, { .fn_name = "metaecc", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_META_ECC, 0}, }, { .fn_name = "xattr", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_XATTR, 0}, }, { .fn_name = "indexed-dirs", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS, 0}, }, { .fn_name = "usrquota", .fn_flag = {0, 0, OCFS2_FEATURE_RO_COMPAT_USRQUOTA}, }, { .fn_name = "grpquota", .fn_flag = {0, 0, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}, }, { .fn_name = "refcount", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE, 0}, }, { .fn_name = "discontig-bg", .fn_flag = {0, OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG, 0}, }, { .fn_name = NULL, }, }; /* * The printable names of every flag in s_tunefs_flag. If libocfs2 supports * the flag, its name must be here. * * These MUST be kept in sync with the flags in ocfs2_fs.h. */ static struct tunefs_flag_name ocfs2_tunefs_flag_names[] = { { .tfn_name = "remove-slot", .tfn_flag = OCFS2_TUNEFS_INPROG_REMOVE_SLOT, }, { .tfn_name = "dir-trailer", .tfn_flag = OCFS2_TUNEFS_INPROG_DIR_TRAILER, }, { .tfn_name = NULL, }, }; /* * The printable names of every flag in e_flags. If libocfs2 supports the * flag, its name must be here. * * These MUST be kept in sync with the flags in ocfs2_fs.h. */ static struct extent_flag_name ocfs2_extent_flag_names[] = { { .efn_name = "Unwritten", .efn_flag = OCFS2_EXT_UNWRITTEN, }, { .efn_name = "Refcounted", .efn_flag = OCFS2_EXT_REFCOUNTED, }, { .efn_name = NULL, }, }; /* * The printable names of every flag in rf_flags. If libocfs2 supports the * flag, its name must be here. * * These MUST be kept in sync with the flags in ocfs2_fs.h. */ static struct refcount_flag_name ocfs2_refcount_flag_names[] = { { .rfn_name = "Leaf", .rfn_flag = OCFS2_REFCOUNT_LEAF_FL, }, { .rfn_name = "Tree", .rfn_flag = OCFS2_REFCOUNT_TREE_FL, }, { .rfn_name = NULL, }, }; static inline void merge_features(ocfs2_fs_options *features, ocfs2_fs_options new_features) { features->opt_compat |= new_features.opt_compat; features->opt_incompat |= new_features.opt_incompat; features->opt_ro_compat |= new_features.opt_ro_compat; } /* Get the feature level according to the value set by "--fs-feature-level". */ errcode_t ocfs2_parse_feature_level(const char *typestr, enum ocfs2_feature_levels *level) { int i; for(i = 0; ocfs2_feature_levels_table[i].fl_str; i++) { if (strcmp(typestr, ocfs2_feature_levels_table[i].fl_str) == 0) { *level = ocfs2_feature_levels_table[i].fl_type; break; } } if (!ocfs2_feature_levels_table[i].fl_str) { return OCFS2_ET_UNSUPP_FEATURE; } return 0; } static int check_feature_flags(ocfs2_fs_options *fs_flags, ocfs2_fs_options *fs_r_flags) { int ret = 1; if (fs_r_flags->opt_compat && fs_flags->opt_compat & fs_r_flags->opt_compat) ret = 0; else if (fs_r_flags->opt_incompat && fs_flags->opt_incompat & fs_r_flags->opt_incompat) ret = 0; else if (fs_r_flags->opt_ro_compat && fs_flags->opt_ro_compat & fs_r_flags->opt_ro_compat) ret = 0; return ret; } static int feature_match(ocfs2_fs_options *a, ocfs2_fs_options *b) { if ((a->opt_compat & b->opt_compat) || (a->opt_incompat & b->opt_incompat) || (a->opt_ro_compat & b->opt_ro_compat)) return 1; return 0; } errcode_t ocfs2_snprint_feature_flags(char *str, size_t size, ocfs2_fs_options *flags) { int i, printed; char *ptr = str; size_t remain = size; errcode_t err = 0; char *sep = " "; ocfs2_fs_options found = {0, 0, 0}; for (i = 0; ocfs2_feature_names[i].fn_name; i++) { if (!feature_match(flags, &ocfs2_feature_names[i].fn_flag)) continue; merge_features(&found, ocfs2_feature_names[i].fn_flag); printed = snprintf(ptr, remain, "%s%s", ptr == str ? "" : sep, ocfs2_feature_names[i].fn_name); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; if (err) break; remain -= printed; ptr += printed; } if (!err) { if ((found.opt_compat != flags->opt_compat) || (found.opt_ro_compat != flags->opt_ro_compat) || (found.opt_incompat != flags->opt_incompat)) { printed = snprintf(ptr, remain, "%sunknown", ptr == str ? "" : sep); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; } } return err; } errcode_t ocfs2_snprint_tunefs_flags(char *str, size_t size, uint16_t flags) { int i, printed; char *ptr = str; size_t remain = size; errcode_t err = 0; char *sep = " "; uint16_t found = 0; for (i = 0; ocfs2_tunefs_flag_names[i].tfn_name; i++) { if (!(flags & ocfs2_tunefs_flag_names[i].tfn_flag)) continue; found |= ocfs2_tunefs_flag_names[i].tfn_flag; printed = snprintf(ptr, remain, "%s%s", ptr == str ? "" : sep, ocfs2_tunefs_flag_names[i].tfn_name); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; if (err) break; remain -= printed; ptr += printed; } if (!err) { if (found != flags) { printed = snprintf(ptr, remain, "%sunknown", ptr == str ? "" : sep); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; } } return err; } errcode_t ocfs2_snprint_extent_flags(char *str, size_t size, uint8_t flags) { int i, printed; char *ptr = str; size_t remain = size; errcode_t err = 0; char *sep = " "; uint8_t found = 0; for (i = 0; ocfs2_extent_flag_names[i].efn_name; i++) { if (!(flags & ocfs2_extent_flag_names[i].efn_flag)) continue; found |= ocfs2_extent_flag_names[i].efn_flag; printed = snprintf(ptr, remain, "%s%s", ptr == str ? "" : sep, ocfs2_extent_flag_names[i].efn_name); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; if (err) break; remain -= printed; ptr += printed; } if (!err) { if (found != flags) { printed = snprintf(ptr, remain, "%sUnknown", ptr == str ? "" : sep); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; } } return err; } errcode_t ocfs2_snprint_refcount_flags(char *str, size_t size, uint8_t flags) { int i, printed; char *ptr = str; size_t remain = size; errcode_t err = 0; char *sep = " "; uint8_t found = 0; for (i = 0; ocfs2_refcount_flag_names[i].rfn_name; i++) { if (!(flags & ocfs2_refcount_flag_names[i].rfn_flag)) continue; found |= ocfs2_refcount_flag_names[i].rfn_flag; printed = snprintf(ptr, remain, "%s%s", ptr == str ? "" : sep, ocfs2_refcount_flag_names[i].rfn_name); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; if (err) break; remain -= printed; ptr += printed; } if (!err) { if (found != flags) { printed = snprintf(ptr, remain, "%sUnknown", ptr == str ? "" : sep); if (printed < 0) err = OCFS2_ET_INTERNAL_FAILURE; else if (printed >= remain) err = OCFS2_ET_NO_SPACE; } } return err; } /* * If we are asked to clear a feature, we also need to clear any other * features that depend on it. */ static void ocfs2_feature_clear_deps(ocfs2_fs_options *reverse_set) { int i; for(i = 0; ocfs2_supported_features[i].ff_str; i++) { if (feature_match(reverse_set, &ocfs2_supported_features[i].ff_flags)) { merge_features(reverse_set, ocfs2_supported_features[i].ff_own_flags); } } } /* * Check and Merge all the diffent features set by the user. * * index: the feature level. * feature_set: all the features a user set by "--fs-features". * reverse_set: all the features a user want to clear by "--fs-features". */ errcode_t ocfs2_merge_feature_flags_with_level(ocfs2_fs_options *dest, enum ocfs2_mkfs_types fstype, int level, ocfs2_fs_options *feature_set, ocfs2_fs_options *reverse_set) { ocfs2_fs_options level_set; if (level == OCFS2_FEATURE_LEVEL_DEFAULT) level_set = mkfstypes_features_defaults[fstype]; else level_set = feature_level_defaults[level]; /* * Ensure that all dependancies are correct in the reverse set. * A reverse set from ocfs2_parse_feature() will be correct, but * a hand-built one might not be. */ ocfs2_feature_clear_deps(reverse_set); /* * Check whether the user asked for a flag to be set and cleared, * which is illegal. The feature_set and reverse_set are both set * by "--fs-features", so they shouldn't collide with each other, * but a hand-built one might have problems. */ if (!check_feature_flags(feature_set, reverse_set)) return OCFS2_ET_CONFLICTING_FEATURES; /* Now combine all the features the user has set. */ *dest = level_set; merge_features(dest, *feature_set); /* Now clear the reverse set from our destination */ dest->opt_compat &= ~reverse_set->opt_compat; dest->opt_ro_compat &= ~reverse_set->opt_ro_compat; dest->opt_incompat &= ~reverse_set->opt_incompat; return 0; } /* * Parse the feature string. * * For those the user want to clear(with "no" in the beginning), * they are stored in "reverse_flags". * * For those the user want to set, they are stored in "feature_flags". */ errcode_t ocfs2_parse_feature(const char *opts, ocfs2_fs_options *feature_flags, ocfs2_fs_options *reverse_flags) { char *options, *token, *next, *p, *arg; int i, reverse = 0; memset(feature_flags, 0, sizeof(ocfs2_fs_options)); memset(reverse_flags, 0, sizeof(ocfs2_fs_options)); options = strdup(opts); for (token = options; token && *token; token = next) { reverse = 0; p = strchr(token, ','); next = NULL; if (p) { *p = '\0'; next = p + 1; } arg = strstr(token, "no"); if (arg && arg == token) { reverse = 1; token += 2; } for(i = 0; ocfs2_supported_features[i].ff_str; i++) { if (strcmp(token, ocfs2_supported_features[i].ff_str) == 0) { if (!reverse) merge_features(feature_flags, ocfs2_supported_features[i].ff_flags); else merge_features(reverse_flags, ocfs2_supported_features[i].ff_own_flags); break; } } if (!ocfs2_supported_features[i].ff_str) { free(options); return OCFS2_ET_UNSUPP_FEATURE; } } free(options); ocfs2_feature_clear_deps(reverse_flags); /* * Check whether the user asked for a flag to be set and cleared, * which is illegal. The feature_set and reverse_set are both set * by "--fs-features", so they shouldn't collide with each other. */ if (!check_feature_flags(feature_flags, reverse_flags)) return OCFS2_ET_CONFLICTING_FEATURES; return 0; } static int compare_feature_forward(const void *pa, const void *pb) { int ia = *(int *)pa; int ib = *(int *)pb; struct fs_feature_flags *fa = &ocfs2_supported_features[ia]; struct fs_feature_flags *fb = &ocfs2_supported_features[ib]; if (feature_match(&fb->ff_flags, &fa->ff_own_flags)) return -1; if (feature_match(&fa->ff_flags, &fb->ff_own_flags)) return 1; return 0; } static int compare_feature_backward(const void *pa, const void *pb) { return compare_feature_forward(pb, pa); } static void __feature_foreach(int reverse, ocfs2_fs_options *feature_set, int (*func)(ocfs2_fs_options *feature, void *user_data), void *user_data) { int i, index; int num_features = sizeof(ocfs2_supported_features) / sizeof(ocfs2_supported_features[0]); int indices[num_features]; index = 0; for (i = 0; ocfs2_supported_features[i].ff_str; i++) { if (feature_match(feature_set, &ocfs2_supported_features[i].ff_own_flags)) { indices[index] = i; index++; } } qsort(indices, index, sizeof(indices[0]), reverse ? compare_feature_backward : compare_feature_forward); for (i = 0; i < index; i++) { if (func(&ocfs2_supported_features[indices[i]].ff_own_flags, user_data)) break; } } void ocfs2_feature_foreach(ocfs2_fs_options *feature_set, int (*func)(ocfs2_fs_options *feature, void *user_data), void *user_data) { __feature_foreach(0, feature_set, func, user_data); } void ocfs2_feature_reverse_foreach(ocfs2_fs_options *reverse_set, int (*func)(ocfs2_fs_options *feature, void *user_data), void *user_data) { __feature_foreach(1, reverse_set, func, user_data); } #ifdef DEBUG_EXE #include #include #include "ocfs2/ocfs2.h" static void print_features(char *desc, ocfs2_fs_options *feature_set) { int i; fprintf(stdout, "%s:\n", desc); fprintf(stdout, "COMPAT:\t\t"); for(i = 0; ocfs2_supported_features[i].ff_str; i++) if (feature_set->opt_compat & ocfs2_supported_features[i].ff_own_flags.opt_compat) fprintf(stdout, " %s", ocfs2_supported_features[i].ff_str); fprintf(stdout, "\n"); fprintf(stdout, "RO_COMPAT:\t"); for(i = 0; ocfs2_supported_features[i].ff_str; i++) if (feature_set->opt_ro_compat & ocfs2_supported_features[i].ff_own_flags.opt_ro_compat) fprintf(stdout, " %s", ocfs2_supported_features[i].ff_str); fprintf(stdout, "\n"); fprintf(stdout, "INCOMPAT:\t"); for(i = 0; ocfs2_supported_features[i].ff_str; i++) if (feature_set->opt_incompat & ocfs2_supported_features[i].ff_own_flags.opt_incompat) fprintf(stdout, " %s", ocfs2_supported_features[i].ff_str); fprintf(stdout, "\n"); } static void printable_mkfs(ocfs2_fs_options *feature_set) { errcode_t err; char buf[PATH_MAX]; ocfs2_fs_options flags; fprintf(stdout, "Printable version of mkfs features:\n"); memset(&flags, 0, sizeof(flags)); flags.opt_compat = feature_set->opt_compat; err = ocfs2_snprint_feature_flags(buf, PATH_MAX, &flags); if (err) snprintf(buf, PATH_MAX, "An error occurred: %s", error_message(err)); fprintf(stdout, "COMPAT:\t\t%s\n", buf); memset(&flags, 0, sizeof(flags)); flags.opt_ro_compat = feature_set->opt_ro_compat; err = ocfs2_snprint_feature_flags(buf, PATH_MAX, &flags); if (err) snprintf(buf, PATH_MAX, "An error occurred: %s", error_message(err)); fprintf(stdout, "RO_COMPAT:\t%s\n", buf); memset(&flags, 0, sizeof(flags)); flags.opt_incompat = feature_set->opt_incompat; err = ocfs2_snprint_feature_flags(buf, PATH_MAX, &flags); if (err) snprintf(buf, PATH_MAX, "An error occurred: %s", error_message(err)); fprintf(stdout, "INCOMPAT:\t%s\n", buf); fprintf(stdout, "\n"); } static void print_tunefs_flags(void) { errcode_t err; char buf[PATH_MAX]; fprintf(stdout, "Printable s_tunefs_flag:\n"); err = ocfs2_snprint_tunefs_flags(buf, PATH_MAX, OCFS2_TUNEFS_INPROG_REMOVE_SLOT | OCFS2_TUNEFS_INPROG_DIR_TRAILER); if (err) snprintf(buf, PATH_MAX, "An error occurred: %s", error_message(err)); fprintf(stdout, "FLAGS:\t\t%s\n", buf); fprintf(stdout, "\n"); } static void print_extent_flags(void) { errcode_t err; char buf[PATH_MAX]; fprintf(stdout, "Printable e_flags:\n"); err = ocfs2_snprint_extent_flags(buf, PATH_MAX, OCFS2_EXT_UNWRITTEN | OCFS2_EXT_REFCOUNTED); if (err) snprintf(buf, PATH_MAX, "An error occurred: %s", error_message(err)); fprintf(stdout, "FLAGS:\t\t%s\n", buf); fprintf(stdout, "\n"); } static void print_refcount_flags(void) { errcode_t err; char buf[PATH_MAX]; fprintf(stdout, "Printable rf_flags:\n"); err = ocfs2_snprint_refcount_flags(buf, PATH_MAX, OCFS2_REFCOUNT_TREE_FL | OCFS2_REFCOUNT_LEAF_FL); if (err) snprintf(buf, PATH_MAX, "An error occurred: %s", error_message(err)); fprintf(stdout, "FLAGS:\t\t%s\n", buf); fprintf(stdout, "\n"); } static int p_feature(ocfs2_fs_options *feature_set, void *user_data) { int i; for (i = 0; ocfs2_supported_features[i].ff_str; i++) { if (feature_match(feature_set, &ocfs2_supported_features[i].ff_own_flags)) fprintf(stdout, " %s", ocfs2_supported_features[i].ff_str); } return 0; } static void print_order(int reverse, ocfs2_fs_options *feature_set) { fprintf(stdout, "In this order:"); if (reverse) ocfs2_feature_reverse_foreach(feature_set, p_feature, NULL); else ocfs2_feature_foreach(feature_set, p_feature, NULL); fprintf(stdout, "\n\n"); } extern int optind, optopt, opterr; extern char *optarg; int main(int argc, char *argv[]) { int c; enum ocfs2_feature_levels level = OCFS2_FEATURE_LEVEL_DEFAULT; errcode_t err; char *feature_string = NULL; char *level_string = NULL; ocfs2_fs_options set_features, clear_features, mkfs_features; initialize_ocfs_error_table(); opterr = 0; memset(&set_features, 0, sizeof(ocfs2_fs_options)); memset(&clear_features, 0, sizeof(ocfs2_fs_options)); while ((c = getopt(argc, argv, ":l:s:")) != EOF) { switch (c) { case 'l': if (level_string) free(level_string); level_string = strdup(optarg); err = ocfs2_parse_feature_level(optarg, &level); if (err) { com_err(argv[0], err, "while parsing the feature level string"); exit(1); } break; case 's': if (feature_string) free(feature_string); feature_string = strdup(optarg); memset(&set_features, 0, sizeof(ocfs2_fs_options)); memset(&clear_features, 0, sizeof(ocfs2_fs_options)); err = ocfs2_parse_feature(optarg, &set_features, &clear_features); if (err) { com_err(argv[0], err, "while parsing the feature string"); exit(1); } break; default: fprintf(stderr, "%s: Invalid argument: '-%c'\n", argv[0], optopt); exit(1); break; } } memset(&mkfs_features, 0, sizeof(ocfs2_fs_options)); err = ocfs2_merge_feature_flags_with_level(&mkfs_features, OCFS2_MKFSTYPE_DEFAULT, level, &set_features, &clear_features); if (err) { com_err(argv[0], err, "while trying to reconcile default and specified features"); exit(1); } print_features("\nmkfs.ocfs2 would set these features", &mkfs_features); print_order(0, &mkfs_features); printable_mkfs(&mkfs_features); print_features("tunefs.ocfs2 would set these features", &set_features); print_order(0, &set_features); print_features("tunefs.ocfs2 would clear these features", &clear_features); print_order(1, &clear_features); print_tunefs_flags(); print_extent_flags(); print_refcount_flags(); return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/libocfs2/quota.c0000644000176100017610000010327011453177334013771 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * quota.c * * Quota operations for the OCFS2 userspace library. * * Copyright (C) 2008 Novell. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" void ocfs2_swap_quota_header(struct ocfs2_disk_dqheader *header) { if (cpu_is_little_endian) return; header->dqh_magic = bswap_32(header->dqh_magic); header->dqh_version = bswap_32(header->dqh_version); } void ocfs2_swap_quota_local_info(struct ocfs2_local_disk_dqinfo *info) { if (cpu_is_little_endian) return; info->dqi_flags = bswap_32(info->dqi_flags); info->dqi_chunks = bswap_32(info->dqi_chunks); info->dqi_blocks = bswap_32(info->dqi_blocks); } void ocfs2_swap_quota_chunk_header(struct ocfs2_local_disk_chunk *chunk) { if (cpu_is_little_endian) return; chunk->dqc_free = bswap_32(chunk->dqc_free); } void ocfs2_swap_quota_global_info(struct ocfs2_global_disk_dqinfo *info) { if (cpu_is_little_endian) return; info->dqi_bgrace = bswap_32(info->dqi_bgrace); info->dqi_igrace = bswap_32(info->dqi_igrace); info->dqi_syncms = bswap_32(info->dqi_syncms); info->dqi_blocks = bswap_32(info->dqi_blocks); info->dqi_free_blk = bswap_32(info->dqi_free_blk); info->dqi_free_entry = bswap_32(info->dqi_free_entry); } void ocfs2_swap_quota_global_dqblk(struct ocfs2_global_disk_dqblk *dqblk) { if (cpu_is_little_endian) return; dqblk->dqb_id = bswap_32(dqblk->dqb_id); dqblk->dqb_use_count = bswap_32(dqblk->dqb_use_count); dqblk->dqb_ihardlimit = bswap_64(dqblk->dqb_ihardlimit); dqblk->dqb_isoftlimit = bswap_64(dqblk->dqb_isoftlimit); dqblk->dqb_curinodes = bswap_64(dqblk->dqb_curinodes); dqblk->dqb_bhardlimit = bswap_64(dqblk->dqb_bhardlimit); dqblk->dqb_bsoftlimit = bswap_64(dqblk->dqb_bsoftlimit); dqblk->dqb_curspace = bswap_64(dqblk->dqb_curspace); dqblk->dqb_btime = bswap_64(dqblk->dqb_btime); dqblk->dqb_itime = bswap_64(dqblk->dqb_itime); } void ocfs2_swap_quota_leaf_block_header(struct qt_disk_dqdbheader *bheader) { if (cpu_is_little_endian) return; bheader->dqdh_next_free = bswap_32(bheader->dqdh_next_free); bheader->dqdh_prev_free = bswap_32(bheader->dqdh_prev_free); bheader->dqdh_entries = bswap_16(bheader->dqdh_entries); } /* Should be power of two */ #define DEFAULT_QUOTA_HASH_SIZE 8192 /* Maxinum number of hash buckets - use at most 16 MB on a 64-bit arch */ #define MAX_QUOTA_HASH_SIZE (1<<21) errcode_t ocfs2_new_quota_hash(ocfs2_quota_hash **hashp) { ocfs2_quota_hash *hash; errcode_t err; err = ocfs2_malloc(sizeof(ocfs2_quota_hash), &hash); if (err) return err; hash->alloc_entries = DEFAULT_QUOTA_HASH_SIZE; hash->used_entries = 0; err = ocfs2_malloc0(sizeof(ocfs2_quota_hash *) * DEFAULT_QUOTA_HASH_SIZE, &hash->hash); if (err) { ocfs2_free(&hash); return err; } *hashp = hash; return 0; } errcode_t ocfs2_free_quota_hash(ocfs2_quota_hash *hash) { errcode_t err = 0, ret; if (hash->used_entries) return OCFS2_ET_NONEMTY_QUOTA_HASH; ret = ocfs2_free(&hash->hash); if (!err && ret) err = ret; ret = ocfs2_free(&hash); if (!err && ret) err = ret; return err; } static int quota_hash(ocfs2_quota_hash *hash, qid_t id) { return (((unsigned long)id) * 5) & (hash->alloc_entries - 1); } static void quota_add_hash_chain(ocfs2_quota_hash *hash, ocfs2_cached_dquot *dquot) { int hash_val = quota_hash(hash, dquot->d_ddquot.dqb_id); dquot->d_next = hash->hash[hash_val]; if (dquot->d_next) dquot->d_next->d_pprev = &dquot->d_next; hash->hash[hash_val] = dquot; dquot->d_pprev = hash->hash + hash_val; } errcode_t ocfs2_insert_quota_hash(ocfs2_quota_hash *hash, ocfs2_cached_dquot *dquot) { errcode_t err; if (hash->used_entries > hash->alloc_entries && hash->alloc_entries * 2 < MAX_QUOTA_HASH_SIZE) { ocfs2_cached_dquot **new_hash, **old_hash; ocfs2_cached_dquot *h_dquot, *h_next; int i; int old_entries; err = ocfs2_malloc0(sizeof(ocfs2_quota_hash *) * hash->alloc_entries * 2, &new_hash); if (err) return err; old_entries = hash->alloc_entries; old_hash = hash->hash; hash->alloc_entries *= 2; hash->hash = new_hash; /* Rehash */ for (i = 0; i < old_entries; i++) { for (h_dquot = old_hash[i]; h_dquot; h_dquot = h_next) { h_next = h_dquot->d_next; quota_add_hash_chain(hash, h_dquot); } } err = ocfs2_free(&old_hash); if (err) return err; } quota_add_hash_chain(hash, dquot); hash->used_entries++; return 0; } errcode_t ocfs2_remove_quota_hash(ocfs2_quota_hash *hash, ocfs2_cached_dquot *dquot) { *(dquot->d_pprev) = dquot->d_next; if (dquot->d_next) dquot->d_next->d_pprev = dquot->d_pprev; hash->used_entries--; return 0; } errcode_t ocfs2_find_quota_hash(ocfs2_quota_hash *hash, qid_t id, ocfs2_cached_dquot **dquotp) { int hash_val = quota_hash(hash, id); ocfs2_cached_dquot *dquot; for (dquot = hash->hash[hash_val]; dquot; dquot = dquot->d_next) { if (dquot->d_ddquot.dqb_id == id) { *dquotp = dquot; return 0; } } *dquotp = NULL; return 0; } errcode_t ocfs2_find_create_quota_hash(ocfs2_quota_hash *hash, qid_t id, ocfs2_cached_dquot **dquotp) { errcode_t err; err = ocfs2_find_quota_hash(hash, id, dquotp); if (err) return err; if (*dquotp) return 0; err = ocfs2_malloc0(sizeof(ocfs2_cached_dquot), dquotp); if (err) return err; (*dquotp)->d_ddquot.dqb_id = id; err = ocfs2_insert_quota_hash(hash, *dquotp); if (err) { ocfs2_free(dquotp); return err; } return 0; } errcode_t ocfs2_find_read_quota_hash(ocfs2_filesys *fs, ocfs2_quota_hash *hash, int type, qid_t id, ocfs2_cached_dquot **dquotp) { errcode_t err; err = ocfs2_find_quota_hash(hash, id, dquotp); if (err) return err; if (*dquotp) return 0; err = ocfs2_read_dquot(fs, type, id, dquotp); if (err) return err; err = ocfs2_insert_quota_hash(hash, *dquotp); if (err) { ocfs2_free(dquotp); return err; } return 0; } errcode_t ocfs2_compute_quota_usage(ocfs2_filesys *fs, ocfs2_quota_hash *usr_hash, ocfs2_quota_hash *grp_hash) { errcode_t err = 0; ocfs2_inode_scan *scan; uint64_t blkno; char *buf; int close_scan = 0; struct ocfs2_dinode *di; ocfs2_cached_dquot *dquot; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; di = (struct ocfs2_dinode *)buf; err = ocfs2_open_inode_scan(fs, &scan); if (err) goto out; close_scan = 1; while (1) { err = ocfs2_get_next_inode(scan, &blkno, buf); if (err || !blkno) break; /* * Check whether the inode looks reasonable and interesting * for quota */ if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) continue; ocfs2_swap_inode_to_cpu(fs, di); if (di->i_fs_generation != fs->fs_super->i_fs_generation) continue; if (!(di->i_flags & OCFS2_VALID_FL)) continue; if (di->i_flags & OCFS2_SYSTEM_FL && blkno != OCFS2_RAW_SB(fs->fs_super)->s_root_blkno) continue; if (usr_hash) { err = ocfs2_find_create_quota_hash(usr_hash, di->i_uid, &dquot); if (err) break; dquot->d_ddquot.dqb_curspace += ocfs2_clusters_to_bytes(fs, di->i_clusters); dquot->d_ddquot.dqb_curinodes++; } if (grp_hash) { err = ocfs2_find_create_quota_hash(grp_hash, di->i_gid, &dquot); if (err) break; dquot->d_ddquot.dqb_curspace += ocfs2_clusters_to_bytes(fs, di->i_clusters); dquot->d_ddquot.dqb_curinodes++; } } out: if (close_scan) ocfs2_close_inode_scan(scan); ocfs2_free(&buf); return err; } errcode_t ocfs2_init_quota_change(ocfs2_filesys *fs, ocfs2_quota_hash **usrhash, ocfs2_quota_hash **grphash) { errcode_t err; *usrhash = NULL; *grphash = NULL; if (OCFS2_HAS_RO_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { err = ocfs2_new_quota_hash(usrhash); if (err) return err; } if (OCFS2_HAS_RO_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { err = ocfs2_new_quota_hash(grphash); if (err) { if (*usrhash) ocfs2_free_quota_hash(*usrhash); return err; } } return 0; } errcode_t ocfs2_finish_quota_change(ocfs2_filesys *fs, ocfs2_quota_hash *usrhash, ocfs2_quota_hash *grphash) { errcode_t ret = 0, err; if (usrhash) { err = ocfs2_write_release_dquots(fs, USRQUOTA, usrhash); if (!ret) ret = err; err = ocfs2_free_quota_hash(usrhash); if (!ret) ret = err; } if (grphash) { err = ocfs2_write_release_dquots(fs, GRPQUOTA, grphash); if (!ret) ret = err; err = ocfs2_free_quota_hash(grphash); if (!ret) ret = err; } return ret; } errcode_t ocfs2_apply_quota_change(ocfs2_filesys *fs, ocfs2_quota_hash *usrhash, ocfs2_quota_hash *grphash, uid_t uid, gid_t gid, int64_t space_change, int64_t inode_change) { ocfs2_cached_dquot *dquot; errcode_t err; if (usrhash) { err = ocfs2_find_read_quota_hash(fs, usrhash, USRQUOTA, uid, &dquot); if (err) return err; dquot->d_ddquot.dqb_curspace += space_change; dquot->d_ddquot.dqb_curinodes += inode_change; } if (grphash) { err = ocfs2_find_read_quota_hash(fs, grphash, GRPQUOTA, gid, &dquot); if (err) return err; dquot->d_ddquot.dqb_curspace += space_change; dquot->d_ddquot.dqb_curinodes += inode_change; } return 0; } errcode_t ocfs2_iterate_quota_hash(ocfs2_quota_hash *hash, errcode_t (*f)(ocfs2_cached_dquot *, void *), void *data) { errcode_t err = 0; int i; ocfs2_cached_dquot *dquot, *next; for (i = 0; i < hash->alloc_entries; i++) for (dquot = hash->hash[i]; dquot; dquot = next) { next = dquot->d_next; err = f(dquot, data); if (err) goto out; } out: return err; } struct write_rel_ctx { ocfs2_filesys *fs; ocfs2_quota_hash *hash; int type; }; static errcode_t write_release_quota_hash(ocfs2_cached_dquot *dquot, void *p) { struct write_rel_ctx *ctx = p; errcode_t err; if (!dquot->d_ddquot.dqb_isoftlimit || dquot->d_ddquot.dqb_curinodes < dquot->d_ddquot.dqb_isoftlimit) dquot->d_ddquot.dqb_itime = 0; if (!dquot->d_ddquot.dqb_bsoftlimit || dquot->d_ddquot.dqb_curspace < dquot->d_ddquot.dqb_bsoftlimit) dquot->d_ddquot.dqb_btime = 0; err = ocfs2_write_dquot(ctx->fs, ctx->type, dquot); if (err) return err; err = ocfs2_remove_quota_hash(ctx->hash, dquot); if (err) return err; return ocfs2_free(&dquot); } errcode_t ocfs2_write_release_dquots(ocfs2_filesys *fs, int type, ocfs2_quota_hash *hash) { struct write_rel_ctx ctx; ctx.fs = fs; ctx.hash = hash; ctx.type = type; return ocfs2_iterate_quota_hash(hash, write_release_quota_hash, &ctx); } static void mark_quotafile_info_dirty(ocfs2_filesys *fs, int type) { fs->qinfo[type].flags |= OCFS2_QF_INFO_DIRTY; fs->fs_flags |= OCFS2_FLAG_DIRTY; } static void ocfs2_checksum_quota_block(ocfs2_filesys *fs, char *buf) { struct ocfs2_disk_dqtrailer *dqt = ocfs2_block_dqtrailer(fs->fs_blocksize, buf); ocfs2_compute_meta_ecc(fs, buf, &dqt->dq_check); } #define OCFS2_LOCAL_QF_INIT_BLOCKS 2 errcode_t ocfs2_init_local_quota_file(ocfs2_filesys *fs, int type, uint64_t blkno) { ocfs2_cached_inode *ci = NULL; struct ocfs2_dinode *di; struct ocfs2_disk_dqheader *header; struct ocfs2_local_disk_dqinfo *info; unsigned int magics[] = OCFS2_LOCAL_QMAGICS; int versions[] = OCFS2_LOCAL_QVERSIONS; char *buf = NULL; unsigned int written; int bytes = ocfs2_blocks_to_bytes(fs, OCFS2_LOCAL_QF_INIT_BLOCKS); errcode_t err; err = ocfs2_read_cached_inode(fs, blkno, &ci); if (err) goto out; if (!(ci->ci_inode->i_flags & OCFS2_VALID_FL) || !(ci->ci_inode->i_flags & OCFS2_SYSTEM_FL) || !(ci->ci_inode->i_flags & OCFS2_QUOTA_FL)) { err = OCFS2_ET_INTERNAL_FAILURE; goto out; } di = ci->ci_inode; /* We need at least two blocks */ err = ocfs2_cached_inode_extend_allocation(ci, ocfs2_clusters_in_blocks(fs, OCFS2_LOCAL_QF_INIT_BLOCKS)); if (err) goto out; di->i_size = bytes; di->i_mtime = time(NULL); err = ocfs2_write_inode(fs, blkno, (char *)di); if (err) goto out; err = ocfs2_malloc_blocks(fs->fs_io, OCFS2_LOCAL_QF_INIT_BLOCKS, &buf); if (err) goto out; memset(buf, 0, bytes); header = (struct ocfs2_disk_dqheader *)buf; header->dqh_magic = magics[type]; header->dqh_version = versions[type]; ocfs2_swap_quota_header(header); info = (struct ocfs2_local_disk_dqinfo *)(buf + OCFS2_LOCAL_INFO_OFF); info->dqi_chunks = 1; info->dqi_blocks = OCFS2_LOCAL_QF_INIT_BLOCKS; info->dqi_flags = OLQF_CLEAN; ocfs2_swap_quota_local_info(info); /* There are no free chunks because there are no blocks allocated for * them yet. So chunk header is all-zero and needs no initialization */ ocfs2_checksum_quota_block(fs, buf); ocfs2_checksum_quota_block(fs, buf + fs->fs_blocksize); err = ocfs2_file_write(ci, buf, bytes, 0, &written); if (!err && written != bytes) { err = OCFS2_ET_INTERNAL_FAILURE; goto out; } out: if (ci) ocfs2_free_cached_inode(fs, ci); if (buf) ocfs2_free(&buf); return err; } errcode_t ocfs2_init_local_quota_files(ocfs2_filesys *fs, int type) { int num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; char fname[OCFS2_MAX_FILENAME_LEN]; errcode_t ret; uint64_t blkno; int local_type = (type == USRQUOTA) ? LOCAL_USER_QUOTA_SYSTEM_INODE : LOCAL_GROUP_QUOTA_SYSTEM_INODE; int i; for (i = 0; i < num_slots; i++) { ocfs2_sprintf_system_inode_name(fname, sizeof(fname), local_type, i); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname, strlen(fname), NULL, &blkno); if (ret) return ret; /* This is here mainly for fsck... */ ret = ocfs2_truncate(fs, blkno, 0); if (ret) return ret; ret = ocfs2_init_local_quota_file(fs, type, blkno); if (ret) return ret; } return 0; } /* Return depth of quota tree in global file */ int ocfs2_qtree_depth(int blocksize) { unsigned int epb = (blocksize - OCFS2_QBLK_RESERVED_SPACE) >> 2; unsigned long long entries = epb; int i; for (i = 1; entries < (1ULL << 32); i++) entries *= epb; return i; } /* Returns index of next block in the tree of dquots */ static int ocfs2_qtree_index(int blocksize, qid_t id, int depth) { unsigned int epb = (blocksize - OCFS2_QBLK_RESERVED_SPACE) >> 2; depth = ocfs2_qtree_depth(blocksize) - depth - 1; while (depth--) id /= epb; return id % epb; } /* Is given leaf entry unused? */ int ocfs2_qtree_entry_unused(struct ocfs2_global_disk_dqblk *ddquot) { static struct ocfs2_global_disk_dqblk empty; return !memcmp(&empty, ddquot, sizeof(empty)); } errcode_t ocfs2_init_fs_quota_info(ocfs2_filesys *fs, int type) { int global_type = (type == USRQUOTA) ? USER_QUOTA_SYSTEM_INODE : GROUP_QUOTA_SYSTEM_INODE; uint64_t blkno; char fname[OCFS2_MAX_FILENAME_LEN]; errcode_t ret; if (fs->qinfo[type].qi_inode) return 0; ocfs2_sprintf_system_inode_name(fname, sizeof(fname), global_type, 0); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname, strlen(fname), NULL, &blkno); if (ret) return ret; ret = ocfs2_read_cached_inode(fs, blkno, &(fs->qinfo[type].qi_inode)); if (ret) return ret; return 0; } /* Read given block */ static errcode_t read_blk(ocfs2_filesys *fs, int type, unsigned int blk, char *buf) { errcode_t err; uint32_t got; struct ocfs2_disk_dqtrailer *dqt = ocfs2_block_dqtrailer(fs->fs_blocksize, buf); err = ocfs2_file_read(fs->qinfo[type].qi_inode, buf, fs->fs_blocksize, blk * fs->fs_blocksize, &got); if (err) return err; if (got != fs->fs_blocksize) return OCFS2_ET_SHORT_READ; return ocfs2_validate_meta_ecc(fs, buf, &dqt->dq_check); } /* Write given block */ static errcode_t write_blk(ocfs2_filesys *fs, int type, unsigned int blk, char *buf) { errcode_t err; uint32_t written; ocfs2_checksum_quota_block(fs, buf); err = ocfs2_file_write(fs->qinfo[type].qi_inode, buf, fs->fs_blocksize, blk * fs->fs_blocksize, &written); if (err) return err; if (written != fs->fs_blocksize) return OCFS2_ET_SHORT_WRITE; return 0; } errcode_t ocfs2_read_global_quota_info(ocfs2_filesys *fs, int type) { char *buf; errcode_t ret; struct ocfs2_global_disk_dqinfo *info; if (fs->qinfo[type].flags & OCFS2_QF_INFO_LOADED) return 0; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = read_blk(fs, type, 0, buf); if (ret) return ret; info = (struct ocfs2_global_disk_dqinfo *)(buf + OCFS2_GLOBAL_INFO_OFF); ocfs2_swap_quota_global_info(info); memcpy(&(fs->qinfo[type].qi_info), info, sizeof(struct ocfs2_global_disk_dqinfo)); fs->qinfo[type].flags |= OCFS2_QF_INFO_LOADED; return 0; } errcode_t ocfs2_write_global_quota_info(ocfs2_filesys *fs, int type) { errcode_t ret; char *buf; struct ocfs2_disk_dqheader *header; struct ocfs2_global_disk_dqinfo *info; unsigned int magics[] = OCFS2_GLOBAL_QMAGICS; int versions[] = OCFS2_GLOBAL_QVERSIONS; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; header = (struct ocfs2_disk_dqheader *)buf; header->dqh_magic = magics[type]; header->dqh_version = versions[type]; ocfs2_swap_quota_header(header); info = (struct ocfs2_global_disk_dqinfo *)(buf + OCFS2_GLOBAL_INFO_OFF); memcpy(info, &(fs->qinfo[type].qi_info), sizeof(struct ocfs2_global_disk_dqinfo)); ocfs2_swap_quota_global_info(info); ret = write_blk(fs, type, 0, buf); if (ret) goto bail; bail: ocfs2_free(&buf); return ret; } errcode_t ocfs2_load_fs_quota_info(ocfs2_filesys *fs) { errcode_t err; if (OCFS2_HAS_RO_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { err = ocfs2_init_fs_quota_info(fs, USRQUOTA); if (err) return err; err = ocfs2_read_global_quota_info(fs, USRQUOTA); if (err) return err; } if (OCFS2_HAS_RO_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { err = ocfs2_init_fs_quota_info(fs, GRPQUOTA); if (err) return err; err = ocfs2_read_global_quota_info(fs, GRPQUOTA); if (err) return err; } return 0; } #define OCFS2_GLOBAL_QF_INIT_BLOCKS 2 errcode_t ocfs2_init_global_quota_file(ocfs2_filesys *fs, int type) { ocfs2_cached_inode *ci = fs->qinfo[type].qi_inode; struct ocfs2_dinode *di; char *buf = NULL; struct ocfs2_disk_dqheader *header; struct ocfs2_global_disk_dqinfo *info; unsigned int magics[] = OCFS2_GLOBAL_QMAGICS; int versions[] = OCFS2_GLOBAL_QVERSIONS; errcode_t err; int i; int bytes = ocfs2_blocks_to_bytes(fs, OCFS2_GLOBAL_QF_INIT_BLOCKS); if (!(ci->ci_inode->i_flags & OCFS2_VALID_FL) || !(ci->ci_inode->i_flags & OCFS2_SYSTEM_FL) || !(ci->ci_inode->i_flags & OCFS2_QUOTA_FL)) { err = OCFS2_ET_INTERNAL_FAILURE; goto out; } err = ocfs2_cached_inode_extend_allocation(ci, ocfs2_clusters_in_blocks(fs, OCFS2_GLOBAL_QF_INIT_BLOCKS)); if (err) goto out; /* Mark info dirty so that quota inode gets written */ mark_quotafile_info_dirty(fs, type); di = ci->ci_inode; di->i_size = bytes; di->i_mtime = time(NULL); err = ocfs2_malloc_blocks(fs->fs_io, OCFS2_GLOBAL_QF_INIT_BLOCKS, &buf); if (err) goto out; memset(buf, 0, bytes); header = (struct ocfs2_disk_dqheader *)buf; header->dqh_magic = magics[type]; header->dqh_version = versions[type]; ocfs2_swap_quota_header(header); fs->qinfo[type].qi_info.dqi_blocks = OCFS2_GLOBAL_QF_INIT_BLOCKS; fs->qinfo[type].qi_info.dqi_free_blk = 0; fs->qinfo[type].qi_info.dqi_free_entry = 0; info = (struct ocfs2_global_disk_dqinfo *)(buf + OCFS2_GLOBAL_INFO_OFF); info->dqi_bgrace = fs->qinfo[type].qi_info.dqi_bgrace; info->dqi_igrace = fs->qinfo[type].qi_info.dqi_igrace; info->dqi_syncms = fs->qinfo[type].qi_info.dqi_syncms; info->dqi_blocks = OCFS2_GLOBAL_QF_INIT_BLOCKS; info->dqi_free_blk = 0; info->dqi_free_entry = 0; ocfs2_swap_quota_global_info(info); /* * Write the buffer here so that all the headers are properly written. * Normally we don't write tree root block. */ for (i = 0; i < OCFS2_GLOBAL_QF_INIT_BLOCKS; i++) { err = write_blk(fs, type, i, buf + (i * fs->fs_blocksize)); if (err) goto out; } out: if (buf) ocfs2_free(&buf); return err; } /* Is given dquot empty? */ static int ocfs2_global_entry_unused(struct ocfs2_global_disk_dqblk *ddqblk) { static struct ocfs2_global_disk_dqblk empty; return !memcmp(&empty, ddqblk, sizeof(empty)); } /* Get free block in file (either from free list or create new one) */ static errcode_t ocfs2_get_free_dqblk(ocfs2_filesys *fs, int type, unsigned int *blk) { errcode_t err; char *buf; struct qt_disk_dqdbheader *dh; struct ocfs2_global_disk_dqinfo *info = &(fs->qinfo[type].qi_info); ocfs2_cached_inode *ci = fs->qinfo[type].qi_inode; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; dh = (struct qt_disk_dqdbheader *)buf; if (info->dqi_free_blk) { *blk = info->dqi_free_blk; err = read_blk(fs, type, *blk, buf); if (err) goto bail; info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); } else { if (info->dqi_blocks == ocfs2_clusters_to_blocks(fs, ci->ci_inode->i_clusters)) { err = ocfs2_cached_inode_extend_allocation(ci, 1); if (err) goto bail; } *blk = info->dqi_blocks++; ci->ci_inode->i_size = ocfs2_blocks_to_bytes(fs, info->dqi_blocks); } mark_quotafile_info_dirty(fs, type); bail: ocfs2_free(&buf); return err; } /* Put given block to free list */ static errcode_t ocfs2_put_free_dqblk(ocfs2_filesys *fs, int type, char *buf, unsigned int blk) { errcode_t err; struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; struct ocfs2_global_disk_dqinfo *info = &(fs->qinfo[type].qi_info); dh->dqdh_next_free = info->dqi_free_blk; dh->dqdh_prev_free = 0; dh->dqdh_entries = 0; ocfs2_swap_quota_leaf_block_header(dh); err = write_blk(fs, type, blk, buf); ocfs2_swap_quota_leaf_block_header(dh); if (err) return err; info->dqi_free_blk = blk; mark_quotafile_info_dirty(fs, type); return 0; } /* Remove given block from the list of blocks with free entries */ static errcode_t ocfs2_remove_free_dqentry(ocfs2_filesys *fs, int type, char *buf, unsigned int blk) { errcode_t err; char *tmpbuf; struct qt_disk_dqdbheader *dh, *tdh; unsigned int nextblk, prevblk; err = ocfs2_malloc_block(fs->fs_io, &tmpbuf); if (err) return err; dh = (struct qt_disk_dqdbheader *)buf; tdh = (struct qt_disk_dqdbheader *)tmpbuf; nextblk = dh->dqdh_next_free; prevblk = dh->dqdh_prev_free; if (nextblk) { err = read_blk(fs, type, nextblk, tmpbuf); if (err) goto bail; ocfs2_swap_quota_leaf_block_header(tdh); tdh->dqdh_prev_free = prevblk; ocfs2_swap_quota_leaf_block_header(tdh); err = write_blk(fs, type, nextblk, tmpbuf); if (err) goto bail; } if (prevblk) { /* Failure here is bad since we potentially corrupt free list. * OTOH something must be really wrong when read/write fails */ err = read_blk(fs, type, prevblk, tmpbuf); if (err) goto bail; ocfs2_swap_quota_leaf_block_header(tdh); tdh->dqdh_next_free = nextblk; ocfs2_swap_quota_leaf_block_header(tdh); err = write_blk(fs, type, prevblk, tmpbuf); if (err) goto bail; } else { fs->qinfo[type].qi_info.dqi_free_entry = nextblk; mark_quotafile_info_dirty(fs, type); } dh->dqdh_next_free = dh->dqdh_prev_free = 0; ocfs2_swap_quota_leaf_block_header(dh); /* No matter whether write succeeds block is out of list */ write_blk(fs, type, blk, buf); ocfs2_swap_quota_leaf_block_header(dh); bail: ocfs2_free(&tmpbuf); return err; } /* Insert given block to the beginning of list with free entries */ static errcode_t ocfs2_insert_free_dqentry(ocfs2_filesys *fs, int type, char *buf, unsigned int blk) { errcode_t err; char *tmpbuf; struct qt_disk_dqdbheader *tdh, *dh = (struct qt_disk_dqdbheader *)buf; struct ocfs2_global_disk_dqinfo *info = &(fs->qinfo[type].qi_info); err = ocfs2_malloc_block(fs->fs_io, &tmpbuf); if (err) return err; dh->dqdh_next_free = info->dqi_free_entry; dh->dqdh_prev_free = 0; ocfs2_swap_quota_leaf_block_header(dh); err = write_blk(fs, type, blk, buf); ocfs2_swap_quota_leaf_block_header(dh); if (err) goto bail; if (info->dqi_free_entry) { tdh = (struct qt_disk_dqdbheader *)tmpbuf; err = read_blk(fs, type, info->dqi_free_entry, tmpbuf); if (err) goto bail; ocfs2_swap_quota_leaf_block_header(tdh); tdh->dqdh_prev_free = blk; ocfs2_swap_quota_leaf_block_header(tdh); err = write_blk(fs, type, info->dqi_free_entry, tmpbuf); if (err) goto bail; } info->dqi_free_entry = blk; mark_quotafile_info_dirty(fs, type); bail: ocfs2_free(&tmpbuf); return err; } /* Find space for dquot */ static errcode_t ocfs2_find_free_dqentry(ocfs2_filesys *fs, int type, unsigned int *treeblk, loff_t *off) { errcode_t err; unsigned int blk, i; struct ocfs2_global_disk_dqblk *ddquot; struct qt_disk_dqdbheader *dh; struct ocfs2_global_disk_dqinfo *info = &(fs->qinfo[type].qi_info); char *buf; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; dh = (struct qt_disk_dqdbheader *)buf; ddquot = (struct ocfs2_global_disk_dqblk *)(buf + sizeof(struct qt_disk_dqdbheader)); if (info->dqi_free_entry) { blk = info->dqi_free_entry; err = read_blk(fs, type, blk, buf); if (err) goto bail; ocfs2_swap_quota_leaf_block_header(dh); } else { err = ocfs2_get_free_dqblk(fs, type, &blk); if (err) goto bail; memset(buf, 0, fs->fs_blocksize); info->dqi_free_entry = blk; mark_quotafile_info_dirty(fs, type); } /* Block will be full? */ if (dh->dqdh_entries + 1 >= ocfs2_global_dqstr_in_blk(fs->fs_blocksize)) { err = ocfs2_remove_free_dqentry(fs, type, buf, blk); if (err) goto bail; } dh->dqdh_entries++; /* Find free structure in block */ for (i = 0; i < ocfs2_global_dqstr_in_blk(fs->fs_blocksize) && !ocfs2_global_entry_unused(ddquot + i); i++); if (i == ocfs2_global_dqstr_in_blk(fs->fs_blocksize)) { err = OCFS2_ET_CORRUPT_QUOTA_FILE; goto bail; } ocfs2_swap_quota_leaf_block_header(dh); err = write_blk(fs, type, blk, buf); if (err) goto bail; *off = (blk * fs->fs_blocksize) + sizeof(struct qt_disk_dqdbheader) + i * sizeof(struct ocfs2_global_disk_dqblk); *treeblk = blk; bail: ocfs2_free(&buf); return err; } /* Insert reference to structure into the trie */ static errcode_t ocfs2_do_insert_tree(ocfs2_filesys *fs, int type, qid_t id, unsigned int *treeblk, int depth, loff_t *off) { char *buf; int newson = 0, newact = 0; u_int32_t *ref; unsigned int newblk; errcode_t err; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; if (!*treeblk) { err = ocfs2_get_free_dqblk(fs, type, &newblk); if (err) goto bail; *treeblk = newblk; memset(buf, 0, fs->fs_blocksize); newact = 1; } else { err = read_blk(fs, type, *treeblk, buf); if (err) goto bail; } ref = (u_int32_t *) buf; newblk = le32_to_cpu(ref[ ocfs2_qtree_index(fs->fs_blocksize, id, depth)]); if (!newblk) newson = 1; if (depth == ocfs2_qtree_depth(fs->fs_blocksize) - 1) { if (newblk) { err = OCFS2_ET_CORRUPT_QUOTA_FILE; goto bail; } err = ocfs2_find_free_dqentry(fs, type, &newblk, off); } else err = ocfs2_do_insert_tree(fs, type, id, &newblk, depth + 1, off); if (newson && !err) { ref[ocfs2_qtree_index(fs->fs_blocksize, id, depth)] = cpu_to_le32(newblk); err = write_blk(fs, type, *treeblk, buf); } else if (newact && err) ocfs2_put_free_dqblk(fs, type, buf, *treeblk); bail: ocfs2_free(&buf); return err; } /* Wrapper for inserting quota structure into tree */ static errcode_t ocfs2_insert_qtree(ocfs2_filesys *fs, int type, qid_t id, loff_t *off) { unsigned int tmp = QT_TREEOFF; return ocfs2_do_insert_tree(fs, type, id, &tmp, 0, off); } /* Write dquot to file */ errcode_t ocfs2_write_dquot(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot) { errcode_t err; char *buf; struct ocfs2_global_disk_dqblk *ddquot; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; if (!dquot->d_off) { err = ocfs2_insert_qtree(fs, type, dquot->d_ddquot.dqb_id, &dquot->d_off); if (err) goto bail; } err = read_blk(fs, type, dquot->d_off / fs->fs_blocksize, buf); if (err) goto bail; ddquot = (struct ocfs2_global_disk_dqblk *)(buf + (dquot->d_off % fs->fs_blocksize)); memcpy(ddquot, &dquot->d_ddquot, sizeof(struct ocfs2_global_disk_dqblk)); ddquot->dqb_pad1 = 0; ddquot->dqb_pad2 = 0; ocfs2_swap_quota_global_dqblk(ddquot); err = write_blk(fs, type, dquot->d_off / fs->fs_blocksize, buf); bail: ocfs2_free(&buf); return err; } /* Remove dquot entry from its data block */ static errcode_t ocfs2_remove_leaf_dqentry(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot, unsigned int blk) { errcode_t err; char *buf; struct qt_disk_dqdbheader *dh; if (blk != dquot->d_off / fs->fs_blocksize) return OCFS2_ET_CORRUPT_QUOTA_FILE; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; err = read_blk(fs, type, blk, buf); if (err) goto bail; dh = (struct qt_disk_dqdbheader *)buf; ocfs2_swap_quota_leaf_block_header(dh); dh->dqdh_entries--; if (!dh->dqdh_entries) { /* Block got free? */ err = ocfs2_remove_free_dqentry(fs, type, buf, blk); if (err) goto bail; err = ocfs2_put_free_dqblk(fs, type, buf, blk); if (err) goto bail; } else { memset(buf + (dquot->d_off & (fs->fs_blocksize - 1)), 0, sizeof(struct ocfs2_global_disk_dqblk)); /* First free entry? */ if (dh->dqdh_entries == ocfs2_global_dqstr_in_blk(fs->fs_blocksize) - 1) { /* This will also write data block */ err = ocfs2_insert_free_dqentry(fs, type, buf, blk); } else err = write_blk(fs, type, blk, buf); } dquot->d_off = 0; bail: ocfs2_free(&buf); return err; } /* Remove reference to dquot from tree */ static errcode_t ocfs2_remove_tree_dqentry(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot, unsigned int *blk, int depth) { errcode_t err; char *buf; unsigned int newblk; u_int32_t *ref; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; err = read_blk(fs, type, *blk, buf); if (err) goto bail; ref = (u_int32_t *)buf; newblk = le32_to_cpu(ref[ocfs2_qtree_index(fs->fs_blocksize, dquot->d_ddquot.dqb_id, depth)]); if (depth == ocfs2_qtree_depth(fs->fs_blocksize) - 1) { err = ocfs2_remove_leaf_dqentry(fs, type, dquot, newblk); newblk = 0; } else err = ocfs2_remove_tree_dqentry(fs, type, dquot, &newblk, depth + 1); if (err) goto bail; if (!newblk) { int i; ref[ocfs2_qtree_index(fs->fs_blocksize, dquot->d_ddquot.dqb_id, depth)] = cpu_to_le32(0); /* Block got empty? */ for (i = 0; i < fs->fs_blocksize - OCFS2_QBLK_RESERVED_SPACE && !buf[i]; i++); /* Don't put the root block into the free block list */ if (i == fs->fs_blocksize - OCFS2_QBLK_RESERVED_SPACE && *blk != QT_TREEOFF) { err = ocfs2_put_free_dqblk(fs, type, buf, *blk); if (err) goto bail; *blk = 0; } else err = write_blk(fs, type, *blk, buf); } bail: ocfs2_free(&buf); return err; } /* Delete dquot from tree */ errcode_t ocfs2_delete_dquot(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot) { unsigned int tmp = QT_TREEOFF; if (!dquot->d_off) /* Even not allocated? */ return 0; return ocfs2_remove_tree_dqentry(fs, type, dquot, &tmp, 0); } /* Find entry in block */ static errcode_t ocfs2_find_block_dqentry(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot, unsigned int blk) { char *buf; errcode_t err; int i; struct ocfs2_global_disk_dqblk *ddquot; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; err = read_blk(fs, type, blk, buf); if (err) goto bail; ddquot = (struct ocfs2_global_disk_dqblk *)(buf + sizeof(struct qt_disk_dqdbheader)); for (i = 0; i < ocfs2_global_dqstr_in_blk(fs->fs_blocksize); i++, ddquot++) { if (le32_to_cpu(ddquot->dqb_id) == dquot->d_ddquot.dqb_id) { if (dquot->d_ddquot.dqb_id == 0 && ocfs2_qtree_entry_unused(ddquot)) continue; break; } } if (i == ocfs2_global_dqstr_in_blk(fs->fs_blocksize)) { err = OCFS2_ET_CORRUPT_QUOTA_FILE; goto bail; } dquot->d_off = blk * fs->fs_blocksize + ((char *)ddquot - buf); memcpy(&dquot->d_ddquot, ddquot, sizeof(struct ocfs2_global_disk_dqblk)); ocfs2_swap_quota_global_dqblk(&dquot->d_ddquot); bail: ocfs2_free(&buf); return err; } /* Find entry for given id in the tree */ static errcode_t ocfs2_find_tree_dqentry(ocfs2_filesys *fs, int type, ocfs2_cached_dquot *dquot, unsigned int blk, int depth) { errcode_t err; char *buf; u_int32_t *ref; err = ocfs2_malloc_block(fs->fs_io, &buf); if (err) return err; err = read_blk(fs, type, blk, buf); if (err) goto bail; ref = (u_int32_t *)buf; blk = le32_to_cpu(ref[ocfs2_qtree_index(fs->fs_blocksize, dquot->d_ddquot.dqb_id, depth)]); if (!blk) /* No reference? */ goto bail; if (depth < ocfs2_qtree_depth(fs->fs_blocksize) - 1) err = ocfs2_find_tree_dqentry(fs, type, dquot, blk, depth + 1); else err = ocfs2_find_block_dqentry(fs, type, dquot, blk); bail: ocfs2_free(&buf); return err; } /* * Read dquot from disk */ errcode_t ocfs2_read_dquot(ocfs2_filesys *fs, int type, qid_t id, ocfs2_cached_dquot **ret_dquot) { errcode_t err; ocfs2_cached_dquot *dquot; err = ocfs2_malloc0(sizeof(ocfs2_cached_dquot), &dquot); if (err) return err; dquot->d_ddquot.dqb_id = id; err = ocfs2_find_tree_dqentry(fs, type, dquot, QT_TREEOFF, 0); if (err) goto bail; *ret_dquot = dquot; return 0; bail: ocfs2_free(&dquot); return err; } ./ocfs2-tools-1.6.4/libocfs2/image.c0000644000176100017610000001644511500500544013713 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * image.c * * supporting structures/functions to handle ocfs2 image file * * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/byteorder.h" #include "ocfs2/image.h" void ocfs2_image_swap_header(struct ocfs2_image_hdr *hdr) { int i; if (cpu_is_little_endian) return; for (i = 0; i < hdr->hdr_superblkcnt; i++) hdr->hdr_superblocks[i] = bswap_64(hdr->hdr_superblocks[i]); hdr->hdr_magic = bswap_32(hdr->hdr_magic); hdr->hdr_version = bswap_32(hdr->hdr_version); hdr->hdr_timestamp = bswap_32(hdr->hdr_timestamp); hdr->hdr_fsblkcnt = bswap_64(hdr->hdr_fsblkcnt); hdr->hdr_fsblksz = bswap_64(hdr->hdr_fsblksz); hdr->hdr_imgblkcnt = bswap_64(hdr->hdr_imgblkcnt); hdr->hdr_bmpblksz = bswap_64(hdr->hdr_bmpblksz); hdr->hdr_superblkcnt = bswap_64(hdr->hdr_superblkcnt); } errcode_t ocfs2_image_free_bitmap(ocfs2_filesys *ofs) { struct ocfs2_image_state *ost = ofs->ost; int i; /* image bitmaps are allocated only for ocfs2 image image files */ if (!(ofs->fs_flags & OCFS2_FLAG_IMAGE_FILE)) return 0; if (!ost->ost_bmparr) return 0; for (i=0; iost_bmpblks; i++) if (ost->ost_bmparr[i].arr_self) ocfs2_free(&ost->ost_bmparr[i].arr_self); if (ost->ost_bmparr) ocfs2_free(&ost->ost_bmparr); return 0; } /* * allocate ocfs2_image_bitmap_arr and ocfs2 image bitmap blocks. o2image bitmap * block is of size OCFS2_IMAGE_BITMAP_BLOCKSIZE and ocfs2_image_bitmap_arr * tracks the bitmap blocks */ errcode_t ocfs2_image_alloc_bitmap(ocfs2_filesys *ofs) { uint64_t blks, allocsize, leftsize; struct ocfs2_image_state *ost = ofs->ost; int indx, i, n; errcode_t ret; char *buf; ost->ost_bmpblks = ((ost->ost_fsblkcnt - 1) / (OCFS2_IMAGE_BITS_IN_BLOCK)) + 1; ost->ost_bmpblksz = OCFS2_IMAGE_BITMAP_BLOCKSIZE; blks = ost->ost_bmpblks; /* allocate memory for an array to track bitmap blocks */ ret = ocfs2_malloc0((blks * sizeof(ocfs2_image_bitmap_arr)), &ost->ost_bmparr); if (ret) return ret; allocsize = blks * OCFS2_IMAGE_BITMAP_BLOCKSIZE; leftsize = allocsize; indx = 0; /* allocate bitmap blocks and assign blocks to above array */ while (leftsize) { ret = ocfs2_malloc_blocks(ofs->fs_io, allocsize/io_get_blksize(ofs->fs_io), &buf); if (ret && (ret != -ENOMEM)) goto out; if (ret == -ENOMEM) { if (allocsize == OCFS2_IMAGE_BITMAP_BLOCKSIZE) goto out; allocsize >>= 1; if (allocsize % OCFS2_IMAGE_BITMAP_BLOCKSIZE) { allocsize /= OCFS2_IMAGE_BITMAP_BLOCKSIZE; allocsize *= OCFS2_IMAGE_BITMAP_BLOCKSIZE; } continue; } n = allocsize / OCFS2_IMAGE_BITMAP_BLOCKSIZE; for (i = 0; i < n; i++) { ost->ost_bmparr[indx].arr_set_bit_cnt = 0; ost->ost_bmparr[indx].arr_map = ((char *)buf + (i * OCFS2_IMAGE_BITMAP_BLOCKSIZE)); /* remember buf address to free it later */ if (!i) ost->ost_bmparr[indx].arr_self = buf; indx++; } leftsize -= allocsize; if (leftsize <= allocsize) allocsize = leftsize; } out: /* If allocation failed free and return error */ if (leftsize) { for (i = 0; i < indx; i++) if (ost->ost_bmparr[i].arr_self) ocfs2_free(&ost->ost_bmparr[i].arr_self); ocfs2_free(&ost->ost_bmparr); } return ret; } /* * This routine loads bitmap blocks from an o2image image file into memory. * This process happens during file open. bitmap blocks reside towards * the end of the imagefile. */ errcode_t ocfs2_image_load_bitmap(ocfs2_filesys *ofs) { struct ocfs2_image_state *ost; struct ocfs2_image_hdr *hdr; uint64_t blk_off, bits_set; int count, i, j, fd; errcode_t ret; char *blk; ret = ocfs2_malloc0(sizeof(struct ocfs2_image_state), &ofs->ost); if (ret) return ret; ost = ofs->ost; ret = ocfs2_malloc_block(ofs->fs_io, &blk); if (ret) return ret; /* read ocfs2 image header */ ret = io_read_block(ofs->fs_io, 0, 1, blk); if (ret) goto out; hdr = (struct ocfs2_image_hdr *)blk; ocfs2_image_swap_header(hdr); ret = OCFS2_ET_BAD_MAGIC; if (hdr->hdr_magic != OCFS2_IMAGE_MAGIC) goto out; if (memcmp(hdr->hdr_magic_desc, OCFS2_IMAGE_DESC, sizeof(OCFS2_IMAGE_DESC))) goto out; ret = OCFS2_ET_OCFS_REV; if (hdr->hdr_version > OCFS2_IMAGE_VERSION) goto out; ost->ost_fsblkcnt = hdr->hdr_fsblkcnt; ost->ost_fsblksz = hdr->hdr_fsblksz; ost->ost_imgblkcnt = hdr->hdr_imgblkcnt; ost->ost_bmpblksz = hdr->hdr_bmpblksz; ret = ocfs2_image_alloc_bitmap(ofs); if (ret) return ret; /* load bitmap blocks ocfs2 image state */ bits_set = 0; fd = io_get_fd(ofs->fs_io); blk_off = (ost->ost_imgblkcnt + 1) * ost->ost_fsblksz; for (i = 0; i < ost->ost_bmpblks; i++) { ost->ost_bmparr[i].arr_set_bit_cnt = bits_set; /* * we don't use io_read_block as ocfs2 image bitmap block size * could be different from filesystem block size */ count = pread64(fd, ost->ost_bmparr[i].arr_map, ost->ost_bmpblksz, blk_off); if (count < ost->ost_bmpblksz) goto out; /* add bits set in this bitmap */ for (j = 0; j < (ost->ost_bmpblksz * 8); j++) if (ocfs2_test_bit(j, ost->ost_bmparr[i].arr_map)) bits_set++; blk_off += ost->ost_bmpblksz; } out: if (blk) ocfs2_free(&blk); return ret; } void ocfs2_image_mark_bitmap(ocfs2_filesys *ofs, uint64_t blkno) { struct ocfs2_image_state *ost = ofs->ost; int bitmap_blk; int bit; bit = blkno % OCFS2_IMAGE_BITS_IN_BLOCK; bitmap_blk = blkno / OCFS2_IMAGE_BITS_IN_BLOCK; ocfs2_set_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map); } int ocfs2_image_test_bit(ocfs2_filesys *ofs, uint64_t blkno) { struct ocfs2_image_state *ost = ofs->ost; int bitmap_blk; int bit; bit = blkno % OCFS2_IMAGE_BITS_IN_BLOCK; bitmap_blk = blkno / OCFS2_IMAGE_BITS_IN_BLOCK; if (ocfs2_test_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map)) return 1; else return 0; } uint64_t ocfs2_image_get_blockno(ocfs2_filesys *ofs, uint64_t blkno) { struct ocfs2_image_state *ost = ofs->ost; uint64_t ret_blk; int bitmap_blk; int i, bit; bit = blkno % OCFS2_IMAGE_BITS_IN_BLOCK; bitmap_blk = blkno / OCFS2_IMAGE_BITS_IN_BLOCK; if (ocfs2_test_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map)) { ret_blk = ost->ost_bmparr[bitmap_blk].arr_set_bit_cnt + 1; /* add bits set in this block before the block no */ for (i = 0; i < bit; i++) if (ocfs2_test_bit(i, ost->ost_bmparr[bitmap_blk].arr_map)) ret_blk++; } else ret_blk = -1; return ret_blk; } ./ocfs2-tools-1.6.4/libocfs2/xattr.c0000644000176100017610000004326511500500544013773 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * xattr.c * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" struct ocfs2_xattr_def_value_root { struct ocfs2_xattr_value_root xv; struct ocfs2_extent_rec er; }; #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) uint32_t ocfs2_xattr_uuid_hash(unsigned char *uuid) { uint32_t i, hash = 0; for (i = 0; i < OCFS2_VOL_UUID_LEN; i++) { hash = (hash << OCFS2_HASH_SHIFT) ^ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ *uuid++; } return hash; } uint32_t ocfs2_xattr_name_hash(uint32_t uuid_hash, const char *name, int name_len) { /* Get hash value of uuid from super block */ uint32_t hash = uuid_hash; int i; /* hash extended attribute name */ for (i = 0; i < name_len; i++) { hash = (hash << OCFS2_HASH_SHIFT) ^ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ *name++; } return hash; } uint16_t ocfs2_xattr_buckets_per_cluster(ocfs2_filesys *fs) { return fs->fs_clustersize / OCFS2_XATTR_BUCKET_SIZE; } uint16_t ocfs2_blocks_per_xattr_bucket(ocfs2_filesys *fs) { return OCFS2_XATTR_BUCKET_SIZE / fs->fs_blocksize; } static void ocfs2_swap_xattr_entry(struct ocfs2_xattr_entry *xe) { xe->xe_name_hash = bswap_32(xe->xe_name_hash); xe->xe_name_offset = bswap_16(xe->xe_name_offset); xe->xe_value_size = bswap_64(xe->xe_value_size); } static void ocfs2_swap_xattr_tree_root(struct ocfs2_xattr_tree_root *xt) { xt->xt_clusters = bswap_32(xt->xt_clusters); xt->xt_last_eb_blk = bswap_64(xt->xt_last_eb_blk); } static void ocfs2_swap_xattr_value_root(struct ocfs2_xattr_value_root *xr) { xr->xr_clusters = bswap_32(xr->xr_clusters); xr->xr_last_eb_blk = bswap_64(xr->xr_last_eb_blk); } static void ocfs2_swap_xattr_block_header(struct ocfs2_xattr_block *xb) { xb->xb_suballoc_slot = bswap_16(xb->xb_suballoc_slot); xb->xb_suballoc_bit = bswap_16(xb->xb_suballoc_bit); xb->xb_fs_generation = bswap_32(xb->xb_fs_generation); xb->xb_blkno = bswap_64(xb->xb_blkno); xb->xb_flags = bswap_16(xb->xb_flags); xb->xb_suballoc_loc = bswap_64(xb->xb_suballoc_loc); } static void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh) { if (cpu_is_little_endian) return; xh->xh_count = bswap_16(xh->xh_count); xh->xh_free_start = bswap_16(xh->xh_free_start); xh->xh_name_value_len = bswap_16(xh->xh_name_value_len); xh->xh_num_buckets = bswap_16(xh->xh_num_buckets); } /* * The swap barriers for xattrs are the hardest. The ocfs2_xattr_header * can be at the start of a bucket, inside an xattr block, or at the end * of an inode. Thus, we need to pass obj for the containing object. * On top of that, buckets are always 4K, regardless of blocksize. Thus, * we take objsize as an argument and fake the ocfs2_filesys we pass to * ocfs2_swap_barrier(). * * Much of this is internal to xattr.c, thankfully. The callers of the * pubic ocfs2_swap_xattr*() APIs don't have to worry about objsize! */ static void ocfs2_swap_xattr_entries_to_cpu(ocfs2_filesys *fs, void *obj, size_t objsize, struct ocfs2_xattr_header *xh) { uint16_t i; char *value; ocfs2_filesys fake_fs = { .fs_blocksize = objsize, }; if (cpu_is_little_endian) return; for (i = 0; i < xh->xh_count; i++) { struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; if (ocfs2_swap_barrier(&fake_fs, obj, xe, sizeof(struct ocfs2_xattr_entry))) break; ocfs2_swap_xattr_entry(xe); value = (char *)xh + xe->xe_name_offset + OCFS2_XATTR_SIZE(xe->xe_name_len); if (!ocfs2_xattr_is_local(xe)) { struct ocfs2_xattr_value_root *xr = (struct ocfs2_xattr_value_root *)value; if (ocfs2_swap_barrier(&fake_fs, obj, xr, OCFS2_XATTR_ROOT_SIZE)) break; ocfs2_swap_xattr_value_root(xr); ocfs2_swap_extent_list_to_cpu(&fake_fs, xh, &xr->xr_list); } else if (ocfs2_swap_barrier(&fake_fs, obj, value, OCFS2_XATTR_SIZE(xe->xe_value_size))) break; } } static void ocfs2_swap_xattr_entries_from_cpu(ocfs2_filesys *fs, void *obj, size_t objsize, struct ocfs2_xattr_header *xh) { uint16_t i; char *value; ocfs2_filesys fake_fs = { .fs_blocksize = objsize, }; if (cpu_is_little_endian) return; for (i = 0; i < xh->xh_count; i++) { struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; if (ocfs2_swap_barrier(&fake_fs, obj, xe, sizeof(struct ocfs2_xattr_entry))) break; value = (char *)xh + xe->xe_name_offset + OCFS2_XATTR_SIZE(xe->xe_name_len); if (!ocfs2_xattr_is_local(xe)) { struct ocfs2_xattr_value_root *xr = (struct ocfs2_xattr_value_root *)value; if (ocfs2_swap_barrier(&fake_fs, obj, xr, OCFS2_XATTR_ROOT_SIZE)) break; ocfs2_swap_extent_list_from_cpu(&fake_fs, xh, &xr->xr_list); ocfs2_swap_xattr_value_root(xr); } else if (ocfs2_swap_barrier(&fake_fs, obj, value, OCFS2_XATTR_SIZE(xe->xe_value_size))) break; ocfs2_swap_xattr_entry(xe); } } static void __ocfs2_swap_xattrs_to_cpu(ocfs2_filesys *fs, void *obj, size_t objsize, struct ocfs2_xattr_header *xh) { ocfs2_swap_xattr_header(xh); ocfs2_swap_xattr_entries_to_cpu(fs, obj, objsize, xh); } void ocfs2_swap_xattrs_to_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_xattr_header *xh) { return __ocfs2_swap_xattrs_to_cpu(fs, obj, fs->fs_blocksize, xh); } static void __ocfs2_swap_xattrs_from_cpu(ocfs2_filesys *fs, void *obj, size_t objsize, struct ocfs2_xattr_header *xh) { ocfs2_swap_xattr_entries_from_cpu(fs, obj, objsize, xh); ocfs2_swap_xattr_header(xh); } void ocfs2_swap_xattrs_from_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_xattr_header *xh) { return __ocfs2_swap_xattrs_from_cpu(fs, obj, fs->fs_blocksize, xh); } void ocfs2_swap_xattr_block_to_cpu(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb) { if (cpu_is_little_endian) return; ocfs2_swap_xattr_block_header(xb); if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) ocfs2_swap_xattrs_to_cpu(fs, xb, &xb->xb_attrs.xb_header); else { ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root); ocfs2_swap_extent_list_to_cpu(fs, xb, &xb->xb_attrs.xb_root.xt_list); } } void ocfs2_swap_xattr_block_from_cpu(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb) { if (cpu_is_little_endian) return; if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) ocfs2_swap_xattrs_from_cpu(fs, xb, &xb->xb_attrs.xb_header); else { ocfs2_swap_extent_list_from_cpu(fs, xb, &xb->xb_attrs.xb_root.xt_list); ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root); } ocfs2_swap_xattr_block_header(xb); } errcode_t ocfs2_read_xattr_block(ocfs2_filesys *fs, uint64_t blkno, char *xb_buf) { errcode_t ret = 0; char *blk; struct ocfs2_xattr_block *xb; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; xb = (struct ocfs2_xattr_block *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &xb->xb_check); if (ret) goto out; if (memcmp(xb->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE, strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { ret = OCFS2_ET_BAD_XATTR_BLOCK_MAGIC; goto out; } memcpy(xb_buf, blk, fs->fs_blocksize); xb = (struct ocfs2_xattr_block *)xb_buf; ocfs2_swap_xattr_block_to_cpu(fs, xb); out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_write_xattr_block(ocfs2_filesys *fs, uint64_t blkno, char *xb_buf) { errcode_t ret = 0; char *blk; struct ocfs2_xattr_block *xb; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; memcpy(blk, xb_buf, fs->fs_blocksize); xb = (struct ocfs2_xattr_block *)blk; ocfs2_swap_xattr_block_from_cpu(fs, xb); ocfs2_compute_meta_ecc(fs, blk, &xb->xb_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (!ret) fs->fs_flags |= OCFS2_FLAG_CHANGED; ocfs2_free(&blk); return ret; } errcode_t ocfs2_xattr_get_rec(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb, uint32_t name_hash, uint64_t *p_blkno, uint32_t *e_cpos, uint32_t *num_clusters) { int i; errcode_t ret = 0; char *eb_buf = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_rec *rec = NULL; struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; uint64_t e_blkno = 0; if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) return OCFS2_ET_INVALID_ARGUMENT; if (el->l_tree_depth) { ret = ocfs2_tree_find_leaf(fs, el, xb->xb_blkno, (char *)xb, name_hash, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *) eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } } for (i = el->l_next_free_rec - 1; i >= 0; i--) { rec = &el->l_recs[i]; if (rec->e_cpos <= name_hash) { e_blkno = rec->e_blkno; break; } } if (!e_blkno) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } *p_blkno = rec->e_blkno; *num_clusters = rec->e_leaf_clusters; if (e_cpos) *e_cpos = rec->e_cpos; out: if (eb_buf) ocfs2_free(&eb_buf); return ret; } uint16_t ocfs2_xattr_value_real_size(uint16_t name_len, uint16_t value_len) { uint16_t size = 0; if (value_len <= OCFS2_XATTR_INLINE_SIZE) size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len); else size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; return size; } uint16_t ocfs2_xattr_min_offset(struct ocfs2_xattr_header *xh, uint16_t size) { int i; uint16_t min_offs = size; for (i = 0 ; i < xh->xh_count; i++) { struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; size_t offs = xe->xe_name_offset; if (offs < min_offs) min_offs = offs; } return min_offs; } uint16_t ocfs2_xattr_name_value_len(struct ocfs2_xattr_header *xh) { int i; uint16_t total_len = 0; for (i = 0 ; i < xh->xh_count; i++) { struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; total_len += ocfs2_xattr_value_real_size(xe->xe_name_len, xe->xe_value_size); } return total_len; } errcode_t ocfs2_read_xattr_bucket(ocfs2_filesys *fs, uint64_t blkno, char *bucket_buf) { errcode_t ret = 0; char *bucket; struct ocfs2_xattr_header *xh; int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs); ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, blk_per_bucket, bucket); if (ret) goto out; xh = (struct ocfs2_xattr_header *)bucket; if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super)) && !(fs->fs_flags & OCFS2_FLAG_NO_ECC_CHECKS)) { ret = ocfs2_block_check_validate(bucket, OCFS2_XATTR_BUCKET_SIZE, &xh->xh_check); if (ret) goto out; } memcpy(bucket_buf, bucket, OCFS2_XATTR_BUCKET_SIZE); xh = (struct ocfs2_xattr_header *)bucket_buf; __ocfs2_swap_xattrs_to_cpu(fs, xh, OCFS2_XATTR_BUCKET_SIZE, xh); out: ocfs2_free(&bucket); return ret; } errcode_t ocfs2_write_xattr_bucket(ocfs2_filesys *fs, uint64_t blkno, char *bucket_buf) { errcode_t ret = 0; char *bucket; struct ocfs2_xattr_header *xh; int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs); if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket); if (ret) return ret; memcpy(bucket, bucket_buf, OCFS2_XATTR_BUCKET_SIZE); xh = (struct ocfs2_xattr_header *)bucket; __ocfs2_swap_xattrs_from_cpu(fs, xh, OCFS2_XATTR_BUCKET_SIZE, xh); if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super))) ocfs2_block_check_compute(bucket, OCFS2_XATTR_BUCKET_SIZE, &xh->xh_check); ret = io_write_block(fs->fs_io, blkno, blk_per_bucket, bucket); if (!ret) fs->fs_flags |= OCFS2_FLAG_CHANGED; ocfs2_free(&bucket); return ret; } struct xattr_iterate_ctxt { ocfs2_cached_inode *ci; int (*func)(ocfs2_cached_inode *ci, char *xe_buf, uint64_t xe_blkno, struct ocfs2_xattr_entry *xe, char *value_buf, uint64_t value_blkno, void *value, int in_bucket, void *priv_data); errcode_t errcode; void *priv_data; }; static int ocfs2_xattr_iterate_entries(struct xattr_iterate_ctxt *ctxt, char *xattr_buf, uint64_t xe_blkno, struct ocfs2_xattr_header *xh, int is_bucket) { int i, value_offset, block_offset; struct ocfs2_xattr_entry *xe = NULL; int iret = 0; char *value_buf; void *value; for (i = 0 ; i < xh->xh_count; i++) { xe = &xh->xh_entries[i]; value_offset = xe->xe_name_offset + OCFS2_XATTR_SIZE(xe->xe_name_len); block_offset = value_offset / ctxt->ci->ci_fs->fs_blocksize; value_buf = xattr_buf + block_offset * ctxt->ci->ci_fs->fs_blocksize; value = (char *)xh + value_offset; if (ctxt->func) { iret = ctxt->func(ctxt->ci, xattr_buf, xe_blkno, xe, value_buf, xe_blkno + block_offset, value, is_bucket, ctxt->priv_data); if (iret & (OCFS2_XATTR_ABORT | OCFS2_XATTR_ERROR)) break; } } return iret; } static int ocfs2_xattr_iterate_ibody(struct xattr_iterate_ctxt *ctxt) { struct ocfs2_xattr_header *xh = NULL; struct ocfs2_dinode *di = ctxt->ci->ci_inode; if (!(di->i_dyn_features & OCFS2_INLINE_XATTR_FL)) return 0; xh = (struct ocfs2_xattr_header *)((char *)di + ctxt->ci->ci_fs->fs_blocksize - di->i_xattr_inline_size); return ocfs2_xattr_iterate_entries(ctxt, (char *)di, di->i_blkno, xh, 0); } static int ocfs2_xattr_iterate_bucket(struct xattr_iterate_ctxt *ctxt, uint64_t blkno, uint32_t clusters) { int i, iret = 0 ; char *bucket = NULL; struct ocfs2_xattr_header *xh; ocfs2_filesys *fs = ctxt->ci->ci_fs; int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs); uint32_t bpc = ocfs2_xattr_buckets_per_cluster(fs); uint32_t num_buckets = clusters * bpc; ctxt->errcode = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket); if (ctxt->errcode) goto out; for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { ctxt->errcode = ocfs2_read_xattr_bucket(fs, blkno, bucket); if (ctxt->errcode) goto out; xh = (struct ocfs2_xattr_header *)bucket; /* * The real bucket num in this series of blocks is stored * in the 1st bucket. */ if (i == 0) num_buckets = xh->xh_num_buckets; iret = ocfs2_xattr_iterate_entries(ctxt, bucket, blkno, xh, 1); } out: if (bucket) ocfs2_free(&bucket); if (ctxt->errcode) iret |= OCFS2_XATTR_ERROR; return iret; } static int ocfs2_xattr_iterate_index_block(struct xattr_iterate_ctxt *ctxt, struct ocfs2_xattr_block *xb) { ocfs2_filesys *fs = ctxt->ci->ci_fs; struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0; uint64_t p_blkno = 0; int iret = 0; if (!el->l_next_free_rec) return 0; while (name_hash > 0) { ctxt->errcode = ocfs2_xattr_get_rec(fs, xb, name_hash, &p_blkno, &e_cpos, &num_clusters); if (ctxt->errcode) break; iret = ocfs2_xattr_iterate_bucket(ctxt, p_blkno, num_clusters); if (iret & (OCFS2_XATTR_ERROR | OCFS2_XATTR_ABORT)) break; if (e_cpos == 0) break; name_hash = e_cpos - 1; } if (ctxt->errcode) iret |= OCFS2_XATTR_ERROR; return iret; } static int ocfs2_xattr_iterate_block(struct xattr_iterate_ctxt *ctxt) { char *blk = NULL; ocfs2_filesys *fs = ctxt->ci->ci_fs; struct ocfs2_dinode *di = ctxt->ci->ci_inode; struct ocfs2_xattr_block *xb; int iret = 0; if (!di->i_xattr_loc) return 0; ctxt->errcode = ocfs2_malloc_block(fs->fs_io, &blk); if (ctxt->errcode) goto out; ctxt->errcode = ocfs2_read_xattr_block(fs, di->i_xattr_loc, blk); if (ctxt->errcode) goto out; xb = (struct ocfs2_xattr_block *)blk; if (xb->xb_flags & OCFS2_XATTR_INDEXED) iret = ocfs2_xattr_iterate_index_block(ctxt, xb); else { struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header; iret = ocfs2_xattr_iterate_entries(ctxt, blk, di->i_xattr_loc, header, 0); } out: if (blk) ocfs2_free(&blk); if (ctxt->errcode) iret |= OCFS2_XATTR_ERROR; return iret; } /* * Iterate the xattr entries on inode 'ci'. If 'func' returns * OCFS2_XATTR_ABORT or OCFS2_XATTR_ERROR, stop iteration. * If OCFS2_XATTR_ERROR, return an error from ocfs2_xattr_iterate. * * If you modify an xattr, you must restart your iteration - there is * no guarantee it is in a consistent state. */ errcode_t ocfs2_xattr_iterate(ocfs2_cached_inode *ci, int (*func)(ocfs2_cached_inode *ci, char *xe_buf, uint64_t xe_blkno, struct ocfs2_xattr_entry *xe, char *value_buf, uint64_t value_blkno, void *value, int in_bucket, void *priv_data), void *priv_data) { errcode_t ret = 0; int iret = 0; struct xattr_iterate_ctxt ctxt; if (!ocfs2_support_xattr(OCFS2_RAW_SB(ci->ci_fs->fs_super)) || (!(ci->ci_inode->i_dyn_features & OCFS2_HAS_XATTR_FL))) return 0; ctxt.ci = ci; ctxt.func = func; ctxt.priv_data = priv_data; ctxt.errcode = 0; iret = ocfs2_xattr_iterate_ibody(&ctxt); if (!(iret & (OCFS2_XATTR_ABORT | OCFS2_XATTR_ERROR))) iret = ocfs2_xattr_iterate_block(&ctxt); if (iret & OCFS2_XATTR_ERROR) ret = ctxt.errcode; return ret; } ./ocfs2-tools-1.6.4/libocfs2/extent_tree.c0000644000176100017610000032606711500500544015163 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extent_tree.c * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #include #include #include #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include "extent_tree.h" static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, uint64_t blkno) { struct ocfs2_dinode *di = et->et_object; di->i_last_eb_blk = blkno; } static uint64_t ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et) { struct ocfs2_dinode *di = et->et_object; return di->i_last_eb_blk; } static void ocfs2_dinode_update_clusters(struct ocfs2_extent_tree *et, uint32_t clusters) { struct ocfs2_dinode *di = et->et_object; di->i_clusters += clusters; } static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et) { struct ocfs2_dinode *di = et->et_object; et->et_root_el = &di->id2.i_list; } static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { .eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, .eo_update_clusters = ocfs2_dinode_update_clusters, .eo_fill_root_el = ocfs2_dinode_fill_root_el, }; static void ocfs2_refcount_tree_fill_root_el(struct ocfs2_extent_tree *et) { struct ocfs2_refcount_block *rb = et->et_object; et->et_root_el = &rb->rf_list; } static void ocfs2_refcount_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, uint64_t blkno) { struct ocfs2_refcount_block *rb = et->et_object; rb->rf_last_eb_blk = blkno; } static uint64_t ocfs2_refcount_tree_get_last_eb_blk(struct ocfs2_extent_tree *et) { struct ocfs2_refcount_block *rb = et->et_object; return rb->rf_last_eb_blk; } static void ocfs2_refcount_tree_update_clusters(struct ocfs2_extent_tree *et, uint32_t clusters) { struct ocfs2_refcount_block *rb = et->et_object; rb->rf_clusters += clusters; } static enum ocfs2_contig_type ocfs2_refcount_tree_extent_contig(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_extent_rec *ext, struct ocfs2_extent_rec *insert_rec) { return CONTIG_NONE; } static struct ocfs2_extent_tree_operations ocfs2_refcount_tree_et_ops = { .eo_set_last_eb_blk = ocfs2_refcount_tree_set_last_eb_blk, .eo_get_last_eb_blk = ocfs2_refcount_tree_get_last_eb_blk, .eo_update_clusters = ocfs2_refcount_tree_update_clusters, .eo_fill_root_el = ocfs2_refcount_tree_fill_root_el, .eo_extent_contig = ocfs2_refcount_tree_extent_contig, }; static void ocfs2_xattr_value_fill_root_el(struct ocfs2_extent_tree *et) { struct ocfs2_xattr_value_root *xv = et->et_object; et->et_root_el = &xv->xr_list; } static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, uint64_t blkno) { struct ocfs2_xattr_value_root *xv = et->et_object; xv->xr_last_eb_blk = blkno; } static uint64_t ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et) { struct ocfs2_xattr_value_root *xv = et->et_object; return xv->xr_last_eb_blk; } static void ocfs2_xattr_value_update_clusters(struct ocfs2_extent_tree *et, uint32_t clusters) { struct ocfs2_xattr_value_root *xv = et->et_object; xv->xr_clusters += clusters; } static uint32_t ocfs2_xattr_value_get_clusters(struct ocfs2_extent_tree *et) { struct ocfs2_xattr_value_root *xv = et->et_object; return xv->xr_clusters; } static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = { .eo_set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, .eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, .eo_update_clusters = ocfs2_xattr_value_update_clusters, .eo_get_clusters = ocfs2_xattr_value_get_clusters, .eo_fill_root_el = ocfs2_xattr_value_fill_root_el, }; static void ocfs2_dx_root_set_last_eb_blk (struct ocfs2_extent_tree *et, uint64_t blkno) { struct ocfs2_dx_root_block *dx_root = et->et_object; dx_root->dr_last_eb_blk = blkno; } static uint64_t ocfs2_dx_root_get_last_eb_blk (struct ocfs2_extent_tree *et) { struct ocfs2_dx_root_block *dx_root = et->et_object; return dx_root->dr_last_eb_blk; } static void ocfs2_dx_root_update_clusters(struct ocfs2_extent_tree *et, uint32_t clusters) { struct ocfs2_dx_root_block *dx_root = et->et_object; dx_root->dr_clusters += clusters; } static int ocfs2_dx_root_sanity_check(struct ocfs2_extent_tree *et) { struct ocfs2_dx_root_block *dx_root = (struct ocfs2_dx_root_block *)et->et_object; assert(OCFS2_IS_VALID_DX_ROOT(dx_root)); return 0; } static void ocfs2_dx_root_fill_root_el (struct ocfs2_extent_tree *et) { struct ocfs2_dx_root_block *dx_root = et->et_object; et->et_root_el = &dx_root->dr_list; } static struct ocfs2_extent_tree_operations ocfs2_dx_root_et_ops = { .eo_set_last_eb_blk = ocfs2_dx_root_set_last_eb_blk, .eo_get_last_eb_blk = ocfs2_dx_root_get_last_eb_blk, .eo_update_clusters = ocfs2_dx_root_update_clusters, .eo_sanity_check = ocfs2_dx_root_sanity_check, .eo_fill_root_el = ocfs2_dx_root_fill_root_el, }; static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno, ocfs2_root_write_func write, void *obj, struct ocfs2_extent_tree_operations *ops) { et->et_ops = ops; et->et_root_buf = buf; et->et_root_blkno = blkno; et->et_root_write = write; et->et_object = obj; et->et_ops->eo_fill_root_el(et); if (!et->et_ops->eo_fill_max_leaf_clusters) et->et_max_leaf_clusters = 0; else et->et_ops->eo_fill_max_leaf_clusters(fs, et); } void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno) { __ocfs2_init_extent_tree(et, fs, buf, blkno, ocfs2_write_inode, buf, &ocfs2_dinode_et_ops); } void ocfs2_init_refcount_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno) { __ocfs2_init_extent_tree(et, fs, buf, blkno, ocfs2_write_refcount_block, buf, &ocfs2_refcount_tree_et_ops); } void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno, ocfs2_root_write_func write, struct ocfs2_xattr_value_root *xv) { __ocfs2_init_extent_tree(et, fs, buf, blkno, write, xv, &ocfs2_xattr_value_et_ops); } void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno) { __ocfs2_init_extent_tree(et, fs, buf, blkno, ocfs2_write_dx_root, buf, &ocfs2_dx_root_et_ops); } static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et, uint64_t new_last_eb_blk) { et->et_ops->eo_set_last_eb_blk(et, new_last_eb_blk); } static inline uint64_t ocfs2_et_get_last_eb_blk(struct ocfs2_extent_tree *et) { return et->et_ops->eo_get_last_eb_blk(et); } static inline void ocfs2_et_update_clusters(struct ocfs2_extent_tree *et, uint32_t clusters) { return et->et_ops->eo_update_clusters(et, clusters); } struct insert_ctxt { ocfs2_filesys *fs; struct ocfs2_extent_tree *et; struct ocfs2_extent_rec rec; }; /* * Reset the actual path elements so that we can re-use the structure * to build another path. Generally, this involves freeing the buffer * heads. */ static void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root) { int i, start = 0, depth = 0; struct ocfs2_path_item *node; if (keep_root) start = 1; for(i = start; i < path_num_items(path); i++) { node = &path->p_node[i]; if (!node->buf) continue; ocfs2_free(&node->buf); node->blkno = 0; node->buf = NULL; node->el = NULL; } /* * Tree depth may change during truncate, or insert. If we're * keeping the root extent list, then make sure that our path * structure reflects the proper depth. */ if (keep_root) depth = path_root_el(path)->l_tree_depth; path->p_tree_depth = depth; } void ocfs2_free_path(struct ocfs2_path *path) { /* We don't free the root because often in libocfs2 the root is a * shared buffer such as the inode. Caller must be responsible for * handling the root of the path. */ if (path) { ocfs2_reinit_path(path, 1); ocfs2_free(&path); } } static enum ocfs2_contig_type ocfs2_extent_rec_contig(ocfs2_filesys *fs, struct ocfs2_extent_rec *ext, struct ocfs2_extent_rec *insert_rec); static inline enum ocfs2_contig_type ocfs2_et_extent_contig(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_extent_rec *rec, struct ocfs2_extent_rec *insert_rec) { if (et->et_ops->eo_extent_contig) return et->et_ops->eo_extent_contig(fs, et, rec, insert_rec); return ocfs2_extent_rec_contig(fs, rec, insert_rec); } /* * All the elements of src into dest. After this call, src could be freed * without affecting dest. * * Both paths should have the same root. Any non-root elements of dest * will be freed. */ static void ocfs2_cp_path(ocfs2_filesys *fs, struct ocfs2_path *dest, struct ocfs2_path *src) { int i; struct ocfs2_extent_block *eb = NULL; assert(path_root_blkno(dest) == path_root_blkno(src)); dest->p_tree_depth = src->p_tree_depth; for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) { if (!src->p_node[i].buf) { if (dest->p_node[i].buf) ocfs2_free(dest->p_node[i].buf); dest->p_node[i].blkno = 0; dest->p_node[i].buf = NULL; dest->p_node[i].el = NULL; continue; } if (!dest->p_node[i].buf) ocfs2_malloc_block(fs->fs_io, &dest->p_node[i].buf); assert(dest->p_node[i].buf); memcpy(dest->p_node[i].buf, src->p_node[i].buf, fs->fs_blocksize); eb = (struct ocfs2_extent_block *)dest->p_node[i].buf; dest->p_node[i].el = &eb->h_list; dest->p_node[i].blkno = src->p_node[i].blkno; } } /* * Make the *dest path the same as src and re-initialize src path to * have a root only. */ static void ocfs2_mv_path(struct ocfs2_path *dest, struct ocfs2_path *src) { int i; assert(path_root_blkno(dest) == path_root_blkno(src)); for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) { ocfs2_free(&dest->p_node[i].buf); dest->p_node[i].blkno = src->p_node[i].blkno; dest->p_node[i].buf = src->p_node[i].buf; dest->p_node[i].el = src->p_node[i].el; src->p_node[i].blkno = 0; src->p_node[i].buf = NULL; src->p_node[i].el = NULL; } } /* * Insert an extent block at given index. * * Note: * This buf will be inserted into the path, so the caller shouldn't free it. */ static inline void ocfs2_path_insert_eb(struct ocfs2_path *path, int index, char *buf) { struct ocfs2_extent_block *eb = (struct ocfs2_extent_block *) buf; /* * Right now, no root buf is an extent block, so this helps * catch code errors with dinode trees. The assertion can be * safely removed if we ever need to insert extent block * structures at the root. */ assert(index); path->p_node[index].blkno = eb->h_blkno; path->p_node[index].buf = (char *)buf; path->p_node[index].el = &eb->h_list; } static struct ocfs2_path *ocfs2_new_path(char *buf, struct ocfs2_extent_list *root_el, uint64_t blkno) { errcode_t ret = 0; struct ocfs2_path *path = NULL; assert(root_el->l_tree_depth < OCFS2_MAX_PATH_DEPTH); ret = ocfs2_malloc0(sizeof(*path), &path); if (path) { path->p_tree_depth = root_el->l_tree_depth; path->p_node[0].blkno = blkno; path->p_node[0].buf = buf; path->p_node[0].el = root_el; } return path; } static struct ocfs2_path *ocfs2_new_path_from_path(struct ocfs2_path *path) { return ocfs2_new_path(path_root_buf(path), path_root_el(path), path_root_blkno(path)); } struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et) { return ocfs2_new_path(et->et_root_buf, et->et_root_el, et->et_root_blkno); } /* Write all the extent block information to the disk. * We write all paths furthur down than subtree_index. * The caller will handle writing the sub_index. */ static errcode_t ocfs2_write_path_eb(ocfs2_filesys *fs, struct ocfs2_path *path, int sub_index) { errcode_t ret; int i; for (i = path->p_tree_depth; i > sub_index; i--) { ret = ocfs2_write_extent_block(fs, path->p_node[i].blkno, path->p_node[i].buf); if (ret) return ret; } return 0; } /* some extent blocks is modified and we need to synchronize them to the disk * accordingly. * * We will not update the inode if subtree_index is "0" since it should be * updated by the caller. * * left_path or right_path can be NULL, but they can't be NULL in the same time. * And if they are both not NULL, we will treat subtree_index in the right_path * as the right extent block information. */ static errcode_t ocfs2_sync_path_to_disk(ocfs2_filesys *fs, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index) { errcode_t ret = 0; struct ocfs2_path *path = NULL; assert(left_path || right_path); if (left_path) { ret = ocfs2_write_path_eb(fs, left_path, subtree_index); if (ret) goto bail; } if (right_path) { ret = ocfs2_write_path_eb(fs, right_path, subtree_index); if (ret) goto bail; } if (subtree_index) { /* subtree_index indicates an extent block. */ path = right_path ? right_path : left_path; ret = ocfs2_write_extent_block(fs, path->p_node[subtree_index].blkno, path->p_node[subtree_index].buf); if (ret) goto bail; } bail: return ret; } /* * Return the index of the extent record which contains cluster #v_cluster. * -1 is returned if it was not found. * * Should work fine on interior and exterior nodes. */ int ocfs2_search_extent_list(struct ocfs2_extent_list *el, uint32_t v_cluster) { int ret = -1; int i; struct ocfs2_extent_rec *rec; uint32_t rec_end, rec_start, clusters; for(i = 0; i < el->l_next_free_rec; i++) { rec = &el->l_recs[i]; rec_start = rec->e_cpos; clusters = ocfs2_rec_clusters(el->l_tree_depth, rec); rec_end = rec_start + clusters; if (v_cluster >= rec_start && v_cluster < rec_end) { ret = i; break; } } return ret; } /* * NOTE: ocfs2_block_extent_contig(), ocfs2_extents_adjacent() and * ocfs2_extent_rec_contig only work properly against leaf nodes! */ static inline int ocfs2_block_extent_contig(ocfs2_filesys *fs, struct ocfs2_extent_rec *ext, uint64_t blkno) { uint64_t blk_end = ext->e_blkno; blk_end += ocfs2_clusters_to_blocks(fs, ext->e_leaf_clusters); return blkno == blk_end; } static inline int ocfs2_extents_adjacent(struct ocfs2_extent_rec *left, struct ocfs2_extent_rec *right) { uint32_t left_range; left_range = left->e_cpos + left->e_leaf_clusters; return (left_range == right->e_cpos); } static enum ocfs2_contig_type ocfs2_extent_rec_contig(ocfs2_filesys *fs, struct ocfs2_extent_rec *ext, struct ocfs2_extent_rec *insert_rec) { uint64_t blkno = insert_rec->e_blkno; /* * Refuse to coalesce extent records with different flag * fields - we don't want to mix unwritten extents with user * data. */ if (ext->e_flags != insert_rec->e_flags) return CONTIG_NONE; if (ocfs2_extents_adjacent(ext, insert_rec) && ocfs2_block_extent_contig(fs, ext, blkno)) return CONTIG_RIGHT; blkno = ext->e_blkno; if (ocfs2_extents_adjacent(insert_rec, ext) && ocfs2_block_extent_contig(fs, insert_rec, blkno)) return CONTIG_LEFT; return CONTIG_NONE; } /* * NOTE: We can have pretty much any combination of contiguousness and * appending. * * The usefulness of APPEND_TAIL is more in that it lets us know that * we'll have to update the path to that leaf. */ enum ocfs2_append_type { APPEND_NONE = 0, APPEND_TAIL, }; enum ocfs2_split_type { SPLIT_NONE = 0, SPLIT_LEFT, SPLIT_RIGHT, }; struct ocfs2_insert_type { enum ocfs2_split_type ins_split; enum ocfs2_append_type ins_appending; enum ocfs2_contig_type ins_contig; int ins_contig_index; int ins_tree_depth; }; struct ocfs2_merge_ctxt { enum ocfs2_contig_type c_contig_type; int c_has_empty_extent; int c_split_covers_rec; }; /* * Helper function for ocfs2_add_branch() and shift_tree_depth(). * * Returns the sum of the rightmost extent rec logical offset and * cluster count. * * ocfs2_add_branch() uses this to determine what logical cluster * value should be populated into the leftmost new branch records. * * shift_tree_depth() uses this to determine the # clusters * value for the new topmost tree record. */ static inline uint32_t ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el) { uint16_t i = el->l_next_free_rec - 1; return el->l_recs[i].e_cpos + ocfs2_rec_clusters(el->l_tree_depth, &el->l_recs[i]); } /* * Add an entire tree branch to our inode. eb_buf is the extent block * to start at, if we don't want to start the branch at the dinode * structure. * * last_eb_buf is required as we have to update it's next_leaf pointer * for the new last extent block. * * the new branch will be 'empty' in the sense that every block will * contain a single record with e_clusters == 0. */ static int ocfs2_add_branch(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, char *eb_buf, char **last_eb_buf) { errcode_t ret; int new_blocks, i; uint64_t next_blkno, new_last_eb_blk; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *eb_el; struct ocfs2_extent_list *el; uint32_t new_cpos; uint64_t *new_blknos = NULL; char **new_eb_bufs = NULL; char *buf = NULL; assert(*last_eb_buf); if (eb_buf) { eb = (struct ocfs2_extent_block *) eb_buf; el = &eb->h_list; } else el = et->et_root_el; /* we never add a branch to a leaf. */ assert(el->l_tree_depth); new_blocks = el->l_tree_depth; /* allocate the number of new eb blocks we need new_blocks should be * allocated here.*/ ret = ocfs2_malloc0(sizeof(uint64_t) * new_blocks, &new_blknos); if (ret) goto bail; memset(new_blknos, 0, sizeof(uint64_t) * new_blocks); ret = ocfs2_malloc0(sizeof(char *) * new_blocks, &new_eb_bufs); if (ret) goto bail; memset(new_eb_bufs, 0, sizeof(char *) * new_blocks); for (i = 0; i < new_blocks; i++) { ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; new_eb_bufs[i] = buf; ret = ocfs2_new_extent_block(fs, &new_blknos[i]); if (ret) goto bail; ret = ocfs2_read_extent_block(fs, new_blknos[i], buf); if (ret) goto bail; } eb = (struct ocfs2_extent_block *)(*last_eb_buf); new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); /* Note: new_eb_bufs[new_blocks - 1] is the guy which will be * linked with the rest of the tree. * conversly, new_eb_bufs[0] is the new bottommost leaf. * * when we leave the loop, new_last_eb_blk will point to the * newest leaf, and next_blkno will point to the topmost extent * block. */ next_blkno = new_last_eb_blk = 0; for(i = 0; i < new_blocks; i++) { buf = new_eb_bufs[i]; eb = (struct ocfs2_extent_block *) buf; eb_el = &eb->h_list; eb->h_next_leaf_blk = 0; eb_el->l_tree_depth = i; eb_el->l_next_free_rec = 1; memset(eb_el->l_recs, 0, sizeof(struct ocfs2_extent_rec) * eb_el->l_count); /* * This actually counts as an empty extent as * c_clusters == 0 */ eb_el->l_recs[0].e_cpos = new_cpos; eb_el->l_recs[0].e_blkno = next_blkno; /* * eb_el isn't always an interior node, but even leaf * nodes want a zero'd flags and reserved field so * this gets the whole 32 bits regardless of use. */ eb_el->l_recs[0].e_int_clusters = 0; if (!eb_el->l_tree_depth) new_last_eb_blk = eb->h_blkno; next_blkno = eb->h_blkno; } /* Link the new branch into the rest of the tree (el will * either be on the fe, or the extent block passed in. */ i = el->l_next_free_rec; el->l_recs[i].e_blkno = next_blkno; el->l_recs[i].e_cpos = new_cpos; el->l_recs[i].e_int_clusters = 0; el->l_next_free_rec++; /* fe needs a new last extent block pointer, as does the * next_leaf on the previously last-extent-block. */ ocfs2_et_set_last_eb_blk(et, new_last_eb_blk); /* here all the extent block and the new inode information should be * written back to the disk. */ for(i = 0; i < new_blocks; i++) { buf = new_eb_bufs[i]; ret = ocfs2_write_extent_block(fs, new_blknos[i], buf); if (ret) goto bail; } /* update last_eb_buf's next_leaf pointer for * the new last extent block. */ eb = (struct ocfs2_extent_block *)(*last_eb_buf); eb->h_next_leaf_blk = new_last_eb_blk; ret = ocfs2_write_extent_block(fs, eb->h_blkno, *last_eb_buf); if (ret) goto bail; if (eb_buf) { eb = (struct ocfs2_extent_block *)eb_buf; ret = ocfs2_write_extent_block(fs, eb->h_blkno, eb_buf); if (ret) goto bail; } /* * Some callers want to track the rightmost leaf so pass it * back here. */ memcpy(*last_eb_buf, new_eb_bufs[0], fs->fs_blocksize); /* The inode information isn't updated since we use duplicated extent * block in the insertion and it may fail in other steps. */ ret = 0; bail: if (new_eb_bufs) { for (i = 0; i < new_blocks; i++) if (new_eb_bufs[i]) ocfs2_free(&new_eb_bufs[i]); ocfs2_free(&new_eb_bufs); } if (ret && new_blknos) for (i = 0; i < new_blocks; i++) if (new_blknos[i]) ocfs2_delete_extent_block(fs, new_blknos[i]); if (new_blknos) ocfs2_free(&new_blknos); return ret; } /* * Should only be called when there is no space left in any of the * leaf nodes. What we want to do is find the lowest tree depth * non-leaf extent block with room for new records. There are three * valid results of this search: * * 1) a lowest extent block is found, then we pass it back in * *target_buf and return '0' * * 2) the search fails to find anything, but the dinode has room. We * pass NULL back in *target_buf, but still return '0' * * 3) the search fails to find anything AND the dinode is full, in * which case we return > 0 * * return status < 0 indicates an error. */ static errcode_t ocfs2_find_branch_target(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, char **target_buf) { errcode_t ret = 0; int i; uint64_t blkno; struct ocfs2_extent_block *eb; char *buf = NULL, *lowest_buf = NULL; struct ocfs2_extent_list *el = et->et_root_el; *target_buf = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; while(el->l_tree_depth > 1) { if (el->l_next_free_rec == 0) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto bail; } i = el->l_next_free_rec - 1; blkno = el->l_recs[i].e_blkno; if (!blkno) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto bail; } ret = ocfs2_read_extent_block(fs, blkno, buf); if (ret) goto bail; eb = (struct ocfs2_extent_block *) buf; el = &eb->h_list; if (el->l_next_free_rec < el->l_count) lowest_buf = buf; } el = et->et_root_el; /* If we didn't find one and the fe doesn't have any room, * then return '1' */ if (!lowest_buf && el->l_next_free_rec == el->l_count) ret = 1; *target_buf = lowest_buf; bail: if (buf && !*target_buf) ocfs2_free(&buf); return ret; } /* * This function will discard the rightmost extent record. */ static void ocfs2_shift_records_right(struct ocfs2_extent_list *el) { int next_free = el->l_next_free_rec; int count = el->l_count; unsigned int num_bytes; assert(next_free); /* This will cause us to go off the end of our extent list. */ assert(next_free < count); num_bytes = sizeof(struct ocfs2_extent_rec) * next_free; memmove(&el->l_recs[1], &el->l_recs[0], num_bytes); } static void ocfs2_rotate_leaf(struct ocfs2_extent_list *el, struct ocfs2_extent_rec *insert_rec) { int i, insert_index, next_free, has_empty, num_bytes; uint32_t insert_cpos = insert_rec->e_cpos; struct ocfs2_extent_rec *rec; next_free = el->l_next_free_rec; has_empty = ocfs2_is_empty_extent(&el->l_recs[0]); assert(next_free); /* The tree code before us didn't allow enough room in the leaf. */ if (el->l_next_free_rec == el->l_count && !has_empty) assert(0); /* * The easiest way to approach this is to just remove the * empty extent and temporarily decrement next_free. */ if (has_empty) { /* * If next_free was 1 (only an empty extent), this * loop won't execute, which is fine. We still want * the decrement above to happen. */ for(i = 0; i < (next_free - 1); i++) el->l_recs[i] = el->l_recs[i+1]; next_free--; } /* Figure out what the new record index should be. */ for(i = 0; i < next_free; i++) { rec = &el->l_recs[i]; if (insert_cpos < rec->e_cpos) break; } insert_index = i; assert(insert_index >= 0); assert(insert_index < el->l_count); assert(insert_index <= next_free); /* No need to memmove if we're just adding to the tail. */ if (insert_index != next_free) { assert(next_free < el->l_count); num_bytes = next_free - insert_index; num_bytes *= sizeof(struct ocfs2_extent_rec); memmove(&el->l_recs[insert_index + 1], &el->l_recs[insert_index], num_bytes); } /* * Either we had an empty extent, and need to re-increment or * there was no empty extent on a non full rightmost leaf node, * in which case we still need to increment. */ next_free++; el->l_next_free_rec = next_free; /* Make sure none of the math above just messed up our tree. */ assert(el->l_next_free_rec <= el->l_count); el->l_recs[insert_index] = *insert_rec; } static void ocfs2_remove_empty_extent(struct ocfs2_extent_list *el) { int size, num_recs = el->l_next_free_rec; assert(num_recs); if (ocfs2_is_empty_extent(&el->l_recs[0])) { num_recs--; size = num_recs * sizeof(struct ocfs2_extent_rec); memmove(&el->l_recs[0], &el->l_recs[1], size); memset(&el->l_recs[num_recs], 0, sizeof(struct ocfs2_extent_rec)); el->l_next_free_rec = num_recs; } } /* * Create an empty extent record . * * l_next_free_rec may be updated. * * If an empty extent already exists do nothing. */ static void ocfs2_create_empty_extent(struct ocfs2_extent_list *el) { int next_free = el->l_next_free_rec; assert(el->l_tree_depth == 0); if (next_free == 0) goto set_and_inc; if (ocfs2_is_empty_extent(&el->l_recs[0])) return; ocfs2_shift_records_right(el); set_and_inc: el->l_next_free_rec += 1; memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); } /* * For a rotation which involves two leaf nodes, the "root node" is * the lowest level tree node which contains a path to both leafs. This * resulting set of information can be used to form a complete "subtree" * * This function is passed two full paths from the dinode down to a * pair of adjacent leaves. It's task is to figure out which path * index contains the subtree root - this can be the root index itself * in a worst-case rotation. * * The array index of the subtree root is passed back. */ static int ocfs2_find_subtree_root(struct ocfs2_path *left, struct ocfs2_path *right) { int i = 0; /* Check that the caller passed in two paths from the same tree. */ assert(path_root_blkno(left) == path_root_blkno(right)); do { i++; /* The caller didn't pass two adjacent paths. */ if (i > left->p_tree_depth) assert(0); } while (left->p_node[i].blkno == right->p_node[i].blkno); return i - 1; } typedef errcode_t (path_insert_t)(void *, char *); /* * Traverse a btree path in search of cpos, starting at root_el. * * This code can be called with a cpos larger than the tree, in which * case it will return the rightmost path. */ static errcode_t __ocfs2_find_path(ocfs2_filesys *fs, struct ocfs2_extent_list *root_el, uint32_t cpos, path_insert_t *func, void *data) { int i, ret = 0; uint32_t range; uint64_t blkno; char *buf = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *rec; el = root_el; while (el->l_tree_depth) { if (el->l_next_free_rec == 0) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } for(i = 0; i < el->l_next_free_rec - 1; i++) { rec = &el->l_recs[i]; /* * In the case that cpos is off the allocation * tree, this should just wind up returning the * rightmost record. */ range = rec->e_cpos + ocfs2_rec_clusters(el->l_tree_depth, rec); if (cpos >= rec->e_cpos && cpos < range) break; } blkno = el->l_recs[i].e_blkno; if (blkno == 0) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_extent_block(fs, blkno, buf); if (ret) goto out; eb = (struct ocfs2_extent_block *) buf; el = &eb->h_list; if (el->l_next_free_rec > el->l_count) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } /* The user's callback must give us the tip for how to * handle the buf we allocated by return values. * * 1) return '0': * the function succeeds,and it will use the buf and * take care of the buffer release. * * 2) return > 0: * the function succeeds, and there is no need for buf, * so we will release it. * * 3) return < 0: * the function fails. */ if (func) { ret = func(data, buf); if (ret == 0) { buf = NULL; continue; } else if (ret < 0) goto out; } ocfs2_free(&buf); buf = NULL; } out: /* Catch any trailing buf that the loop didn't handle. */ if (buf) ocfs2_free(&buf); return ret; } /* * Given an initialized path (that is, it has a valid root extent * list), this function will traverse the btree in search of the path * which would contain cpos. * * The path traveled is recorded in the path structure. * * Note that this will not do any comparisons on leaf node extent * records, so it will work fine in the case that we just added a tree * branch. */ struct find_path_data { int index; struct ocfs2_path *path; }; static errcode_t find_path_ins(void *data, char *eb) { struct find_path_data *fp = data; ocfs2_path_insert_eb(fp->path, fp->index, eb); fp->index++; return 0; } int ocfs2_find_path(ocfs2_filesys *fs, struct ocfs2_path *path, uint32_t cpos) { struct find_path_data data; data.index = 1; data.path = path; return __ocfs2_find_path(fs, path_root_el(path), cpos, find_path_ins, &data); } /* * Find the leaf block in the tree which would contain cpos. No * checking of the actual leaf is done. * * This function doesn't handle non btree extent lists. */ int ocfs2_tree_find_leaf(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t el_blkno, char *el_blk, uint32_t cpos, char **leaf_buf) { int ret; char *buf = NULL; struct ocfs2_path *path = NULL; assert(el->l_tree_depth > 0); path = ocfs2_new_path(el_blk, el, el_blkno); if (!path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, path, cpos); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; memcpy(buf, path_leaf_buf(path), fs->fs_blocksize); *leaf_buf = buf; out: ocfs2_free_path(path); return ret; } int ocfs2_find_leaf(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t cpos, char **leaf_buf) { return ocfs2_tree_find_leaf(fs, &di->id2.i_list, di->i_blkno, (char *)di, cpos, leaf_buf); } /* * Adjust the adjacent records (left_rec, right_rec) involved in a rotation. * * Basically, we've moved stuff around at the bottom of the tree and * we need to fix up the extent records above the changes to reflect * the new changes. * * left_rec: the record on the left. * left_child_el: is the child list pointed to by left_rec * right_rec: the record to the right of left_rec * right_child_el: is the child list pointed to by right_rec * * By definition, this only works on interior nodes. */ static void ocfs2_adjust_adjacent_records(struct ocfs2_extent_rec *left_rec, struct ocfs2_extent_list *left_child_el, struct ocfs2_extent_rec *right_rec, struct ocfs2_extent_list *right_child_el) { uint32_t left_clusters, right_end; /* * Interior nodes never have holes. Their cpos is the cpos of * the leftmost record in their child list. Their cluster * count covers the full theoretical range of their child list * - the range between their cpos and the cpos of the record * immediately to their right. */ left_clusters = right_child_el->l_recs[0].e_cpos; if (ocfs2_is_empty_extent(&right_child_el->l_recs[0])) { assert(right_child_el->l_next_free_rec > 1); left_clusters = right_child_el->l_recs[1].e_cpos; } left_clusters -= left_rec->e_cpos; left_rec->e_int_clusters = left_clusters; /* * Calculate the rightmost cluster count boundary before * moving cpos - we will need to adjust clusters after * updating e_cpos to keep the same highest cluster count. */ right_end = right_rec->e_cpos; right_end += right_rec->e_int_clusters; right_rec->e_cpos = left_rec->e_cpos; right_rec->e_cpos += left_clusters; right_end -= right_rec->e_cpos; right_rec->e_int_clusters = right_end; } /* * Adjust the adjacent root node records involved in a * rotation. left_el_blkno is passed in as a key so that we can easily * find it's index in the root list. */ static void ocfs2_adjust_root_records(struct ocfs2_extent_list *root_el, struct ocfs2_extent_list *left_el, struct ocfs2_extent_list *right_el, uint64_t left_el_blkno) { int i; assert(root_el->l_tree_depth > left_el->l_tree_depth); for(i = 0; i < root_el->l_next_free_rec - 1; i++) { if (root_el->l_recs[i].e_blkno == left_el_blkno) break; } /* * The path walking code should have never returned a root and * two paths which are not adjacent. */ assert(i < (root_el->l_next_free_rec - 1)); ocfs2_adjust_adjacent_records(&root_el->l_recs[i], left_el, &root_el->l_recs[i + 1], right_el); } /* * We've changed a leaf block (in right_path) and need to reflect that * change back up the subtree. * * This happens in multiple places: * - When we've moved an extent record from the left path leaf to the right * path leaf to make room for an empty extent in the left path leaf. * - When our insert into the right path leaf is at the leftmost edge * and requires an update of the path immediately to it's left. This * can occur at the end of some types of rotation and appending inserts. */ static void ocfs2_complete_edge_insert(ocfs2_filesys *fs, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index) { int i, idx; uint64_t blkno; struct ocfs2_extent_list *el, *left_el, *right_el; struct ocfs2_extent_rec *left_rec, *right_rec; /* * Update the counts and position values within all the * interior nodes to reflect the leaf rotation we just did. * * The root node is handled below the loop. * * We begin the loop with right_el and left_el pointing to the * leaf lists and work our way up. * * NOTE: within this loop, left_el and right_el always refer * to the *child* lists. */ left_el = path_leaf_el(left_path); right_el = path_leaf_el(right_path); for(i = left_path->p_tree_depth - 1; i > subtree_index; i--) { /* * One nice property of knowing that all of these * nodes are below the root is that we only deal with * the leftmost right node record and the rightmost * left node record. */ el = left_path->p_node[i].el; idx = left_el->l_next_free_rec - 1; left_rec = &el->l_recs[idx]; el = right_path->p_node[i].el; right_rec = &el->l_recs[0]; ocfs2_adjust_adjacent_records(left_rec, left_el, right_rec, right_el); /* * Setup our list pointers now so that the current * parents become children in the next iteration. */ left_el = left_path->p_node[i].el; right_el = right_path->p_node[i].el; } /* * At the root node, adjust the two adjacent records which * begin our path to the leaves. */ el = left_path->p_node[subtree_index].el; left_el = left_path->p_node[subtree_index + 1].el; right_el = right_path->p_node[subtree_index + 1].el; blkno = left_path->p_node[subtree_index + 1].blkno; ocfs2_adjust_root_records(el, left_el, right_el, blkno); /* ocfs2_adjust_root_records only update the extent block in the left * path, and actually right_path->p_node[subtree_index].eb indicates the * same extent block, so we must keep them the same content. */ memcpy(right_path->p_node[subtree_index].buf, left_path->p_node[subtree_index].buf, fs->fs_blocksize); } /* Rotate the subtree to right. * * Note: After successful rotation, the extent block will be flashed * to disk accordingly. */ static errcode_t ocfs2_rotate_subtree_right(ocfs2_filesys *fs, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index) { errcode_t ret; int i; char *right_leaf_eb; char *left_leaf_eb = NULL; struct ocfs2_extent_list *right_el, *left_el; struct ocfs2_extent_rec move_rec; struct ocfs2_extent_block *eb; left_leaf_eb = path_leaf_buf(left_path); eb = (struct ocfs2_extent_block *)left_leaf_eb; left_el = path_leaf_el(left_path); if (left_el->l_next_free_rec != left_el->l_count) return OCFS2_ET_CORRUPT_EXTENT_BLOCK; /* * This extent block may already have an empty record, so we * return early if so. */ if (ocfs2_is_empty_extent(&left_el->l_recs[0])) return 0; assert(left_path->p_node[subtree_index].blkno == right_path->p_node[subtree_index].blkno); right_leaf_eb = path_leaf_buf(right_path); right_el = path_leaf_el(right_path); ocfs2_create_empty_extent(right_el); /* Do the copy now. */ i = left_el->l_next_free_rec - 1; move_rec = left_el->l_recs[i]; right_el->l_recs[0] = move_rec; /* * Clear out the record we just copied and shift everything * over, leaving an empty extent in the left leaf. * * We temporarily subtract from next_free_rec so that the * shift will lose the tail record (which is now defunct). */ left_el->l_next_free_rec -= 1; ocfs2_shift_records_right(left_el); memset(&left_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); left_el->l_next_free_rec += 1; ocfs2_complete_edge_insert(fs, left_path, right_path, subtree_index); ret = ocfs2_sync_path_to_disk(fs, left_path, right_path, subtree_index); return ret; } /* * Given a full path, determine what cpos value would return us a path * containing the leaf immediately to the left of the current one. * * Will return zero if the path passed in is already the leftmost path. */ static int ocfs2_find_cpos_for_left_leaf(struct ocfs2_path *path, uint32_t *cpos) { int i, j, ret = 0; uint64_t blkno; struct ocfs2_extent_list *el; assert(path->p_tree_depth > 0); *cpos = 0; blkno = path_leaf_blkno(path); /* Start at the tree node just above the leaf and work our way up. */ i = path->p_tree_depth - 1; while (i >= 0) { el = path->p_node[i].el; /* Find the extent record just before the one in our path. */ for(j = 0; j < el->l_next_free_rec; j++) { if (el->l_recs[j].e_blkno == blkno) { if (j == 0) { if (i == 0) { /* * We've determined that the * path specified is already * the leftmost one - return a * cpos of zero. */ goto out; } /* * The leftmost record points to our * leaf - we need to travel up the * tree one level. */ goto next_node; } *cpos = el->l_recs[j - 1].e_cpos; *cpos = *cpos + ocfs2_rec_clusters( el->l_tree_depth, &el->l_recs[j - 1]); *cpos = *cpos - 1; goto out; } } /* * If we got here, we never found a valid node where * the tree indicated one should be. */ ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; next_node: blkno = path->p_node[i].blkno; i--; } out: return ret; } /* * Trap the case where we're inserting into the theoretical range past * the _actual_ left leaf range. Otherwise, we'll rotate a record * whose cpos is less than ours into the right leaf. * * It's only necessary to look at the rightmost record of the left * leaf because the logic that calls us should ensure that the * theoretical ranges in the path components above the leaves are * correct. */ static int ocfs2_rotate_requires_path_adjustment(struct ocfs2_path *left_path, uint32_t insert_cpos) { struct ocfs2_extent_list *left_el; struct ocfs2_extent_rec *rec; int next_free; left_el = path_leaf_el(left_path); next_free = left_el->l_next_free_rec; rec = &left_el->l_recs[next_free - 1]; if (insert_cpos > rec->e_cpos) return 1; return 0; } static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, uint32_t cpos) { int next_free = el->l_next_free_rec; unsigned int range; struct ocfs2_extent_rec *rec; if (next_free == 0) return 0; rec = &el->l_recs[0]; if (ocfs2_is_empty_extent(rec)) { /* Empty list. */ if (next_free == 1) return 0; rec = &el->l_recs[1]; } range = rec->e_cpos + ocfs2_rec_clusters(el->l_tree_depth, rec); if (cpos >= rec->e_cpos && cpos < range) return 1; return 0; } /* * Rotate all the records in a btree right one record, starting at insert_cpos. * * The path to the rightmost leaf should be passed in. * * The array is assumed to be large enough to hold an entire path (tree depth). * * Upon succesful return from this function: * * - The 'right_path' array will contain a path to the leaf block * whose range contains e_cpos. * - That leaf block will have a single empty extent in list index 0. * - In the case that the rotation requires a post-insert update, * *ret_left_path will contain a valid path which can be passed to * ocfs2_insert_path(). */ static int ocfs2_rotate_tree_right(ocfs2_filesys *fs, enum ocfs2_split_type split, uint32_t insert_cpos, struct ocfs2_path *right_path, struct ocfs2_path **ret_left_path) { int ret, start; uint32_t cpos; struct ocfs2_path *left_path = NULL; *ret_left_path = NULL; left_path = ocfs2_new_path_from_path(right_path); if (!left_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_cpos_for_left_leaf(right_path, &cpos); if (ret) goto out; /* * What we want to do here is: * * 1) Start with the rightmost path. * * 2) Determine a path to the leaf block directly to the left * of that leaf. * * 3) Determine the 'subtree root' - the lowest level tree node * which contains a path to both leaves. * * 4) Rotate the subtree. * * 5) Find the next subtree by considering the left path to be * the new right path. * * The check at the top of this while loop also accepts * insert_cpos == cpos because cpos is only a _theoretical_ * value to get us the left path - insert_cpos might very well * be filling that hole. * * Stop at a cpos of '0' because we either started at the * leftmost branch (i.e., a tree with one branch and a * rotation inside of it), or we've gone as far as we can in * rotating subtrees. */ while (cpos && insert_cpos <= cpos) { ret = ocfs2_find_path(fs, left_path, cpos); if (ret) goto out; if (path_leaf_blkno(left_path) == path_leaf_blkno(right_path)) assert(0); if (split == SPLIT_NONE && ocfs2_rotate_requires_path_adjustment(left_path, insert_cpos)) { /* * We've rotated the tree as much as we * should. The rest is up to * ocfs2_insert_path() to complete, after the * record insertion. We indicate this * situation by returning the left path. * * The reason we don't adjust the records here * before the record insert is that an error * later might break the rule where a parent * record e_cpos will reflect the actual * e_cpos of the 1st nonempty record of the * child list. */ *ret_left_path = left_path; goto out_ret_path; } start = ocfs2_find_subtree_root(left_path, right_path); ret = ocfs2_rotate_subtree_right(fs, left_path, right_path, start); if (ret) goto out; if (split != SPLIT_NONE && ocfs2_leftmost_rec_contains(path_leaf_el(right_path), insert_cpos)) { /* * A rotate moves the rightmost left leaf * record over to the leftmost right leaf * slot. If we're doing an extent split * instead of a real insert, then we have to * check that the extent to be split wasn't * just moved over. If it was, then we can * exit here, passing left_path back - * ocfs2_split_extent() is smart enough to * search both leaves. */ *ret_left_path = left_path; goto out_ret_path; } /* * There is no need to re-read the next right path * as we know that it'll be our current left * path. Optimize by copying values instead. */ ocfs2_mv_path(right_path, left_path); ret = ocfs2_find_cpos_for_left_leaf(right_path, &cpos); if (ret) goto out; } out: ocfs2_free_path(left_path); out_ret_path: return ret; } static void ocfs2_update_edge_lengths(struct ocfs2_path *path) { int i, idx; struct ocfs2_extent_rec *rec; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; uint32_t range; /* Path should always be rightmost. */ eb = (struct ocfs2_extent_block *)path_leaf_buf(path); assert(eb->h_next_leaf_blk == 0ULL); el = &eb->h_list; assert(el->l_next_free_rec > 0); idx = el->l_next_free_rec - 1; rec = &el->l_recs[idx]; range = rec->e_cpos + ocfs2_rec_clusters(el->l_tree_depth, rec); for (i = 0; i < path->p_tree_depth; i++) { el = path->p_node[i].el; idx = el->l_next_free_rec - 1; rec = &el->l_recs[idx]; rec->e_int_clusters = range; rec->e_int_clusters -= rec->e_cpos; } } static errcode_t ocfs2_unlink_path(ocfs2_filesys *fs, struct ocfs2_path *path, int unlink_start) { int ret, i; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; char *buf; for(i = unlink_start; i < path_num_items(path); i++) { buf = path->p_node[i].buf; eb = (struct ocfs2_extent_block *)buf; /* * Not all nodes might have had their final count * decremented by the caller - handle this here. */ el = &eb->h_list; assert(el->l_next_free_rec <= 1); el->l_next_free_rec = 0; memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); ret = ocfs2_delete_extent_block(fs, path->p_node[i].blkno); if (ret) return ret; } return 0; } /* * ocfs2_unlink_subtree will delete extent blocks in the "right_path" * from "subtree_index". */ static errcode_t ocfs2_unlink_subtree(ocfs2_filesys *fs, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index) { errcode_t ret; int i; struct ocfs2_extent_list *root_el = left_path->p_node[subtree_index].el; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; el = path_leaf_el(left_path); eb = (struct ocfs2_extent_block *)right_path->p_node[subtree_index + 1].buf; for(i = 1; i < root_el->l_next_free_rec; i++) if (root_el->l_recs[i].e_blkno == eb->h_blkno) break; assert(i < root_el->l_next_free_rec); memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec)); root_el->l_next_free_rec -= 1; eb = (struct ocfs2_extent_block *)path_leaf_buf(left_path); eb->h_next_leaf_blk = 0; ret = ocfs2_unlink_path(fs, right_path, subtree_index + 1); if (ret) return ret; return 0; } static int ocfs2_rotate_subtree_left(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index, int *deleted) { errcode_t ret; int i, del_right_subtree = 0, right_has_empty = 0; char *root_buf; struct ocfs2_extent_list *right_leaf_el, *left_leaf_el; struct ocfs2_extent_block *eb; *deleted = 0; right_leaf_el = path_leaf_el(right_path); left_leaf_el = path_leaf_el(left_path); root_buf = left_path->p_node[subtree_index].buf; assert(left_path->p_node[subtree_index].blkno == right_path->p_node[subtree_index].blkno); if (!ocfs2_is_empty_extent(&left_leaf_el->l_recs[0])) return 0; eb = (struct ocfs2_extent_block *)path_leaf_buf(right_path); if (ocfs2_is_empty_extent(&right_leaf_el->l_recs[0])) { /* * It's legal for us to proceed if the right leaf is * the rightmost one and it has an empty extent. There * are two cases to handle - whether the leaf will be * empty after removal or not. If the leaf isn't empty * then just remove the empty extent up front. The * next block will handle empty leaves by flagging * them for unlink. * * Non rightmost leaves will throw EAGAIN and the * caller can manually move the subtree and retry. */ if (eb->h_next_leaf_blk != 0ULL) return EAGAIN; if (right_leaf_el->l_next_free_rec > 1) { ocfs2_remove_empty_extent(right_leaf_el); } else right_has_empty = 1; } if (eb->h_next_leaf_blk == 0ULL && right_leaf_el->l_next_free_rec == 1) { /* * We have to update i_last_eb_blk during the meta * data delete. */ del_right_subtree = 1; } /* * Getting here with an empty extent in the right path implies * that it's the rightmost path and will be deleted. */ assert(!right_has_empty || del_right_subtree); if (!right_has_empty) { /* * Only do this if we're moving a real * record. Otherwise, the action is delayed until * after removal of the right path in which case we * can do a simple shift to remove the empty extent. */ ocfs2_rotate_leaf(left_leaf_el, &right_leaf_el->l_recs[0]); memset(&right_leaf_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); } if (eb->h_next_leaf_blk == 0ULL) { /* * Move recs over to get rid of empty extent, decrease * next_free. This is allowed to remove the last * extent in our leaf (setting l_next_free_rec to * zero) - the delete code below won't care. */ ocfs2_remove_empty_extent(right_leaf_el); } if (del_right_subtree) { ocfs2_unlink_subtree(fs, left_path, right_path, subtree_index); ocfs2_update_edge_lengths(left_path); /* * Now the good extent block information is stored in left_path, so * synchronize the right path with it. */ for (i = 0; i <= subtree_index; i++) memcpy(right_path->p_node[i].buf, left_path->p_node[i].buf, fs->fs_blocksize); eb = (struct ocfs2_extent_block *)path_leaf_buf(left_path); ocfs2_et_set_last_eb_blk(et, eb->h_blkno); /* * Removal of the extent in the left leaf was skipped * above so we could delete the right path * 1st. */ if (right_has_empty) ocfs2_remove_empty_extent(left_leaf_el); *deleted = 1; /* * The extent block in the right path belwo subtree_index * have been deleted, so we don't need to synchronize * them to the disk. */ ret = ocfs2_sync_path_to_disk(fs, left_path, NULL, subtree_index); } else { ocfs2_complete_edge_insert(fs, left_path, right_path, subtree_index); ret = ocfs2_sync_path_to_disk(fs, left_path, right_path, subtree_index); } return ret; } /* * Given a full path, determine what cpos value would return us a path * containing the leaf immediately to the right of the current one. * * Will return zero if the path passed in is already the rightmost path. * * This looks similar, but is subtly different to * ocfs2_find_cpos_for_left_leaf(). */ static int ocfs2_find_cpos_for_right_leaf(ocfs2_filesys *fs, struct ocfs2_path *path, uint32_t *cpos) { int i, j, ret = 0; uint64_t blkno; struct ocfs2_extent_list *el; *cpos = 0; if (path->p_tree_depth == 0) return 0; blkno = path_leaf_blkno(path); /* Start at the tree node just above the leaf and work our way up. */ i = path->p_tree_depth - 1; while (i >= 0) { int next_free; el = path->p_node[i].el; /* * Find the extent record just after the one in our * path. */ next_free = el->l_next_free_rec; for(j = 0; j < el->l_next_free_rec; j++) { if (el->l_recs[j].e_blkno == blkno) { if (j == (next_free - 1)) { if (i == 0) { /* * We've determined that the * path specified is already * the rightmost one - return a * cpos of zero. */ goto out; } /* * The rightmost record points to our * leaf - we need to travel up the * tree one level. */ goto next_node; } *cpos = el->l_recs[j + 1].e_cpos; goto out; } } /* * If we got here, we never found a valid node where * the tree indicated one should be. */ ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; next_node: blkno = path->p_node[i].blkno; i--; } out: return ret; } static void ocfs2_rotate_rightmost_leaf_left(ocfs2_filesys *fs, struct ocfs2_extent_list *el) { if (!ocfs2_is_empty_extent(&el->l_recs[0])) return; ocfs2_remove_empty_extent(el); return; } static int __ocfs2_rotate_tree_left(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *path, struct ocfs2_path **empty_extent_path) { int i, ret, subtree_root, deleted; uint32_t right_cpos; struct ocfs2_path *left_path = NULL; struct ocfs2_path *right_path = NULL; assert(ocfs2_is_empty_extent(&(path_leaf_el(path)->l_recs[0]))); *empty_extent_path = NULL; ret = ocfs2_find_cpos_for_right_leaf(fs, path, &right_cpos); if (ret) goto out; left_path = ocfs2_new_path_from_path(path); if (!left_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ocfs2_cp_path(fs, left_path, path); right_path = ocfs2_new_path_from_path(path); if (!right_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } while (right_cpos) { ret = ocfs2_find_path(fs, right_path, right_cpos); if (ret) goto out; subtree_root = ocfs2_find_subtree_root(left_path, right_path); ret = ocfs2_rotate_subtree_left(fs, et, left_path, right_path, subtree_root, &deleted); if (ret == EAGAIN) { /* * The rotation has to temporarily stop due to * the right subtree having an empty * extent. Pass it back to the caller for a * fixup. */ *empty_extent_path = right_path; right_path = NULL; goto out; } if (ret) goto out; /* * The subtree rotate might have removed records on * the rightmost edge. If so, then rotation is * complete. */ if (deleted) break; ocfs2_mv_path(left_path, right_path); ret = ocfs2_find_cpos_for_right_leaf(fs, left_path, &right_cpos); if (ret) goto out; } out: ocfs2_free_path(right_path); ocfs2_free_path(left_path); /* * the path's information is changed during the process of rotation, * so re-read them. */ for (i = 1; i <= path->p_tree_depth; i++) { ret = ocfs2_read_extent_block(fs, path->p_node[i].blkno, path->p_node[i].buf); if (ret) break; } return ret; } static int ocfs2_remove_rightmost_path(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *path) { int ret, subtree_index, i; uint32_t cpos; struct ocfs2_path *left_path = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; ret = ocfs2_find_cpos_for_left_leaf(path, &cpos); if (ret) goto out; if (cpos) { /* * We have a path to the left of this one - it needs * an update too. */ left_path = ocfs2_new_path_from_path(path); if (!left_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, left_path, cpos); if (ret) goto out; subtree_index = ocfs2_find_subtree_root(left_path, path); ocfs2_unlink_subtree(fs, left_path, path, subtree_index); ocfs2_update_edge_lengths(left_path); /* * Now the good extent block information is stored in left_path, so * synchronize the right path with it. */ for (i = 0; i <= subtree_index; i++) memcpy(path->p_node[i].buf, left_path->p_node[i].buf, fs->fs_blocksize); ret = ocfs2_sync_path_to_disk(fs, left_path, NULL, subtree_index); if (ret) goto out; eb = (struct ocfs2_extent_block *)path_leaf_buf(left_path); ocfs2_et_set_last_eb_blk(et, eb->h_blkno); } else { /* * 'path' is also the leftmost path which * means it must be the only one. This gets * handled differently because we want to * revert the inode back to having extents * in-line. */ ocfs2_unlink_path(fs, path, 1); el = et->et_root_el; el->l_tree_depth = 0; el->l_next_free_rec = 0; memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); ocfs2_et_set_last_eb_blk(et, 0); } out: ocfs2_free_path(left_path); return ret; } /* * Left rotation of btree records. * * In many ways, this is (unsurprisingly) the opposite of right * rotation. We start at some non-rightmost path containing an empty * extent in the leaf block. The code works its way to the rightmost * path by rotating records to the left in every subtree. * * This is used by any code which reduces the number of extent records * in a leaf. After removal, an empty record should be placed in the * leftmost list position. * * This won't handle a length update of the rightmost path records if * the rightmost tree leaf record is removed so the caller is * responsible for detecting and correcting that. */ static int ocfs2_rotate_tree_left(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *path) { int ret = 0; struct ocfs2_path *tmp_path = NULL, *restart_path = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; el = path_leaf_el(path); if (!ocfs2_is_empty_extent(&el->l_recs[0])) return 0; if (path->p_tree_depth == 0) { rightmost_no_delete: /* * In-inode extents. This is trivially handled, so do * it up front. */ ocfs2_rotate_rightmost_leaf_left(fs, path_leaf_el(path)); /* we have to synchronize the modified extent block to disk. */ if (path->p_tree_depth > 0) { ret = ocfs2_write_extent_block(fs, path_leaf_blkno(path), path_leaf_buf(path)); } goto out; } /* * Handle rightmost branch now. There's several cases: * 1) simple rotation leaving records in there. That's trivial. * 2) rotation requiring a branch delete - there's no more * records left. Two cases of this: * a) There are branches to the left. * b) This is also the leftmost (the only) branch. * * 1) is handled via ocfs2_rotate_rightmost_leaf_left() * 2a) we need the left branch so that we can update it with the unlink * 2b) we need to bring the inode back to inline extents. */ eb = (struct ocfs2_extent_block *)path_leaf_buf(path); el = &eb->h_list; if (eb->h_next_leaf_blk == 0) { /* * This gets a bit tricky if we're going to delete the * rightmost path. Get the other cases out of the way * 1st. */ if (el->l_next_free_rec > 1) goto rightmost_no_delete; if (el->l_next_free_rec == 0) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } /* * XXX: The caller can not trust "path" any more after * this as it will have been deleted. What do we do? * * In theory the rotate-for-merge code will never get * here because it'll always ask for a rotate in a * nonempty list. */ ret = ocfs2_remove_rightmost_path(fs, et, path); goto out; } /* * Now we can loop, remembering the path we get from EAGAIN * and restarting from there. */ try_rotate: ret = __ocfs2_rotate_tree_left(fs, et, path, &restart_path); if (ret && ret != EAGAIN) { goto out; } while (ret == EAGAIN) { tmp_path = restart_path; restart_path = NULL; ret = __ocfs2_rotate_tree_left(fs, et, tmp_path, &restart_path); if (ret && ret != EAGAIN) { goto out; } ocfs2_free_path(tmp_path); tmp_path = NULL; if (ret == 0) goto try_rotate; } out: ocfs2_free_path(tmp_path); ocfs2_free_path(restart_path); return ret; } static void ocfs2_cleanup_merge(struct ocfs2_extent_list *el, int index) { struct ocfs2_extent_rec *rec = &el->l_recs[index]; unsigned int size; if (rec->e_leaf_clusters == 0) { /* * We consumed all of the merged-from record. An empty * extent cannot exist anywhere but the 1st array * position, so move things over if the merged-from * record doesn't occupy that position. * * This creates a new empty extent so the caller * should be smart enough to have removed any existing * ones. */ if (index > 0) { assert(!ocfs2_is_empty_extent(&el->l_recs[0])); size = index * sizeof(struct ocfs2_extent_rec); memmove(&el->l_recs[1], &el->l_recs[0], size); } /* * Always memset - the caller doesn't check whether it * created an empty extent, so there could be junk in * the other fields. */ memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); } } /* * Remove split_rec clusters from the record at index and merge them * onto the beginning of the record at index + 1. */ static int ocfs2_merge_rec_right(ocfs2_filesys *fs, struct ocfs2_extent_rec *split_rec, struct ocfs2_extent_list *el, int index) { unsigned int split_clusters = split_rec->e_leaf_clusters; struct ocfs2_extent_rec *left_rec; struct ocfs2_extent_rec *right_rec; assert(index < el->l_next_free_rec); left_rec = &el->l_recs[index]; right_rec = &el->l_recs[index + 1]; left_rec->e_leaf_clusters -= split_clusters; right_rec->e_cpos -= split_clusters; right_rec->e_blkno -= ocfs2_clusters_to_blocks(fs, split_clusters); right_rec->e_leaf_clusters += split_clusters; ocfs2_cleanup_merge(el, index); return 0; } /* * Remove split_rec clusters from the record at index and merge them * onto the tail of the record at index - 1. */ static int ocfs2_merge_rec_left(ocfs2_filesys *fs, struct ocfs2_extent_rec *split_rec, struct ocfs2_extent_list *el, int index) { int has_empty_extent = 0; unsigned int split_clusters = split_rec->e_leaf_clusters; struct ocfs2_extent_rec *left_rec; struct ocfs2_extent_rec *right_rec; assert(index > 0); left_rec = &el->l_recs[index - 1]; right_rec = &el->l_recs[index]; if (ocfs2_is_empty_extent(&el->l_recs[0])) has_empty_extent = 1; if (has_empty_extent && index == 1) { /* * The easy case - we can just plop the record right in. */ *left_rec = *split_rec; has_empty_extent = 0; } else { left_rec->e_leaf_clusters += split_clusters; } right_rec->e_cpos += split_clusters; right_rec->e_blkno += ocfs2_clusters_to_blocks(fs, split_clusters); right_rec->e_leaf_clusters -= split_clusters; ocfs2_cleanup_merge(el, index); return 0; } static int ocfs2_try_to_merge_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *left_path, int split_index, struct ocfs2_extent_rec *split_rec, struct ocfs2_merge_ctxt *ctxt) { int ret = 0; struct ocfs2_extent_list *el = path_leaf_el(left_path); struct ocfs2_extent_rec *rec = &el->l_recs[split_index]; assert(ctxt->c_contig_type != CONTIG_NONE); if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) { /* * The merge code will need to create an empty * extent to take the place of the newly * emptied slot. Remove any pre-existing empty * extents - having more than one in a leaf is * illegal. */ ret = ocfs2_rotate_tree_left(fs, et, left_path); if (ret) goto out; split_index--; rec = &el->l_recs[split_index]; } if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) { /* * Left-right contig implies this. */ assert(ctxt->c_split_covers_rec); assert(split_index != 0); /* * Since the leftright insert always covers the entire * extent, this call will delete the insert record * entirely, resulting in an empty extent record added to * the extent block. * * Since the adding of an empty extent shifts * everything back to the right, there's no need to * update split_index here. */ ret = ocfs2_merge_rec_left(fs, split_rec, el, split_index); if (ret) goto out; /* * We can only get this from logic error above. */ assert(ocfs2_is_empty_extent(&el->l_recs[0])); /* * The left merge left us with an empty extent, remove * it. */ ret = ocfs2_rotate_tree_left(fs, et, left_path); if (ret) goto out; split_index--; rec = &el->l_recs[split_index]; /* * Note that we don't pass split_rec here on purpose - * we've merged it into the left side. */ ret = ocfs2_merge_rec_right(fs, rec, el, split_index); if (ret) goto out; assert(ocfs2_is_empty_extent(&el->l_recs[0])); ret = ocfs2_rotate_tree_left(fs, et, left_path); /* * Error from this last rotate is not critical, so * don't bubble it up. */ ret = 0; } else { /* * Merge a record to the left or right. * * 'contig_type' is relative to the existing record, * so for example, if we're "right contig", it's to * the record on the left (hence the left merge). */ if (ctxt->c_contig_type == CONTIG_RIGHT) { ret = ocfs2_merge_rec_left(fs, split_rec, el, split_index); if (ret) goto out; } else { ret = ocfs2_merge_rec_right(fs, split_rec, el, split_index); if (ret) goto out; } /* we have to synchronize the modified extent block to disk. */ if (left_path->p_tree_depth > 0) { ret = ocfs2_write_extent_block(fs, path_leaf_blkno(left_path), path_leaf_buf(left_path)); if (ret) goto out; } if (ctxt->c_split_covers_rec) { /* * The merge may have left an empty extent in * our leaf. Try to rotate it away. */ ret = ocfs2_rotate_tree_left(fs, et, left_path); ret = 0; } } out: return ret; } static void ocfs2_subtract_from_rec(ocfs2_filesys *fs, enum ocfs2_split_type split, struct ocfs2_extent_rec *rec, struct ocfs2_extent_rec *split_rec) { uint64_t len_blocks; len_blocks = ocfs2_clusters_to_blocks(fs, split_rec->e_leaf_clusters); if (split == SPLIT_LEFT) { /* * Region is on the left edge of the existing * record. */ rec->e_cpos += split_rec->e_leaf_clusters; rec->e_blkno += len_blocks; rec->e_leaf_clusters -= split_rec->e_leaf_clusters; } else { /* * Region is on the right edge of the existing * record. */ rec->e_leaf_clusters -= split_rec->e_leaf_clusters; } } /* * Change the depth of the tree. That means allocating an extent block, * copying all extent records from the dinode into the extent block, * and then pointing the dinode to the new extent_block. */ static errcode_t shift_tree_depth(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, char **new_eb) { errcode_t ret; char *buf = NULL; uint64_t blkno; struct ocfs2_extent_list *el = et->et_root_el; struct ocfs2_extent_block *eb; uint32_t new_clusters; if (el->l_next_free_rec != el->l_count) return OCFS2_ET_INTERNAL_FAILURE; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_new_extent_block(fs, &blkno); if (ret) goto out; ret = ocfs2_read_extent_block(fs, blkno, buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)buf; eb->h_list.l_tree_depth = el->l_tree_depth; eb->h_list.l_next_free_rec = el->l_next_free_rec; memcpy(eb->h_list.l_recs, el->l_recs, sizeof(struct ocfs2_extent_rec) * el->l_count); new_clusters = ocfs2_sum_rightmost_rec(&eb->h_list); el->l_tree_depth++; memset(el->l_recs, 0, sizeof(struct ocfs2_extent_rec) * el->l_count); el->l_recs[0].e_cpos = 0; el->l_recs[0].e_blkno = blkno; el->l_recs[0].e_int_clusters = new_clusters; el->l_next_free_rec = 1; if (el->l_tree_depth == 1) ocfs2_et_set_last_eb_blk(et, blkno); ret = ocfs2_write_extent_block(fs, blkno, buf); if (!ret) *new_eb = buf; out: if (buf && !*new_eb) ocfs2_free(&buf); return ret; } static enum ocfs2_contig_type ocfs2_figure_merge_contig_type(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_extent_list *el, int index, struct ocfs2_extent_rec *split_rec) { struct ocfs2_extent_rec *rec; enum ocfs2_contig_type ret = CONTIG_NONE; /* * We're careful to check for an empty extent record here - * the merge code will know what to do if it sees one. */ if (index > 0) { rec = &el->l_recs[index - 1]; if (index == 1 && ocfs2_is_empty_extent(rec)) { if (split_rec->e_cpos == el->l_recs[index].e_cpos) ret = CONTIG_RIGHT; } else { ret = ocfs2_et_extent_contig(fs, et, rec, split_rec); } } if (index < el->l_next_free_rec - 1) { enum ocfs2_contig_type contig_type; rec = &el->l_recs[index + 1]; contig_type = ocfs2_et_extent_contig(fs, et, rec, split_rec); if (contig_type == CONTIG_LEFT && ret == CONTIG_RIGHT) ret = CONTIG_LEFTRIGHT; else if (ret == CONTIG_NONE) ret = contig_type; } return ret; } static void ocfs2_figure_contig_type(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_insert_type *insert, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *insert_rec) { int i; enum ocfs2_contig_type contig_type = CONTIG_NONE; assert(el->l_tree_depth == 0); for(i = 0; i < el->l_next_free_rec; i++) { contig_type = ocfs2_et_extent_contig(fs, et, &el->l_recs[i], insert_rec); if (contig_type != CONTIG_NONE) { insert->ins_contig_index = i; break; } } insert->ins_contig = contig_type; } /* * This should only be called against the righmost leaf extent list. * * ocfs2_figure_appending_type() will figure out whether we'll have to * insert at the tail of the rightmost leaf. * * This should also work against the dinode list for tree's with 0 * depth. If we consider the dinode list to be the rightmost leaf node * then the logic here makes sense. */ static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *insert_rec) { int i; uint32_t cpos = insert_rec->e_cpos; struct ocfs2_extent_rec *rec; insert->ins_appending = APPEND_NONE; assert(el->l_tree_depth == 0); if (!el->l_next_free_rec) goto set_tail_append; if (ocfs2_is_empty_extent(&el->l_recs[0])) { /* Were all records empty? */ if (el->l_next_free_rec == 1) goto set_tail_append; } i = el->l_next_free_rec - 1; rec = &el->l_recs[i]; if (cpos >= (rec->e_cpos + rec->e_leaf_clusters)) goto set_tail_append; return; set_tail_append: insert->ins_appending = APPEND_TAIL; } /* * Helper function called at the begining of an insert. * * This computes a few things that are commonly used in the process of * inserting into the btree: * - Whether the new extent is contiguous with an existing one. * - The current tree depth. * - Whether the insert is an appending one. * - The total # of free records in the tree. * * All of the information is stored on the ocfs2_insert_type * structure. */ static int ocfs2_figure_insert_type(struct insert_ctxt *ctxt, char **last_eb_buf, int *free_records, struct ocfs2_insert_type *insert) { int ret; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *insert_rec = &ctxt->rec; ocfs2_filesys *fs = ctxt->fs; struct ocfs2_extent_tree *et = ctxt->et; struct ocfs2_path *path = NULL; char *buf = *last_eb_buf; uint64_t last_eb_blk = ocfs2_et_get_last_eb_blk(et); insert->ins_split = SPLIT_NONE; el = et->et_root_el; insert->ins_tree_depth = el->l_tree_depth; if (el->l_tree_depth) { /* * If we have tree depth, we read in the * rightmost extent block ahead of time as * ocfs2_figure_insert_type() and ocfs2_add_branch() * may want it later. */ assert(buf); ret = ocfs2_read_extent_block(fs, last_eb_blk, buf); if (ret) goto out; eb = (struct ocfs2_extent_block *) buf; el = &eb->h_list; } /* * Unless we have a contiguous insert, we'll need to know if * there is room left in our allocation tree for another * extent record. * * XXX: This test is simplistic, we can search for empty * extent records too. */ *free_records = el->l_count - el->l_next_free_rec; if (!insert->ins_tree_depth) { ocfs2_figure_contig_type(fs, et, insert, el, insert_rec); ocfs2_figure_appending_type(insert, el, insert_rec); return 0; } path = ocfs2_new_path_from_et(et); if (!path) { ret = OCFS2_ET_NO_MEMORY; goto out; } /* * In the case that we're inserting past what the tree * currently accounts for, ocf2_find_path() will return for * us the rightmost tree path. This is accounted for below in * the appending code. */ ret = ocfs2_find_path(fs, path, insert_rec->e_cpos); if (ret) goto out; el = path_leaf_el(path); /* * Now that we have the path, there's two things we want to determine: * 1) Contiguousness (also set contig_index if this is so) * * 2) Are we doing an append? We can trivially break this up * into two types of appends: simple record append, or a * rotate inside the tail leaf. */ ocfs2_figure_contig_type(fs, et, insert, el, insert_rec); /* * The insert code isn't quite ready to deal with all cases of * left contiguousness. Specifically, if it's an insert into * the 1st record in a leaf, it will require the adjustment of * e_clusters on the last record of the path directly to it's * left. For now, just catch that case and fool the layers * above us. This works just fine for tree_depth == 0, which * is why we allow that above. */ if (insert->ins_contig == CONTIG_LEFT && insert->ins_contig_index == 0) insert->ins_contig = CONTIG_NONE; /* * Ok, so we can simply compare against last_eb to figure out * whether the path doesn't exist. This will only happen in * the case that we're doing a tail append, so maybe we can * take advantage of that information somehow. */ if (last_eb_blk == path_leaf_blkno(path)) { /* * Ok, ocfs2_find_path() returned us the rightmost * tree path. This might be an appending insert. There are * two cases: * 1) We're doing a true append at the tail: * -This might even be off the end of the leaf * 2) We're "appending" by rotating in the tail */ ocfs2_figure_appending_type(insert, el, insert_rec); } out: ocfs2_free_path(path); return ret; } /* * Do the final bits of extent record insertion at the target leaf * list. If this leaf is part of an allocation tree, it is assumed * that the tree above has been prepared. */ static void ocfs2_insert_at_leaf(ocfs2_filesys *fs, struct ocfs2_extent_rec *insert_rec, struct ocfs2_extent_list *el, struct ocfs2_insert_type *insert) { int i = insert->ins_contig_index; unsigned int range; struct ocfs2_extent_rec *rec; assert(el->l_tree_depth == 0); if (insert->ins_split != SPLIT_NONE) { i = ocfs2_search_extent_list(el, insert_rec->e_cpos); assert(i != -1); rec = &el->l_recs[i]; ocfs2_subtract_from_rec(fs, insert->ins_split, rec, insert_rec); goto rotate; } /* * Contiguous insert - either left or right. */ if (insert->ins_contig != CONTIG_NONE) { rec = &el->l_recs[i]; if (insert->ins_contig == CONTIG_LEFT) { rec->e_blkno = insert_rec->e_blkno; rec->e_cpos = insert_rec->e_cpos; } rec->e_leaf_clusters += insert_rec->e_leaf_clusters; return; } /* * Handle insert into an empty leaf. */ if (el->l_next_free_rec == 0 || (el->l_next_free_rec == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) { el->l_recs[0] = *insert_rec; el->l_next_free_rec = 1; return; } /* * Appending insert. */ if (insert->ins_appending == APPEND_TAIL) { i = el->l_next_free_rec - 1; rec = &el->l_recs[i]; range = rec->e_cpos + rec->e_leaf_clusters; assert(insert_rec->e_cpos >= range); i++; el->l_recs[i] = *insert_rec; el->l_next_free_rec += 1; return; } rotate: /* * Ok, we have to rotate. * * At this point, it is safe to assume that inserting into an * empty leaf and appending to a leaf have both been handled * above. * * This leaf needs to have space, either by the empty 1st * extent record, or by virtue of an l_next_rec < l_count. */ ocfs2_rotate_leaf(el, insert_rec); } static int ocfs2_adjust_rightmost_records(ocfs2_filesys *fs, struct ocfs2_path *path, struct ocfs2_extent_rec *insert_rec) { int i, next_free; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *rec; /* * Update everything except the leaf block. */ for (i = 0; i < path->p_tree_depth; i++) { el = path->p_node[i].el; next_free = el->l_next_free_rec; if (next_free == 0) return OCFS2_ET_CORRUPT_EXTENT_BLOCK; rec = &el->l_recs[next_free - 1]; rec->e_int_clusters = insert_rec->e_cpos; rec->e_int_clusters += insert_rec->e_leaf_clusters; rec->e_int_clusters -= rec->e_cpos; } return 0; } static int ocfs2_append_rec_to_path(ocfs2_filesys *fs, struct ocfs2_extent_rec *insert_rec, struct ocfs2_path *right_path, struct ocfs2_path **ret_left_path) { int ret, next_free, i; struct ocfs2_extent_list *el; struct ocfs2_path *left_path = NULL; *ret_left_path = NULL; /* * This shouldn't happen for non-trees. The extent rec cluster * count manipulation below only works for interior nodes. */ assert(right_path->p_tree_depth > 0); /* * If our appending insert is at the leftmost edge of a leaf, * then we might need to update the rightmost records of the * neighboring path. */ el = path_leaf_el(right_path); next_free = el->l_next_free_rec; if (next_free == 0 || (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) { uint32_t left_cpos; ret = ocfs2_find_cpos_for_left_leaf(right_path, &left_cpos); if (ret) goto out; /* * No need to worry if the append is already in the * leftmost leaf. */ if (left_cpos) { left_path = ocfs2_new_path_from_path(right_path); if (!left_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, left_path, left_cpos); if (ret) goto out; } } ret = ocfs2_adjust_rightmost_records(fs, right_path, insert_rec); if (ret) goto out; if (left_path) { /* * Userspace sepcially. * In case we have changed some blocks that is also in * right_path, we have to update them in the left_path. */ i = 0; while (i++ < left_path->p_tree_depth) if (left_path->p_node[i].blkno == right_path->p_node[i].blkno) memcpy(left_path->p_node[i].buf, right_path->p_node[i].buf, fs->fs_blocksize); } *ret_left_path = left_path; ret = 0; out: if (ret) ocfs2_free_path(left_path); return ret; } static void ocfs2_split_record(ocfs2_filesys *fs, struct ocfs2_path *left_path, struct ocfs2_path *right_path, struct ocfs2_extent_rec *split_rec, enum ocfs2_split_type split) { int index; uint32_t cpos = split_rec->e_cpos; struct ocfs2_extent_list *left_el = NULL, *right_el, *insert_el, *el; struct ocfs2_extent_rec *rec, *tmprec; right_el = path_leaf_el(right_path);; if (left_path) left_el = path_leaf_el(left_path); el = right_el; insert_el = right_el; index = ocfs2_search_extent_list(el, cpos); if (index != -1) { if (index == 0 && left_path) { assert(!ocfs2_is_empty_extent(&el->l_recs[0])); /* * This typically means that the record * started in the left path but moved to the * right as a result of rotation. We either * move the existing record to the left, or we * do the later insert there. * * In this case, the left path should always * exist as the rotate code will have passed * it back for a post-insert update. */ if (split == SPLIT_LEFT) { /* * It's a left split. Since we know * that the rotate code gave us an * empty extent in the left path, we * can just do the insert there. */ insert_el = left_el; } else { /* * Right split - we have to move the * existing record over to the left * leaf. The insert will be into the * newly created empty extent in the * right leaf. */ tmprec = &right_el->l_recs[index]; ocfs2_rotate_leaf(left_el, tmprec); el = left_el; memset(tmprec, 0, sizeof(*tmprec)); index = ocfs2_search_extent_list(left_el, cpos); assert(index != -1); } } } else { assert(left_path); assert(ocfs2_is_empty_extent(&left_el->l_recs[0])); /* * Left path is easy - we can just allow the insert to * happen. */ el = left_el; insert_el = left_el; index = ocfs2_search_extent_list(el, cpos); assert(index != -1); } rec = &el->l_recs[index]; ocfs2_subtract_from_rec(fs, split, rec, split_rec); ocfs2_rotate_leaf(insert_el, split_rec); } /* * This function only does inserts on an allocation b-tree. For dinode * lists, ocfs2_insert_at_leaf() is called directly. * * right_path is the path we want to do the actual insert * in. left_path should only be passed in if we need to update that * portion of the tree after an edge insert. */ static int ocfs2_insert_path(ocfs2_filesys *fs, struct ocfs2_path *left_path, struct ocfs2_path *right_path, struct ocfs2_extent_rec *insert_rec, struct ocfs2_insert_type *insert) { int ret, subtree_index; if (insert->ins_split != SPLIT_NONE) { /* * We could call ocfs2_insert_at_leaf() for some types * of splits, but it's easier to just let one seperate * function sort it all out. */ ocfs2_split_record(fs, left_path, right_path, insert_rec, insert->ins_split); } else ocfs2_insert_at_leaf(fs, insert_rec, path_leaf_el(right_path), insert); if (left_path) { /* * The rotate code has indicated that we need to fix * up portions of the tree after the insert. */ subtree_index = ocfs2_find_subtree_root(left_path, right_path); ocfs2_complete_edge_insert(fs, left_path, right_path, subtree_index); } else subtree_index = 0; ret = ocfs2_sync_path_to_disk(fs, left_path, right_path, subtree_index); if (ret) goto out; ret = 0; out: return ret; } static int ocfs2_do_insert_extent(struct insert_ctxt* ctxt, struct ocfs2_insert_type *type) { int ret, rotate = 0; uint32_t cpos; struct ocfs2_path *right_path = NULL; struct ocfs2_path *left_path = NULL; struct ocfs2_extent_rec *insert_rec = &ctxt->rec; ocfs2_filesys *fs = ctxt->fs; struct ocfs2_extent_list *el = ctxt->et->et_root_el; if (el->l_tree_depth == 0) { ocfs2_insert_at_leaf(fs, insert_rec, el, type); goto out_update_clusters; } right_path = ocfs2_new_path_from_et(ctxt->et); if (!right_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } /* * Determine the path to start with. Rotations need the * rightmost path, everything else can go directly to the * target leaf. */ cpos = insert_rec->e_cpos; if (type->ins_appending == APPEND_NONE && type->ins_contig == CONTIG_NONE) { rotate = 1; cpos = UINT_MAX; } ret = ocfs2_find_path(fs, right_path, cpos); if (ret) goto out; /* * Rotations and appends need special treatment - they modify * parts of the tree's above them. * * Both might pass back a path immediate to the left of the * one being inserted to. This will be cause * ocfs2_insert_path() to modify the rightmost records of * left_path to account for an edge insert. * * XXX: When modifying this code, keep in mind that an insert * can wind up skipping both of these two special cases... */ if (rotate) { ret = ocfs2_rotate_tree_right(fs, type->ins_split, insert_rec->e_cpos, right_path, &left_path); if (ret) goto out; } else if (type->ins_appending == APPEND_TAIL && type->ins_contig != CONTIG_LEFT) { ret = ocfs2_append_rec_to_path(fs, insert_rec, right_path, &left_path); if (ret) goto out; } ret = ocfs2_insert_path(fs, left_path, right_path, insert_rec, type); if (ret) goto out; out_update_clusters: if (type->ins_split == SPLIT_NONE) ocfs2_et_update_clusters(ctxt->et, insert_rec->e_leaf_clusters); ret = 0; out: ocfs2_free_path(left_path); ocfs2_free_path(right_path); return ret; } struct duplicate_ctxt { struct ocfs2_extent_tree *et; uint64_t next_leaf_blk; }; static errcode_t duplicate_extent_block(ocfs2_filesys *fs, struct ocfs2_extent_list *old_el, struct ocfs2_extent_list *new_el, struct duplicate_ctxt *ctxt) { int i; errcode_t ret; uint64_t blkno, new_blkno; struct ocfs2_extent_rec *rec = NULL; char *eb_buf = NULL, *new_eb_buf = NULL; struct ocfs2_extent_block *eb = NULL; struct ocfs2_extent_list *child_old_el = NULL, *child_new_el = NULL; assert (old_el->l_tree_depth > 0); /* empty the whole extent list at first. */ *new_el = *old_el; new_el->l_next_free_rec = 0; memset(new_el->l_recs, 0, sizeof(struct ocfs2_extent_rec) * new_el->l_count); if (old_el->l_next_free_rec == 0) { /* XXX: * We have a tree depth > 0 and no extent record in it, * should it be a corrupted block? */ ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto bail; } ret = ocfs2_malloc_block(fs->fs_io, &eb_buf); if (ret) goto bail; ret = ocfs2_malloc_block(fs->fs_io, &new_eb_buf); if (ret) goto bail; /* we iterate the extent list from the last one for recording * the next_leaf_blk for the previous leaf. */ for (i = old_el->l_next_free_rec - 1; i >= 0; i--) { rec = &old_el->l_recs[i]; if (!ocfs2_rec_clusters(old_el->l_tree_depth, rec)) continue; blkno = rec->e_blkno; ret = ocfs2_read_extent_block(fs, blkno, eb_buf); if (ret) goto bail; /* First make the new_buf the same as the old buf. */ memcpy(new_eb_buf, eb_buf, fs->fs_blocksize); eb = (struct ocfs2_extent_block *)eb_buf; child_old_el = &eb->h_list; eb = (struct ocfs2_extent_block *)new_eb_buf; child_new_el = &eb->h_list; if (child_old_el->l_tree_depth > 0) { /* the extent record in our list still has child extent * block, so we have to iterate it. */ ret = duplicate_extent_block(fs, child_old_el, child_new_el, ctxt); if (ret) goto bail; } /* now we allocate a new extent block and save it. */ ret = ocfs2_new_extent_block(fs, &new_blkno); if (ret) goto bail; eb = (struct ocfs2_extent_block *)new_eb_buf; eb->h_blkno = new_blkno; if (child_old_el->l_tree_depth == 0) { /* * This is the leaf blkno, we have to set its * h_next_leaf_blk and then record itself for * future use. */ eb->h_next_leaf_blk = ctxt->next_leaf_blk; ctxt->next_leaf_blk = new_blkno; } ret = ocfs2_write_extent_block(fs, new_blkno, new_eb_buf); if (ret) goto bail; memcpy(&new_el->l_recs[i], rec, sizeof(struct ocfs2_extent_rec)); new_el->l_recs[i].e_blkno = new_blkno; eb = (struct ocfs2_extent_block *)new_eb_buf; /* set the new i_last_eb_blk in the new dinode. */ if (ocfs2_et_get_last_eb_blk(ctxt->et) == blkno) ocfs2_et_set_last_eb_blk(ctxt->et, new_blkno); } new_el->l_next_free_rec = old_el->l_next_free_rec; ret = 0; bail: if (eb_buf) ocfs2_free(&eb_buf); if (new_eb_buf) ocfs2_free(&new_eb_buf); /* Free all the extent block we allocate. */ if (ret) { for (i = 0; i < old_el->l_next_free_rec; i++) { rec = &new_el->l_recs[i]; if (rec->e_blkno) ocfs2_delete_extent_block(fs, rec->e_blkno); } } return ret; } static errcode_t duplicate_extent_block_et(ocfs2_filesys *fs, struct ocfs2_extent_tree *et) { errcode_t ret = 0; struct ocfs2_extent_list *old_el = NULL, *new_el = NULL; char *old_buf, *new_buf; struct duplicate_ctxt ctxt; ret = ocfs2_malloc_block(fs->fs_io, &old_buf); if (ret) return ret; memcpy(old_buf, et->et_root_buf, fs->fs_blocksize); new_buf = et->et_root_buf; new_el = et->et_root_el; old_el = (struct ocfs2_extent_list *) (old_buf + ((char *)new_el - new_buf)); assert(old_el->l_tree_depth > 0); /* empty the whole extent list at first. */ *new_el = *old_el; memset(new_el->l_recs, 0, sizeof(struct ocfs2_extent_rec) * new_el->l_count); new_el->l_next_free_rec = 0; memset(&ctxt, 0, sizeof(ctxt)); ctxt.et = et; ctxt.next_leaf_blk = 0; ret = duplicate_extent_block(fs, old_el, new_el, &ctxt); ocfs2_free(&old_buf); return ret; } static void free_duplicated_extent_block(ocfs2_filesys *fs, struct ocfs2_extent_list *el) { int i; errcode_t ret; char *buf = NULL; struct ocfs2_extent_rec *rec; struct ocfs2_extent_list *child_el; struct ocfs2_extent_block *eb; assert(el->l_tree_depth > 0); ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return; for (i = 0; i < el->l_next_free_rec; i ++) { rec = &el->l_recs[i]; if (!ocfs2_rec_clusters(el->l_tree_depth, rec)) continue; ret = ocfs2_read_extent_block(fs, rec->e_blkno, buf); if (ret) continue; eb = (struct ocfs2_extent_block *)buf; child_el = &eb->h_list; if (child_el->l_tree_depth > 0) free_duplicated_extent_block(fs, child_el); ocfs2_delete_extent_block(fs, rec->e_blkno); } if(buf) ocfs2_free(&buf); } /* * Grow a b-tree so that it has more records. * * We might shift the tree depth in which case existing paths should * be considered invalid. * * Tree depth after the grow is returned via *final_depth. * * *last_eb will be updated by ocfs2_add_branch(). */ static int ocfs2_grow_tree(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, int *final_depth, char **last_eb) { errcode_t ret; char *eb_buf = NULL; int shift; struct ocfs2_extent_list *el = et->et_root_el; int depth = el->l_tree_depth; shift = ocfs2_find_branch_target(fs, et, &eb_buf); if (shift < 0) { ret = shift; goto out; } /* We traveled all the way to the bottom of the allocation tree * and didn't find room for any more extents - we need to add * another tree level */ if (shift) { /* shift_tree_depth will return us a buffer with * the new extent block (so we can pass that to * ocfs2_add_branch). */ ret = shift_tree_depth(fs, et, &eb_buf); if (ret) goto out; depth++; if (depth == 1) { /* * Special case: we have room now if we shifted from * tree_depth 0, so no more work needs to be done. * * We won't be calling add_branch, so pass * back *last_eb as the new leaf. */ assert(*last_eb); memcpy(*last_eb, eb_buf, fs->fs_blocksize); goto out; } } /* call ocfs2_add_branch to add the final part of the tree with * the new data. */ ret = ocfs2_add_branch(fs, et, eb_buf, last_eb); out: if (final_depth) *final_depth = depth; return ret; } errcode_t ocfs2_tree_insert_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag) { errcode_t ret; struct insert_ctxt ctxt; struct ocfs2_insert_type insert = {0, }; char *last_eb = NULL; char *backup_buf = NULL; char *root_buf = et->et_root_buf; int free_records = 0; ctxt.fs = fs; ctxt.et = et; /* In order to orderize the written block sequence and avoid * the corruption for the b-tree, we duplicate the extent block * here and do the insertion in the duplicated ones. * * Note: we only do this in case the b-tree has extent blocks. * And if the duplicate process fails, we should go on the normal * insert process. */ if (et->et_root_el->l_tree_depth) { ret = ocfs2_malloc_block(fs->fs_io, &backup_buf); if (ret) goto bail; memcpy(backup_buf, root_buf, fs->fs_blocksize); /* duplicate the extent block. If it succeeds, di_buf * will point to the new allocated extent blocks, and * the following insertion will happens to the new ones. */ ret = duplicate_extent_block_et(fs, et); if (ret) { memcpy(root_buf, backup_buf, fs->fs_blocksize); ocfs2_free(&backup_buf); backup_buf = NULL; } } memset(&ctxt.rec, 0, sizeof(struct ocfs2_extent_rec)); ctxt.rec.e_cpos = cpos; ctxt.rec.e_blkno = c_blkno; ctxt.rec.e_leaf_clusters = clusters; ctxt.rec.e_flags = flag; ret = ocfs2_malloc_block(fs->fs_io, &last_eb); if (ret) return ret; ret = ocfs2_figure_insert_type(&ctxt, &last_eb, &free_records, &insert); if (ret) goto bail; if (insert.ins_contig == CONTIG_NONE && free_records == 0) { ret = ocfs2_grow_tree(fs, ctxt.et, &insert.ins_tree_depth, &last_eb); if (ret) goto bail; } /* Finally, we can add clusters. This might rotate the tree for us. */ ret = ocfs2_do_insert_extent(&ctxt, &insert); if (ret) goto bail; bail: if (backup_buf) { struct ocfs2_extent_list *free_el; int offset = (char *)et->et_root_el - et->et_root_buf; /* we have duplicated the extent block during the insertion. * so if it succeeds, we should free the old ones, and if fails, * the duplicate ones should be freed. */ if (ret) free_el = (struct ocfs2_extent_list *) (et->et_root_buf + offset); else free_el = (struct ocfs2_extent_list *) (backup_buf + offset); free_duplicated_extent_block(fs, free_el); ocfs2_free(&backup_buf); } if (last_eb) ocfs2_free(&last_eb); /* * Write the root buffer here. * If the caller don't initialize the write function, it should * be responsible for write the root buffer. */ if (!ret && et->et_root_write) ret = et->et_root_write(fs, et->et_root_blkno, root_buf); return ret; } static void ocfs2_make_right_split_rec(ocfs2_filesys *fs, struct ocfs2_extent_rec *split_rec, uint32_t cpos, struct ocfs2_extent_rec *rec) { uint32_t rec_cpos = rec->e_cpos; uint32_t rec_range = rec_cpos + rec->e_leaf_clusters; memset(split_rec, 0, sizeof(struct ocfs2_extent_rec)); split_rec->e_cpos = cpos; split_rec->e_leaf_clusters = rec_range - cpos; split_rec->e_blkno = rec->e_blkno; split_rec->e_blkno += ocfs2_clusters_to_blocks(fs, cpos - rec_cpos); split_rec->e_flags = rec->e_flags; } static int ocfs2_split_and_insert(struct insert_ctxt *ctxt, struct ocfs2_path *path, char **last_eb_buf, int split_index, struct ocfs2_extent_rec *orig_split_rec) { int ret = 0, depth; unsigned int insert_range, rec_range, do_leftright = 0; struct ocfs2_extent_rec tmprec; struct ocfs2_extent_list *rightmost_el; struct ocfs2_extent_rec rec; struct ocfs2_insert_type insert; struct ocfs2_extent_block *eb; leftright: /* * Store a copy of the record on the stack - it might move * around as the tree is manipulated below. */ rec = path_leaf_el(path)->l_recs[split_index]; rightmost_el = ctxt->et->et_root_el; depth = rightmost_el->l_tree_depth; if (depth) { assert(*last_eb_buf); eb = (struct ocfs2_extent_block *) (*last_eb_buf); rightmost_el = &eb->h_list; } if (rightmost_el->l_next_free_rec == rightmost_el->l_count) { ret = ocfs2_grow_tree(ctxt->fs, ctxt->et, &depth, last_eb_buf); if (ret) goto out; } memset(&insert, 0, sizeof(struct ocfs2_insert_type)); insert.ins_appending = APPEND_NONE; insert.ins_contig = CONTIG_NONE; insert.ins_tree_depth = depth; insert_range = ctxt->rec.e_cpos + ctxt->rec.e_leaf_clusters; rec_range = rec.e_cpos + rec.e_leaf_clusters; if (ctxt->rec.e_cpos == rec.e_cpos) { insert.ins_split = SPLIT_LEFT; } else if (insert_range == rec_range) { insert.ins_split = SPLIT_RIGHT; } else { /* * Left/right split. We fake this as a right split * first and then make a second pass as a left split. */ insert.ins_split = SPLIT_RIGHT; ocfs2_make_right_split_rec(ctxt->fs, &tmprec, insert_range, &rec); ctxt->rec = tmprec; assert(!do_leftright); do_leftright = 1; } ret = ocfs2_do_insert_extent(ctxt, &insert); if (ret) goto out; if (do_leftright == 1) { uint32_t cpos; struct ocfs2_extent_list *el; do_leftright++; ctxt->rec = *orig_split_rec; ocfs2_reinit_path(path, 1); cpos = ctxt->rec.e_cpos; ret = ocfs2_find_path(ctxt->fs, path, cpos); if (ret) goto out; el = path_leaf_el(path); split_index = ocfs2_search_extent_list(el, cpos); goto leftright; } out: return ret; } /* * Split part or all of the extent record at split_index in the leaf * pointed to by path. Merge with the contiguous extent record if needed. * * Care is taken to handle contiguousness so as to not grow the tree. * * last_eb_buf should be the rightmost leaf block for any inode with a * btree. Since a split may grow the tree or a merge might shrink it, * the caller cannot trust the contents of that buffer after this call. * * This code is optimized for readability - several passes might be * made over certain portions of the tree. */ static int ocfs2_split_extent(struct insert_ctxt *insert_ctxt, struct ocfs2_path *path, int split_index) { int ret = 0; struct ocfs2_extent_rec split_rec = insert_ctxt->rec; struct ocfs2_extent_list *el = path_leaf_el(path); char *last_eb_buf = NULL; struct ocfs2_extent_rec *rec = &el->l_recs[split_index]; struct ocfs2_merge_ctxt merge_ctxt; struct ocfs2_extent_list *rightmost_el; ocfs2_filesys *fs = insert_ctxt->fs; if (rec->e_cpos > split_rec.e_cpos || ((rec->e_cpos + rec->e_leaf_clusters) < (split_rec.e_cpos + split_rec.e_leaf_clusters))) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } merge_ctxt.c_contig_type = ocfs2_figure_merge_contig_type(fs, insert_ctxt->et, el, split_index, &split_rec); /* * We have to allocate the last_eb_buf no matter the current tree * depth is since we may shift the tree depth from 0 to 1 in * ocfs2_split_and_insert and use last_eb_buf to store. */ ret = ocfs2_malloc_block(fs->fs_io, &last_eb_buf); if (ret) goto out; /* * The core merge / split code wants to know how much room is * left in this inodes allocation tree, so we pass the * rightmost extent list. */ if (path->p_tree_depth) { struct ocfs2_extent_block *eb; ret = ocfs2_read_extent_block(fs, ocfs2_et_get_last_eb_blk(insert_ctxt->et), last_eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *) last_eb_buf; rightmost_el = &eb->h_list; } else rightmost_el = path_root_el(path); if (rec->e_cpos == split_rec.e_cpos && rec->e_leaf_clusters == split_rec.e_leaf_clusters) merge_ctxt.c_split_covers_rec = 1; else merge_ctxt.c_split_covers_rec = 0; merge_ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]); if (merge_ctxt.c_contig_type == CONTIG_NONE) { if (merge_ctxt.c_split_covers_rec) { el->l_recs[split_index] = split_rec; /* * We only write the leaf block, and leave * the write of the root to the caller. */ if (path->p_tree_depth) ret = ocfs2_write_extent_block(fs, path_leaf_blkno(path), path_leaf_buf(path)); } else ret = ocfs2_split_and_insert(insert_ctxt, path, &last_eb_buf, split_index, &split_rec); } else { ret = ocfs2_try_to_merge_extent(fs, insert_ctxt->et, path, split_index, &split_rec, &merge_ctxt); } out: if (last_eb_buf) ocfs2_free(&last_eb_buf); return ret; } /* * Change the flags of the already-existing extent at cpos for len clusters. * * new_flags: the flags we want to set. * clear_flags: the flags we want to clear. * p_blkno: the new physical offset we want this new extent starts from. * * If the existing extent is larger than the request, initiate a * split. An attempt will be made at merging with adjacent extents. */ int ocfs2_change_extent_flag(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t len, uint64_t p_blkno, int new_flags, int clear_flags) { int ret, index; struct ocfs2_path *left_path = NULL; struct ocfs2_extent_list *el; struct insert_ctxt ctxt; struct ocfs2_extent_rec *rec; char *backup_buf = NULL; /* In order to orderize the written block sequence and avoid * the corruption for the inode, we duplicate the extent block * here and do the insertion in the duplicated ones. * * Note: we only do this in case the file has extent blocks. * And if the duplicate process fails, we should go on the normal * insert process. */ if (et->et_root_el->l_tree_depth) { ret = ocfs2_malloc_block(fs->fs_io, &backup_buf); if (ret) goto out; memcpy(backup_buf, et->et_root_buf, fs->fs_blocksize); /* duplicate the extent block. If it succeeds, di_buf * will point to the new allocated extent blocks, and * the following insertion will happens to the new ones. */ ret = duplicate_extent_block_et(fs, et); if (ret) { memcpy(et->et_root_buf, backup_buf, fs->fs_blocksize); ocfs2_free(&backup_buf); backup_buf = NULL; } } left_path = ocfs2_new_path_from_et(et); if (!left_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, left_path, cpos); if (ret) goto out; el = path_leaf_el(left_path); index = ocfs2_search_extent_list(el, cpos); if (index == -1 || index >= el->l_next_free_rec) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } ctxt.fs = fs; ctxt.et = et; ret = OCFS2_ET_IO; rec = &el->l_recs[index]; if (new_flags && (rec->e_flags & new_flags)) goto out; if (clear_flags && !(rec->e_flags & clear_flags)) goto out; memset(&ctxt.rec, 0, sizeof(struct ocfs2_extent_rec)); ctxt.rec.e_cpos = cpos; ctxt.rec.e_leaf_clusters = len; ctxt.rec.e_blkno = p_blkno; ctxt.rec.e_flags = rec->e_flags; if (new_flags) ctxt.rec.e_flags |= new_flags; if (clear_flags) ctxt.rec.e_flags &= ~clear_flags; ret = ocfs2_split_extent(&ctxt, left_path, index); if (ret) goto out; /* * Write the root buffer here. * If the caller don't initialize the write function, it should * be responsible for write the root buffer. */ if (!ret && et->et_root_write) ret = et->et_root_write(fs, et->et_root_blkno, et->et_root_buf); out: if (backup_buf) { struct ocfs2_extent_list *free_el; int offset = (char *)et->et_root_el - et->et_root_buf; /* we have duplicated the extent block during the insertion. * so if it succeeds, we should free the old ones, and if fails, * the duplicate ones should be freed. */ if (ret) free_el = (struct ocfs2_extent_list *) (et->et_root_buf + offset); else free_el = (struct ocfs2_extent_list *) (backup_buf + offset); free_duplicated_extent_block(fs, free_el); ocfs2_free(&backup_buf); } ocfs2_free_path(left_path); return ret; } static int ocfs2_split_tree(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *path, int index, uint32_t new_range) { errcode_t ret; int depth; char *last_eb_buf = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *rightmost_el, *el; struct ocfs2_extent_rec *rec; struct ocfs2_insert_type insert; struct insert_ctxt ctxt; ctxt.fs = fs; ctxt.et = et; ret = ocfs2_malloc_block(fs->fs_io, &last_eb_buf); if (ret) return ret; /* * Setup the record to split before we grow the tree. */ el = path_leaf_el(path); rec = &el->l_recs[index]; ocfs2_make_right_split_rec(fs, &ctxt.rec, new_range, rec); depth = path->p_tree_depth; if (depth > 0) { ret = ocfs2_read_extent_block(fs, ocfs2_et_get_last_eb_blk(et), last_eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)last_eb_buf; rightmost_el = &eb->h_list; } else rightmost_el = path_leaf_el(path); if (rightmost_el->l_next_free_rec == rightmost_el->l_count) { ret = ocfs2_grow_tree(fs, et, &depth, &last_eb_buf); if (ret) goto out; } memset(&insert, 0, sizeof(struct ocfs2_insert_type)); insert.ins_appending = APPEND_NONE; insert.ins_contig = CONTIG_NONE; insert.ins_split = SPLIT_RIGHT; insert.ins_tree_depth = depth; ret = ocfs2_do_insert_extent(&ctxt, &insert); out: if (last_eb_buf) ocfs2_free(&last_eb_buf); return ret; } static int ocfs2_truncate_rec(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_path *path, int index, uint32_t cpos, uint32_t len) { errcode_t ret; uint32_t left_cpos, rec_range, trunc_range; int wants_rotate = 0, is_rightmost_tree_rec = 0; struct ocfs2_path *left_path = NULL; struct ocfs2_extent_list *el = path_leaf_el(path); struct ocfs2_extent_rec *rec; struct ocfs2_extent_block *eb; if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) { ret = ocfs2_rotate_tree_left(fs, et, path); if (ret) goto out; index--; } if (index == el->l_next_free_rec - 1 && path->p_tree_depth) { /* * Check whether this is the rightmost tree record. If * we remove all of this record or part of its right * edge then an update of the record lengths above it * will be required. */ eb = (struct ocfs2_extent_block *)path_leaf_buf(path); if (eb->h_next_leaf_blk == 0) is_rightmost_tree_rec = 1; } rec = &el->l_recs[index]; if (index == 0 && path->p_tree_depth && rec->e_cpos == cpos) { /* * Changing the leftmost offset (via partial or whole * record truncate) of an interior (or rightmost) path * means we have to update the subtree that is formed * by this leaf and the one to it's left. * * There are two cases we can skip: * 1) Path is the leftmost one in our btree. * 2) The leaf is rightmost and will be empty after * we remove the extent record - the rotate code * knows how to update the newly formed edge. */ ret = ocfs2_find_cpos_for_left_leaf(path, &left_cpos); if (ret) goto out; if (left_cpos && el->l_next_free_rec > 1) { left_path = ocfs2_new_path_from_path(path); if (!left_path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, left_path, left_cpos); if (ret) goto out; } } rec_range = rec->e_cpos + ocfs2_rec_clusters(el->l_tree_depth, rec); trunc_range = cpos + len; if (rec->e_cpos == cpos && rec_range == trunc_range) { int next_free; memset(rec, 0, sizeof(*rec)); ocfs2_cleanup_merge(el, index); wants_rotate = 1; next_free = el->l_next_free_rec; if (is_rightmost_tree_rec && next_free > 1) { /* * We skip the edge update if this path will * be deleted by the rotate code. */ rec = &el->l_recs[next_free - 1]; ocfs2_adjust_rightmost_records(fs, path, rec); } } else if (rec->e_cpos == cpos) { /* Remove leftmost portion of the record. */ rec->e_cpos += len; rec->e_blkno += ocfs2_clusters_to_blocks(fs, len); rec->e_leaf_clusters -= len; } else if (rec_range == trunc_range) { /* Remove rightmost portion of the record */ rec->e_leaf_clusters -= len; if (is_rightmost_tree_rec) ocfs2_adjust_rightmost_records(fs, path, rec); } else { /* Caller should have trapped this. */ assert(0); } if (left_path) { int subtree_index; subtree_index = ocfs2_find_subtree_root(left_path, path); ocfs2_complete_edge_insert(fs, left_path, path, subtree_index); } ret = ocfs2_rotate_tree_left(fs, et, path); out: ocfs2_free_path(left_path); return ret; } int ocfs2_remove_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t len) { int ret, index; uint32_t rec_range, trunc_range; struct ocfs2_extent_rec *rec; struct ocfs2_extent_list *el; struct ocfs2_path *path = NULL; path = ocfs2_new_path_from_et(et); if (!path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, path, cpos); if (ret) goto out; el = path_leaf_el(path); index = ocfs2_search_extent_list(el, cpos); if (index == -1 || index >= el->l_next_free_rec) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } /* * We have 3 cases of extent removal: * 1) Range covers the entire extent rec * 2) Range begins or ends on one edge of the extent rec * 3) Range is in the middle of the extent rec (no shared edges) * * For case 1 we remove the extent rec and left rotate to * fill the hole. * * For case 2 we just shrink the existing extent rec, with a * tree update if the shrinking edge is also the edge of an * extent block. * * For case 3 we do a right split to turn the extent rec into * something case 2 can handle. */ rec = &el->l_recs[index]; rec_range = rec->e_cpos + ocfs2_rec_clusters(el->l_tree_depth, rec); trunc_range = cpos + len; assert(cpos >= rec->e_cpos && trunc_range <= rec_range); if (rec->e_cpos == cpos || rec_range == trunc_range) { ret = ocfs2_truncate_rec(fs, et, path, index, cpos, len); if (ret) goto out; } else { ret = ocfs2_split_tree(fs, et, path, index, trunc_range); if (ret) goto out; /* * The split could have manipulated the tree enough to * move the record location, so we have to look for it again. */ ocfs2_reinit_path(path, 1); ret = ocfs2_find_path(fs, path, cpos); if (ret) goto out; el = path_leaf_el(path); index = ocfs2_search_extent_list(el, cpos); if (index == -1 || index >= el->l_next_free_rec) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } /* * Double check our values here. If anything is fishy, * it's easier to catch it at the top level. */ rec = &el->l_recs[index]; rec_range = rec->e_cpos + ocfs2_rec_clusters(el->l_tree_depth, rec); if (rec_range != trunc_range) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } ret = ocfs2_truncate_rec(fs, et, path, index, cpos, len); if (ret) goto out; } out: ocfs2_free_path(path); return ret; } ./ocfs2-tools-1.6.4/libocfs2/refcount.c0000644000176100017610000016256411500500544014462 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * refcount.c * * Functions for the refcount tree structure. Part of the OCFS2 userspace * library. * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #define _XOPEN_SOURCE 600 /* Triggers XOPEN2K in features.h */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include "extent_tree.h" #include "refcount.h" struct ocfs2_cow_context { ocfs2_filesys *fs; uint32_t cow_start; uint32_t cow_len; struct ocfs2_extent_tree data_et; char *ref_root_buf; uint64_t ref_root_blkno; void *cow_object; struct ocfs2_post_refcount *post_refcount; int (*get_clusters)(struct ocfs2_cow_context *context, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags); }; static void ocfs2_swap_refcount_list_primary(struct ocfs2_refcount_list *rl) { rl->rl_count = bswap_16(rl->rl_count); rl->rl_used = bswap_16(rl->rl_used); } static void ocfs2_swap_refcount_list_secondary(ocfs2_filesys *fs, void *obj, struct ocfs2_refcount_list *rl) { int i; for (i = 0; i < rl->rl_count; i++) { struct ocfs2_refcount_rec *rec = &rl->rl_recs[i]; if (ocfs2_swap_barrier(fs, obj, rec, sizeof(struct ocfs2_refcount_rec))) break; rec->r_cpos = bswap_64(rec->r_cpos); rec->r_clusters = bswap_32(rec->r_clusters); rec->r_refcount = bswap_32(rec->r_refcount); } } void ocfs2_swap_refcount_list_from_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_refcount_list *rl) { if (cpu_is_little_endian) return; ocfs2_swap_refcount_list_secondary(fs, obj, rl); ocfs2_swap_refcount_list_primary(rl); } void ocfs2_swap_refcount_list_to_cpu(ocfs2_filesys *fs, void *obj, struct ocfs2_refcount_list *rl) { if (cpu_is_little_endian) return; ocfs2_swap_refcount_list_primary(rl); ocfs2_swap_refcount_list_secondary(fs, obj, rl); } static void ocfs2_swap_refcount_block_header(struct ocfs2_refcount_block *rb) { rb->rf_suballoc_slot = bswap_16(rb->rf_suballoc_slot); rb->rf_suballoc_bit = bswap_16(rb->rf_suballoc_bit); rb->rf_fs_generation = bswap_32(rb->rf_fs_generation); rb->rf_blkno = bswap_64(rb->rf_blkno); rb->rf_parent = bswap_64(rb->rf_parent); rb->rf_last_eb_blk = bswap_64(rb->rf_last_eb_blk); rb->rf_count = bswap_32(rb->rf_count); rb->rf_flags = bswap_32(rb->rf_flags); rb->rf_clusters = bswap_32(rb->rf_clusters); rb->rf_cpos = bswap_32(rb->rf_cpos); rb->rf_suballoc_loc = bswap_64(rb->rf_suballoc_loc); } void ocfs2_swap_refcount_block_from_cpu(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb) { if (cpu_is_little_endian) return; if (rb->rf_flags & OCFS2_REFCOUNT_TREE_FL) ocfs2_swap_extent_list_from_cpu(fs, rb, &rb->rf_list); else ocfs2_swap_refcount_list_from_cpu(fs, rb, &rb->rf_records); ocfs2_swap_refcount_block_header(rb); } void ocfs2_swap_refcount_block_to_cpu(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb) { if (cpu_is_little_endian) return; ocfs2_swap_refcount_block_header(rb); if (rb->rf_flags & OCFS2_REFCOUNT_TREE_FL) ocfs2_swap_extent_list_to_cpu(fs, rb, &rb->rf_list); else ocfs2_swap_refcount_list_to_cpu(fs, rb, &rb->rf_records); } errcode_t ocfs2_read_refcount_block_nocheck(ocfs2_filesys *fs, uint64_t blkno, char *rb_buf) { errcode_t ret; char *blk; struct ocfs2_refcount_block *rb; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; rb = (struct ocfs2_refcount_block *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &rb->rf_check); if (ret) goto out; if (memcmp(rb->rf_signature, OCFS2_REFCOUNT_BLOCK_SIGNATURE, strlen(OCFS2_REFCOUNT_BLOCK_SIGNATURE))) { ret = OCFS2_ET_BAD_EXTENT_BLOCK_MAGIC; goto out; } memcpy(rb_buf, blk, fs->fs_blocksize); rb = (struct ocfs2_refcount_block *) rb_buf; ocfs2_swap_refcount_block_to_cpu(fs, rb); out: ocfs2_free(&blk); return ret; } errcode_t ocfs2_read_refcount_block(ocfs2_filesys *fs, uint64_t blkno, char *rb_buf) { errcode_t ret; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)rb_buf; ret = ocfs2_read_refcount_block_nocheck(fs, blkno, rb_buf); /* * Return corruption error here if the user may have a chance * to walk off the end. * XXX: We trust the rb->rf_flags here. */ if (ret == 0 && (((rb->rf_flags & OCFS2_REFCOUNT_TREE_FL) && rb->rf_list.l_next_free_rec > rb->rf_list.l_count) || (!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL) && rb->rf_records.rl_used > rb->rf_records.rl_count))) ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; return ret; } errcode_t ocfs2_write_refcount_block(ocfs2_filesys *fs, uint64_t blkno, char *rb_buf) { errcode_t ret; char *blk; struct ocfs2_refcount_block *rb; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; memcpy(blk, rb_buf, fs->fs_blocksize); rb = (struct ocfs2_refcount_block *)blk; ocfs2_swap_refcount_block_from_cpu(fs, rb); ocfs2_compute_meta_ecc(fs, blk, &rb->rf_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; } static void ocfs2_find_refcount_rec_in_rl(char *ref_leaf_buf, uint64_t cpos, unsigned int len, struct ocfs2_refcount_rec *ret_rec, int *index) { int i = 0; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_rec *rec = NULL; for (; i < rb->rf_records.rl_used; i++) { rec = &rb->rf_records.rl_recs[i]; if (rec->r_cpos + rec->r_clusters <= cpos) continue; else if (rec->r_cpos > cpos) break; /* ok, cpos fail in this rec. Just return. */ if (ret_rec) *ret_rec = *rec; goto out; } if (ret_rec) { /* We meet with a hole here, so fake the rec. */ ret_rec->r_cpos = cpos; ret_rec->r_refcount = 0; if (i < rb->rf_records.rl_used && rec->r_cpos < cpos + len) ret_rec->r_clusters = rec->r_cpos - cpos; else ret_rec->r_clusters = len; } out: *index = i; } /* * Given a cpos and len, try to find the refcount record which contains cpos. * 1. If cpos can be found in one refcount record, return the record. * 2. If cpos can't be found, return a fake record which start from cpos * and end at a small value between cpos+len and start of the next record. * This fake record has r_refcount = 0. */ int ocfs2_get_refcount_rec(ocfs2_filesys *fs, char *ref_root_buf, uint64_t cpos, unsigned int len, struct ocfs2_refcount_rec *ret_rec, int *index, char *ret_buf) { int ret = 0, i, found; uint32_t low_cpos; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *tmp, *rec = NULL; struct ocfs2_extent_block *eb; char *eb_buf = NULL, *ref_leaf_buf = NULL; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_root_buf; if (!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)) { ocfs2_find_refcount_rec_in_rl(ref_root_buf, cpos, len, ret_rec, index); memcpy(ret_buf, ref_root_buf, fs->fs_blocksize); return 0; } el = &rb->rf_list; low_cpos = cpos & OCFS2_32BIT_POS_MASK; if (el->l_tree_depth) { ret = ocfs2_tree_find_leaf(fs, el, rb->rf_blkno, (char *)rb, low_cpos, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } found = 0; for (i = el->l_next_free_rec - 1; i >= 0; i--) { rec = &el->l_recs[i]; if (rec->e_cpos <= low_cpos) { found = 1; break; } } /* adjust len when we have ocfs2_extent_rec after it. */ if (found && i < el->l_next_free_rec - 1) { tmp = &el->l_recs[i+1]; if (tmp->e_cpos < cpos + len) len = tmp->e_cpos - cpos; } ret = ocfs2_malloc_block(fs->fs_io, &ref_leaf_buf); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, rec->e_blkno, ref_leaf_buf); if (ret) goto out; ocfs2_find_refcount_rec_in_rl(ref_leaf_buf, cpos, len, ret_rec, index); memcpy(ret_buf, ref_leaf_buf, fs->fs_blocksize); out: if (eb_buf) ocfs2_free(&eb_buf); if (ref_leaf_buf) ocfs2_free(&ref_leaf_buf); return ret; } enum ocfs2_ref_rec_contig { REF_CONTIG_NONE = 0, REF_CONTIG_LEFT, REF_CONTIG_RIGHT, REF_CONTIG_LEFTRIGHT, }; static enum ocfs2_ref_rec_contig ocfs2_refcount_rec_adjacent(struct ocfs2_refcount_block *rb, int index) { if ((rb->rf_records.rl_recs[index].r_refcount == rb->rf_records.rl_recs[index + 1].r_refcount) && (rb->rf_records.rl_recs[index].r_cpos + rb->rf_records.rl_recs[index].r_clusters == rb->rf_records.rl_recs[index + 1].r_cpos)) return REF_CONTIG_RIGHT; return REF_CONTIG_NONE; } static enum ocfs2_ref_rec_contig ocfs2_refcount_rec_contig(struct ocfs2_refcount_block *rb, int index) { enum ocfs2_ref_rec_contig ret = REF_CONTIG_NONE; if (index < rb->rf_records.rl_used - 1) ret = ocfs2_refcount_rec_adjacent(rb, index); if (index > 0) { enum ocfs2_ref_rec_contig tmp; tmp = ocfs2_refcount_rec_adjacent(rb, index - 1); if (tmp == REF_CONTIG_RIGHT) { if (ret == REF_CONTIG_RIGHT) ret = REF_CONTIG_LEFTRIGHT; else ret = REF_CONTIG_LEFT; } } return ret; } static void ocfs2_rotate_refcount_rec_left(struct ocfs2_refcount_block *rb, int index) { assert(rb->rf_records.rl_recs[index].r_refcount == rb->rf_records.rl_recs[index+1].r_refcount); rb->rf_records.rl_recs[index].r_clusters += rb->rf_records.rl_recs[index+1].r_clusters; if (index < rb->rf_records.rl_used - 2) memmove(&rb->rf_records.rl_recs[index + 1], &rb->rf_records.rl_recs[index + 2], sizeof(struct ocfs2_refcount_rec) * (rb->rf_records.rl_used - index - 2)); memset(&rb->rf_records.rl_recs[rb->rf_records.rl_used - 1], 0, sizeof(struct ocfs2_refcount_rec)); rb->rf_records.rl_used -= 1; } /* * Merge the refcount rec if we are contiguous with the adjacent recs. */ static void ocfs2_refcount_rec_merge(struct ocfs2_refcount_block *rb, int index) { enum ocfs2_ref_rec_contig contig = ocfs2_refcount_rec_contig(rb, index); if (contig == REF_CONTIG_NONE) return; if (contig == REF_CONTIG_LEFT || contig == REF_CONTIG_LEFTRIGHT) { assert(index > 0); index--; } ocfs2_rotate_refcount_rec_left(rb, index); if (contig == REF_CONTIG_LEFTRIGHT) ocfs2_rotate_refcount_rec_left(rb, index); } /* * Change the refcount indexed by "index" in rb. * If refcount reaches 0, remove it. */ static int ocfs2_change_refcount_rec(ocfs2_filesys *fs, char *ref_leaf_buf, int index, int merge, int change) { struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_list *rl = &rb->rf_records; struct ocfs2_refcount_rec *rec = &rl->rl_recs[index]; rec->r_refcount += change; if (!rec->r_refcount) { if (index != rl->rl_used - 1) { memmove(rec, rec + 1, (rl->rl_used - index - 1) * sizeof(struct ocfs2_refcount_rec)); memset(&rl->rl_recs[le16_to_cpu(rl->rl_used) - 1], 0, sizeof(struct ocfs2_refcount_rec)); } rl->rl_used -= 1; } else if (merge) ocfs2_refcount_rec_merge(rb, index); return ocfs2_write_refcount_block(fs, rb->rf_blkno, ref_leaf_buf); } static int ocfs2_expand_inline_ref_root(ocfs2_filesys *fs, char *ref_root_buf, char *ret_leaf_buf) { int ret; uint64_t new_blkno; char *new_buf = NULL; struct ocfs2_refcount_block *new_rb; struct ocfs2_refcount_block *root_rb = (struct ocfs2_refcount_block *)ref_root_buf; ret = ocfs2_malloc_block(fs->fs_io, &new_buf); if (ret) return ret; ret = ocfs2_new_refcount_block(fs, &new_blkno, root_rb->rf_blkno, root_rb->rf_generation); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, new_blkno, new_buf); if (ret) goto out; /* * Initialize ocfs2_refcount_block. * It should contain the same refcount information as the * old root. So just memcpy the refcount_list, set the * rf_cpos to 0 and the leaf flag. */ new_rb = (struct ocfs2_refcount_block *)new_buf; memcpy(&new_rb->rf_list, &root_rb->rf_list, fs->fs_blocksize - offsetof(struct ocfs2_refcount_block, rf_list)); new_rb->rf_cpos = 0; new_rb->rf_flags = OCFS2_REFCOUNT_LEAF_FL; /* Now change the root. */ memset(&root_rb->rf_list, 0, fs->fs_blocksize - offsetof(struct ocfs2_refcount_block, rf_list)); root_rb->rf_list.l_count = ocfs2_extent_recs_per_rb(fs->fs_blocksize); root_rb->rf_clusters = 1; root_rb->rf_list.l_next_free_rec = 1; root_rb->rf_list.l_recs[0].e_blkno = new_blkno; root_rb->rf_list.l_recs[0].e_leaf_clusters = 1; root_rb->rf_flags = OCFS2_REFCOUNT_TREE_FL; /* * We write the new allocated refcount block first. If the write * fails, skip update the root. */ ret = ocfs2_write_refcount_block(fs, new_rb->rf_blkno, new_buf); if (ret) goto out; ret = ocfs2_write_refcount_block(fs, root_rb->rf_blkno, ref_root_buf); if (ret) goto out; memcpy(ret_leaf_buf, new_buf, fs->fs_blocksize); out: ocfs2_free(&new_buf); return ret; } static int ocfs2_refcount_rec_no_intersect(struct ocfs2_refcount_rec *prev, struct ocfs2_refcount_rec *next) { if (ocfs2_get_ref_rec_low_cpos(prev) + prev->r_clusters <= ocfs2_get_ref_rec_low_cpos(next)) return 1; return 0; } static int cmp_refcount_rec_by_low_cpos(const void *a, const void *b) { const struct ocfs2_refcount_rec *l = a, *r = b; uint32_t l_cpos = ocfs2_get_ref_rec_low_cpos(l); uint32_t r_cpos = ocfs2_get_ref_rec_low_cpos(r); if (l_cpos > r_cpos) return 1; if (l_cpos < r_cpos) return -1; return 0; } static int cmp_refcount_rec_by_cpos(const void *a, const void *b) { const struct ocfs2_refcount_rec *l = a, *r = b; uint64_t l_cpos = l->r_cpos; uint64_t r_cpos = r->r_cpos; if (l_cpos > r_cpos) return 1; if (l_cpos < r_cpos) return -1; return 0; } /* * The refcount cpos are ordered by their 64bit cpos, * But we will use the low 32 bit to be the e_cpos in the b-tree. * So we need to make sure that this pos isn't intersected with others. * * Note: The refcount block is already sorted by their low 32 bit cpos, * So just try the middle pos first, and we will exit when we find * the good position. */ static int ocfs2_find_refcount_split_pos(struct ocfs2_refcount_list *rl, uint32_t *split_pos, int *split_index) { int num_used = rl->rl_used; int delta, middle = num_used / 2; for (delta = 0; delta < middle; delta++) { /* Let's check delta earlier than middle */ if (ocfs2_refcount_rec_no_intersect( &rl->rl_recs[middle - delta - 1], &rl->rl_recs[middle - delta])) { *split_index = middle - delta; break; } /* For even counts, don't walk off the end */ if ((middle + delta + 1) == num_used) continue; /* Now try delta past middle */ if (ocfs2_refcount_rec_no_intersect( &rl->rl_recs[middle + delta], &rl->rl_recs[middle + delta + 1])) { *split_index = middle + delta + 1; break; } } if (delta >= middle) return OCFS2_ET_NO_SPACE; *split_pos = ocfs2_get_ref_rec_low_cpos(&rl->rl_recs[*split_index]); return 0; } static int ocfs2_divide_leaf_refcount_block(char *ref_leaf_buf, char *new_buf, uint32_t *split_cpos) { int split_index = 0, num_moved, ret; uint32_t cpos = 0; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_list *rl = &rb->rf_records; struct ocfs2_refcount_block *new_rb = (struct ocfs2_refcount_block *)new_buf; struct ocfs2_refcount_list *new_rl = &new_rb->rf_records; /* * XXX: Improvement later. * If we know all the high 32 bit cpos is the same, no need to sort. * * In order to make the whole process safe, we do: * 1. sort the entries by their low 32 bit cpos first so that we can * find the split cpos easily. * 2. call ocfs2_tree_insert_extent to insert the new refcount block. * 3. move the refcount rec to the new block. * 4. sort the entries by their 64 bit cpos. * 5. And we will delay the write out of the leaf block after the * extent tree is successfully changed by its caller. */ qsort(&rl->rl_recs, rl->rl_used, sizeof(struct ocfs2_refcount_rec), cmp_refcount_rec_by_low_cpos); ret = ocfs2_find_refcount_split_pos(rl, &cpos, &split_index); if (ret) return ret; new_rb->rf_cpos = cpos; /* move refcount records starting from split_index to the new block. */ num_moved = rl->rl_used - split_index; memcpy(new_rl->rl_recs, &rl->rl_recs[split_index], num_moved * sizeof(struct ocfs2_refcount_rec)); /*ok, remove the entries we just moved over to the other block. */ memset(&rl->rl_recs[split_index], 0, num_moved * sizeof(struct ocfs2_refcount_rec)); /* change old and new rl_used accordingly. */ rl->rl_used -= num_moved; new_rl->rl_used = num_moved; qsort(&rl->rl_recs, rl->rl_used, sizeof(struct ocfs2_refcount_rec), cmp_refcount_rec_by_cpos); qsort(&new_rl->rl_recs, new_rl->rl_used, sizeof(struct ocfs2_refcount_rec), cmp_refcount_rec_by_cpos); *split_cpos = cpos; return 0; } static int ocfs2_new_leaf_refcount_block(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf) { int ret; uint32_t new_cpos; uint64_t new_blkno; struct ocfs2_refcount_block *root_rb = (struct ocfs2_refcount_block *)ref_root_buf; char *new_buf = NULL; struct ocfs2_refcount_block *rb; struct ocfs2_extent_tree ref_et; assert(root_rb->rf_flags & OCFS2_REFCOUNT_TREE_FL); ret = ocfs2_malloc_block(fs->fs_io, &new_buf); if (ret) return ret; ret = ocfs2_new_refcount_block(fs, &new_blkno, root_rb->rf_blkno, root_rb->rf_generation); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, new_blkno, new_buf); ret = ocfs2_divide_leaf_refcount_block(ref_leaf_buf, new_buf, &new_cpos); if (ret) goto out; ocfs2_init_refcount_extent_tree(&ref_et, fs, ref_root_buf, root_rb->rf_blkno); ret = ocfs2_tree_insert_extent(fs, &ref_et, new_cpos, new_blkno, 1, 0); if (ret) goto out; /* * Write the old refcount block first. * If the write fails, fsck should be able to remove all * the refcounted clusters we have moved to the new refcount block. */ rb = (struct ocfs2_refcount_block *)ref_leaf_buf; ret = ocfs2_write_refcount_block(fs, rb->rf_blkno, ref_leaf_buf); if (ret) goto out; ret = ocfs2_write_refcount_block(fs, new_blkno, new_buf); if (ret) goto out; out: if (new_buf) ocfs2_free(&new_buf); return ret; } static int ocfs2_expand_refcount_tree(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf) { int ret; struct ocfs2_refcount_block *root_rb = (struct ocfs2_refcount_block *)ref_root_buf; struct ocfs2_refcount_block *leaf_rb = (struct ocfs2_refcount_block *)ref_leaf_buf; if (root_rb->rf_blkno == leaf_rb->rf_blkno) { /* * the old root bh hasn't been expanded to a b-tree, * so expand it first. */ ret = ocfs2_expand_inline_ref_root(fs, ref_root_buf, ref_leaf_buf); if (ret) goto out; } /* Now add a new refcount block into the tree.*/ ret = ocfs2_new_leaf_refcount_block(fs, ref_root_buf, ref_leaf_buf); out: return ret; } /* * Adjust the extent rec in b-tree representing ref_leaf_buf. * * Only called when we have inserted a new refcount rec at index 0 * which means ocfs2_extent_rec.e_cpos may need some change. */ static int ocfs2_adjust_refcount_rec(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf, struct ocfs2_refcount_rec *rec) { int ret = 0, i; uint32_t new_cpos, old_cpos; struct ocfs2_path *path = NULL; struct ocfs2_extent_list *el; struct ocfs2_extent_tree et; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_root_buf; uint64_t ref_root_blkno = rb->rf_blkno;; if (!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)) goto out; rb = (struct ocfs2_refcount_block *)ref_leaf_buf; old_cpos = rb->rf_cpos; new_cpos = rec->r_cpos & OCFS2_32BIT_POS_MASK; if (old_cpos <= new_cpos) goto out; ocfs2_init_refcount_extent_tree(&et, fs, ref_root_buf, ref_root_blkno); path = ocfs2_new_path_from_et(&et); if (!path) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_find_path(fs, path, old_cpos); if (ret) goto out; /* change the leaf extent block first. */ el = path_leaf_el(path); for (i = 0; i < el->l_next_free_rec; i++) if (el->l_recs[i].e_cpos == old_cpos) break; assert(i < el->l_next_free_rec); el->l_recs[i].e_cpos = new_cpos; /* change the r_cpos in the leaf block. */ rb->rf_cpos = new_cpos; ret = ocfs2_write_extent_block(fs, path_leaf_blkno(path), path_leaf_buf(path)); if (ret) goto out; ret = ocfs2_write_refcount_block(fs, rb->rf_blkno, ref_leaf_buf); out: ocfs2_free_path(path); return ret; } static int ocfs2_insert_refcount_rec(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf, struct ocfs2_refcount_rec *rec, int index, int merge) { int ret; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_list *rf_list = &rb->rf_records; assert(!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)); if (rf_list->rl_used == rf_list->rl_count) { uint64_t cpos = rec->r_cpos; uint32_t len = rec->r_clusters; ret = ocfs2_expand_refcount_tree(fs, ref_root_buf, ref_leaf_buf); if (ret) goto out; ret = ocfs2_get_refcount_rec(fs, ref_root_buf, cpos, len, NULL, &index, ref_leaf_buf); if (ret) goto out; } if (index < rf_list->rl_used) memmove(&rf_list->rl_recs[index + 1], &rf_list->rl_recs[index], (rf_list->rl_used - index) * sizeof(struct ocfs2_refcount_rec)); rf_list->rl_recs[index] = *rec; rf_list->rl_used += 1; if (merge) ocfs2_refcount_rec_merge(rb, index); ret = ocfs2_write_refcount_block(fs, rb->rf_blkno, ref_leaf_buf); if (ret) goto out; if (index == 0) ret = ocfs2_adjust_refcount_rec(fs, ref_root_buf, ref_leaf_buf, rec); out: return ret; } /* * Split the refcount_rec indexed by "index" in ref_leaf_buf. * This is much simple than our b-tree code. * split_rec is the new refcount rec we want to insert. * If split_rec->r_refcount > 0, we are changing the refcount(in case we * increase refcount or decrease a refcount to non-zero). * If split_rec->r_refcount == 0, we are punching a hole in current refcount * rec( in case we decrease a refcount to zero). */ static int ocfs2_split_refcount_rec(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf, struct ocfs2_refcount_rec *split_rec, int index, int merge) { int ret, recs_need; uint32_t len; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_list *rf_list = &rb->rf_records; struct ocfs2_refcount_rec *orig_rec = &rf_list->rl_recs[index]; struct ocfs2_refcount_rec *tail_rec = NULL; assert(!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)); /* * If we just need to split the header or tail clusters, * no more recs are needed, just split is OK. * Otherwise we at least need one new recs. */ if (!split_rec->r_refcount && (split_rec->r_cpos == orig_rec->r_cpos || split_rec->r_cpos + split_rec->r_clusters == orig_rec->r_cpos + orig_rec->r_clusters)) recs_need = 0; else recs_need = 1; /* * We need one more rec if we split in the middle and the new rec have * some refcount in it. */ if (split_rec->r_refcount && (split_rec->r_cpos != orig_rec->r_cpos && split_rec->r_cpos + split_rec->r_clusters != orig_rec->r_cpos + orig_rec->r_clusters)) recs_need++; /* If the leaf block don't have enough record, expand it. */ if (rf_list->rl_used + recs_need > rf_list->rl_count) { struct ocfs2_refcount_rec tmp_rec; uint64_t cpos = orig_rec->r_cpos; len = orig_rec->r_clusters; ret = ocfs2_expand_refcount_tree(fs, ref_root_buf, ref_leaf_buf); if (ret) goto out; /* * We have to re-get it since now cpos may be moved to * another leaf block. */ ret = ocfs2_get_refcount_rec(fs, ref_root_buf, cpos, len, &tmp_rec, &index, ref_leaf_buf); if (ret) goto out; orig_rec = &rf_list->rl_recs[index]; } /* * We have calculated out how many new records we need and store * in recs_need, so spare enough space first by moving the records * after "index" to the end. */ if (rf_list->rl_used && index != rf_list->rl_used - 1) memmove(&rf_list->rl_recs[index + 1 + recs_need], &rf_list->rl_recs[index + 1], (rf_list->rl_used - index - 1) * sizeof(struct ocfs2_refcount_rec)); len = (orig_rec->r_cpos + orig_rec->r_clusters) - (split_rec->r_cpos + split_rec->r_clusters); /* * If we have "len", the we will split in the tail and move it * to the end of the space we have just spared. */ if (len) { tail_rec = &rf_list->rl_recs[index + recs_need]; memcpy(tail_rec, orig_rec, sizeof(struct ocfs2_refcount_rec)); tail_rec->r_cpos += tail_rec->r_clusters - len; tail_rec->r_clusters = len; } /* * If the split pos isn't the same as the original one, we need to * split in the head. * * Note: We have the chance that split_rec.r_refcount = 0, * recs_need = 0 and len > 0, which means we just cut the head from * the orig_rec and in that case we have done some modification in * orig_rec above, so the check for r_cpos is faked. */ if (split_rec->r_cpos != orig_rec->r_cpos && tail_rec != orig_rec) { len = split_rec->r_cpos - orig_rec->r_cpos; orig_rec->r_clusters = len; index++; } rf_list->rl_used += recs_need; if (split_rec->r_refcount) { rf_list->rl_recs[index] = *split_rec; if (merge) ocfs2_refcount_rec_merge(rb, index); } ret = ocfs2_write_refcount_block(fs, rb->rf_blkno, ref_leaf_buf); out: return ret; } static int __ocfs2_increase_refcount(ocfs2_filesys *fs, char *ref_root_buf, uint64_t cpos, uint32_t len, int merge, int value) { int ret = 0, index; char *ref_leaf_buf = NULL; struct ocfs2_refcount_rec rec; unsigned int set_len = 0; struct ocfs2_refcount_block *root_rb, *rb; ret = ocfs2_malloc_block(fs->fs_io, &ref_leaf_buf); if (ret) return ret; root_rb = (struct ocfs2_refcount_block *)ref_root_buf; rb = (struct ocfs2_refcount_block *)ref_leaf_buf; while (len) { ret = ocfs2_get_refcount_rec(fs, ref_root_buf, cpos, len, &rec, &index, ref_leaf_buf); if (ret) goto out; set_len = rec.r_clusters; /* * Here we may meet with 3 situations: * * 1. If we find an already existing record, and the length * is the same, cool, we just need to increase the r_refcount * and it is OK. * 2. If we find a hole, just insert it with r_refcount = 1. * 3. If we are in the middle of one extent record, split * it. */ if (rec.r_refcount && rec.r_cpos == cpos && set_len <= len) { ret = ocfs2_change_refcount_rec(fs, ref_leaf_buf, index, merge, value); if (ret) goto out; } else if (!rec.r_refcount) { rec.r_refcount = value; ret = ocfs2_insert_refcount_rec(fs, ref_root_buf, ref_leaf_buf, &rec, index, merge); if (ret) goto out; } else { set_len = ocfs2_min((uint64_t)(cpos + len), (uint64_t)(rec.r_cpos + set_len)) - cpos; rec.r_cpos = cpos; rec.r_clusters = set_len; rec.r_refcount += value; ret = ocfs2_split_refcount_rec(fs, ref_root_buf, ref_leaf_buf, &rec, index, merge); if (ret) goto out; } cpos += set_len; len -= set_len; /* In user space, we have to sync the buf by ourselves. */ if (rb->rf_blkno == root_rb->rf_blkno) memcpy(ref_root_buf, ref_leaf_buf, fs->fs_blocksize); } out: ocfs2_free(&ref_leaf_buf); return ret; } errcode_t ocfs2_increase_refcount(ocfs2_filesys *fs, uint64_t ino, uint64_t cpos, uint32_t len) { errcode_t ret; char *ref_root_buf = NULL; char *di_buf = NULL; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, ino, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; assert(di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL); assert(di->i_refcount_loc); ret = ocfs2_malloc_block(fs->fs_io, &ref_root_buf); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, di->i_refcount_loc, ref_root_buf); if (ret) goto out; ret = __ocfs2_increase_refcount(fs, ref_root_buf, cpos, len, 1, 1); out: if (ref_root_buf) ocfs2_free(&ref_root_buf); if (di_buf) ocfs2_free(&di_buf); return ret; } static int ocfs2_remove_refcount_extent(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf) { int ret; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_block *root_rb = (struct ocfs2_refcount_block *)ref_root_buf; struct ocfs2_extent_tree et; assert(rb->rf_records.rl_used == 0); ocfs2_init_refcount_extent_tree(&et, fs, ref_root_buf, root_rb->rf_blkno); ret = ocfs2_remove_extent(fs, &et, rb->rf_cpos, 1); if (ret) goto out; ret = ocfs2_delete_refcount_block(fs, rb->rf_blkno); root_rb->rf_clusters -= 1; /* * check whether we need to restore the root refcount block if * there is no leaf extent block at atll. */ if (!root_rb->rf_list.l_next_free_rec) { assert(root_rb->rf_clusters == 0); root_rb->rf_flags = 0; root_rb->rf_parent = 0; root_rb->rf_cpos = 0; memset(&root_rb->rf_records, 0, fs->fs_blocksize - offsetof(struct ocfs2_refcount_block, rf_records)); root_rb->rf_records.rl_count = ocfs2_refcount_recs_per_rb(fs->fs_blocksize); } ret = ocfs2_write_refcount_block(fs, root_rb->rf_blkno, ref_root_buf); out: return ret; } static int ocfs2_decrease_refcount_rec(ocfs2_filesys *fs, char *ref_root_buf, char *ref_leaf_buf, int index, uint64_t cpos, unsigned int len, int value) { int ret; struct ocfs2_refcount_block *rb = (struct ocfs2_refcount_block *)ref_leaf_buf; struct ocfs2_refcount_block *root_rb = (struct ocfs2_refcount_block *)ref_root_buf; struct ocfs2_refcount_rec *rec = &rb->rf_records.rl_recs[index]; assert(cpos >= rec->r_cpos); assert(cpos + len <= rec->r_cpos + rec->r_clusters); if (cpos == rec->r_cpos && len == rec->r_clusters) ret = ocfs2_change_refcount_rec(fs, ref_leaf_buf, index, 1, -value); else { struct ocfs2_refcount_rec split = *rec; split.r_cpos = cpos; split.r_clusters = len; split.r_refcount -= value; ret = ocfs2_split_refcount_rec(fs, ref_root_buf, ref_leaf_buf, &split, index, 1); } if (ret) goto out; /* In user space, we have to sync the buf by ourselves. */ if (rb->rf_blkno == root_rb->rf_blkno) memcpy(ref_root_buf, ref_leaf_buf, fs->fs_blocksize); /* Remove the leaf refcount block if it contains no refcount record. */ if (!rb->rf_records.rl_used && rb->rf_blkno != root_rb->rf_blkno) { ret = ocfs2_remove_refcount_extent(fs, ref_root_buf, ref_leaf_buf); } out: return ret; } static int __ocfs2_decrease_refcount(ocfs2_filesys *fs, char *ref_root_buf, uint64_t cpos, uint32_t len, int delete) { int ret = 0, index = 0; struct ocfs2_refcount_rec rec; unsigned int r_count = 0, r_len; char *ref_leaf_buf = NULL; ret = ocfs2_malloc_block(fs->fs_io, &ref_leaf_buf); if (ret) return ret; while (len) { ret = ocfs2_get_refcount_rec(fs, ref_root_buf, cpos, len, &rec, &index, ref_leaf_buf); if (ret) goto out; r_count = rec.r_refcount; assert(r_count > 0); if (!delete) assert(r_count == 1); r_len = ocfs2_min((uint64_t)(cpos + len), (uint64_t)(rec.r_cpos + rec.r_clusters)) - cpos; ret = ocfs2_decrease_refcount_rec(fs, ref_root_buf, ref_leaf_buf, index, cpos, r_len, 1); if (ret) goto out; if (rec.r_refcount == 1 && delete) { ret = ocfs2_free_clusters(fs, r_len, ocfs2_clusters_to_blocks(fs, cpos)); if (ret) goto out; } cpos += r_len; len -= r_len; } out: ocfs2_free(&ref_leaf_buf); return ret; } errcode_t ocfs2_decrease_refcount(ocfs2_filesys *fs, uint64_t ino, uint32_t cpos, uint32_t len, int delete) { errcode_t ret; char *ref_root_buf = NULL; char *di_buf = NULL; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, ino, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; assert(di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL); assert(di->i_refcount_loc); ret = ocfs2_malloc_block(fs->fs_io, &ref_root_buf); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, di->i_refcount_loc, ref_root_buf); if (ret) goto out; ret = __ocfs2_decrease_refcount(fs, ref_root_buf, cpos, len, delete); out: if (ref_root_buf) ocfs2_free(&ref_root_buf); if (di_buf) ocfs2_free(&di_buf); return ret; } #define MAX_CONTIG_BYTES 1048576 static inline unsigned int ocfs2_cow_contig_clusters(ocfs2_filesys *fs) { return ocfs2_clusters_in_bytes(fs, MAX_CONTIG_BYTES); } static inline unsigned int ocfs2_cow_contig_mask(ocfs2_filesys *fs) { return ~(ocfs2_cow_contig_clusters(fs) - 1); } /* * Given an extent that starts at 'start' and an I/O that starts at 'cpos', * find an offset (start + (n * contig_clusters)) that is closest to cpos * while still being less than or equal to it. * * The goal is to break the extent at a multiple of contig_clusters. */ static inline unsigned int ocfs2_cow_align_start(ocfs2_filesys *fs, unsigned int start, unsigned int cpos) { assert(start <= cpos); return start + ((cpos - start) & ocfs2_cow_contig_mask(fs)); } /* * Given a cluster count of len, pad it out so that it is a multiple * of contig_clusters. */ static inline unsigned int ocfs2_cow_align_length(ocfs2_filesys *fs, unsigned int len) { unsigned int padded = (len + (ocfs2_cow_contig_clusters(fs) - 1)) & ocfs2_cow_contig_mask(fs); /* Did we wrap? */ if (padded < len) padded = UINT_MAX; return padded; } /* * Calculate out the start and number of virtual clusters we need to to CoW. * * cpos is vitual start cluster position we want to do CoW in a * file and write_len is the cluster length. * max_cpos is the place where we want to stop CoW intentionally. * * Normal we will start CoW from the beginning of extent record cotaining cpos. * We try to break up extents on boundaries of MAX_CONTIG_BYTES so that we * get good I/O from the resulting extent tree. */ static int ocfs2_refcount_cal_cow_clusters(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t write_len, uint32_t max_cpos, uint32_t *cow_start, uint32_t *cow_len) { int ret = 0; struct ocfs2_extent_list *el = et->et_root_el; int tree_height = el->l_tree_depth, i; char *eb_buf = NULL; struct ocfs2_extent_block *eb = NULL; struct ocfs2_extent_rec *rec; unsigned int want_clusters, rec_end = 0; int contig_clusters = ocfs2_cow_contig_clusters(fs); int leaf_clusters; assert(cpos + write_len <= max_cpos); ret = ocfs2_malloc_block(fs->fs_io, &eb_buf); if (ret) return ret; if (tree_height > 0) { ret = ocfs2_tree_find_leaf(fs, el, et->et_root_blkno, et->et_root_buf, cpos, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *) eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } else el = et->et_root_el; *cow_len = 0; for (i = 0; i < el->l_next_free_rec; i++) { rec = &el->l_recs[i]; if (ocfs2_is_empty_extent(rec)) { assert(i == 0); continue; } if (rec->e_cpos + rec->e_leaf_clusters <= cpos) continue; if (*cow_len == 0) { /* * We should find a refcounted record in the * first pass. */ assert(rec->e_flags & OCFS2_EXT_REFCOUNTED); *cow_start = rec->e_cpos; } /* * If we encounter a hole, a non-refcounted record or * pass the max_cpos, stop the search. */ if ((!(rec->e_flags & OCFS2_EXT_REFCOUNTED)) || (*cow_len && rec_end != rec->e_cpos) || (max_cpos <= rec->e_cpos)) break; leaf_clusters = rec->e_leaf_clusters; rec_end = rec->e_cpos + leaf_clusters; if (rec_end > max_cpos) { rec_end = max_cpos; leaf_clusters = rec_end - rec->e_cpos; } /* * How many clusters do we actually need from * this extent? First we see how many we actually * need to complete the write. If that's smaller * than contig_clusters, we try for contig_clusters. */ if (!*cow_len) want_clusters = write_len; else want_clusters = (cpos + write_len) - (*cow_start + *cow_len); if (want_clusters < contig_clusters) want_clusters = contig_clusters; /* * If the write does not cover the whole extent, we * need to calculate how we're going to split the extent. * We try to do it on contig_clusters boundaries. * * Any extent smaller than contig_clusters will be * CoWed in its entirety. */ if (leaf_clusters <= contig_clusters) *cow_len += leaf_clusters; else if (*cow_len || (*cow_start == cpos)) { /* * This extent needs to be CoW'd from its * beginning, so all we have to do is compute * how many clusters to grab. We align * want_clusters to the edge of contig_clusters * to get better I/O. */ want_clusters = ocfs2_cow_align_length(fs, want_clusters); if (leaf_clusters < want_clusters) *cow_len += leaf_clusters; else *cow_len += want_clusters; } else if ((*cow_start + contig_clusters) >= (cpos + write_len)) { /* * Breaking off contig_clusters at the front * of the extent will cover our write. That's * easy. */ *cow_len = contig_clusters; } else if ((rec_end - cpos) <= contig_clusters) { /* * Breaking off contig_clusters at the tail of * this extent will cover cpos. */ *cow_start = rec_end - contig_clusters; *cow_len = contig_clusters; } else if ((rec_end - cpos) <= want_clusters) { /* * While we can't fit the entire write in this * extent, we know that the write goes from cpos * to the end of the extent. Break that off. * We try to break it at some multiple of * contig_clusters from the front of the extent. * Failing that (ie, cpos is within * contig_clusters of the front), we'll CoW the * entire extent. */ *cow_start = ocfs2_cow_align_start(fs, *cow_start, cpos); *cow_len = rec_end - *cow_start; } else { /* * Ok, the entire write lives in the middle of * this extent. Let's try to slice the extent up * nicely. Optimally, our CoW region starts at * m*contig_clusters from the beginning of the * extent and goes for n*contig_clusters, * covering the entire write. */ *cow_start = ocfs2_cow_align_start(fs, *cow_start, cpos); want_clusters = (cpos + write_len) - *cow_start; want_clusters = ocfs2_cow_align_length(fs, want_clusters); if (*cow_start + want_clusters <= rec_end) *cow_len = want_clusters; else *cow_len = rec_end - *cow_start; } /* Have we covered our entire write yet? */ if ((*cow_start + *cow_len) >= (cpos + write_len)) break; /* * If we reach the end of the extent block and don't get enough * clusters, continue with the next extent block if possible. */ if (i + 1 == el->l_next_free_rec && eb && eb->h_next_leaf_blk) { ret = ocfs2_read_extent_block(fs, eb->h_next_leaf_blk, eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)eb_buf; el = &eb->h_list; i = -1; } } out: if (eb_buf) ocfs2_free(&eb_buf); return ret; } static int ocfs2_duplicate_clusters(struct ocfs2_cow_context *context, uint32_t cpos, uint32_t old_cluster, uint32_t new_cluster, uint32_t new_len) { int ret; int i, bpc = context->fs->fs_clustersize / context->fs->fs_blocksize; uint64_t old_block = ocfs2_clusters_to_blocks(context->fs, old_cluster); uint64_t new_block = ocfs2_clusters_to_blocks(context->fs, new_cluster); char *buf = NULL; ret = ocfs2_malloc_blocks(context->fs->fs_io, bpc, &buf); if (ret) return ret; for (i = 0; i < new_len; i++, old_block += bpc, new_block += bpc) { ret = ocfs2_read_blocks(context->fs, old_block, bpc, buf); if (ret) break; ret = io_write_block(context->fs->fs_io, new_block, bpc, buf); if (ret) break; } ocfs2_free(&buf); return ret; } static int __ocfs2_clear_ext_refcount(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t p_cluster, uint32_t len, unsigned int ext_flags) { return ocfs2_change_extent_flag(fs, et, cpos, len, ocfs2_clusters_to_blocks(fs, p_cluster), 0, OCFS2_EXT_REFCOUNTED); } static int ocfs2_replace_clusters(struct ocfs2_cow_context *context, uint32_t cpos, uint32_t old, uint32_t new, uint32_t len, unsigned int ext_flags) { int ret; /*If the old clusters is unwritten, no need to duplicate. */ if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { ret = ocfs2_duplicate_clusters(context, cpos, old, new, len); if (ret) goto out; } ret = __ocfs2_clear_ext_refcount(context->fs, &context->data_et, cpos, new, len, ext_flags); out: return ret; } static int ocfs2_di_get_clusters(struct ocfs2_cow_context *context, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags) { ocfs2_cached_inode *cinode = context->cow_object; return ocfs2_get_clusters(cinode, v_cluster, p_cluster, num_clusters, extent_flags); } static int ocfs2_make_clusters_writable(struct ocfs2_cow_context *context, uint32_t cpos, uint32_t p_cluster, uint32_t num_clusters, unsigned int e_flags) { int ret, delete, index; uint32_t new_len; uint64_t start; unsigned int set_len; char *ref_leaf_buf = NULL; struct ocfs2_refcount_rec rec; ret = ocfs2_malloc_block(context->fs->fs_io, &ref_leaf_buf); if (ret) return ret; while (num_clusters) { ret = ocfs2_get_refcount_rec(context->fs, context->ref_root_buf, p_cluster, num_clusters, &rec, &index, ref_leaf_buf); if (ret) goto out; assert(rec.r_refcount); set_len = ocfs2_min((uint64_t)p_cluster + num_clusters, (uint64_t)rec.r_cpos + rec.r_clusters) - p_cluster; /* * There are many different situation here. * 1. If refcount == 1, remove the flag and don't COW. * 2. If refcount > 1, allocate clusters. * Here we may not allocate r_len once at a time, so continue * until we reach num_clusters. */ if (rec.r_refcount == 1) { delete = 0; ret = __ocfs2_clear_ext_refcount(context->fs, &context->data_et, cpos, p_cluster, set_len, e_flags); if (ret) goto out; } else { delete = 1; ret = ocfs2_new_clusters(context->fs, 1, set_len, &start, &new_len); if (ret) goto out; ret = ocfs2_replace_clusters(context, cpos, p_cluster, ocfs2_blocks_to_clusters(context->fs, start), new_len, e_flags); if (ret) goto out; set_len = new_len; } ret = __ocfs2_decrease_refcount(context->fs, context->ref_root_buf, p_cluster, set_len, delete); if (ret) goto out; cpos += set_len; p_cluster += set_len; num_clusters -= set_len; } /* handle any post_cow action. */ if (context->post_refcount && context->post_refcount->func) { ret = context->post_refcount->func(context->fs, context->post_refcount->para); if (ret) goto out; } out: if (ref_leaf_buf) ocfs2_free(&ref_leaf_buf); return ret; } static int ocfs2_replace_cow(struct ocfs2_cow_context *context) { int ret = 0; uint32_t cow_start = context->cow_start, cow_len = context->cow_len; uint32_t p_cluster, num_clusters; uint16_t ext_flags; if (!ocfs2_refcount_tree(OCFS2_RAW_SB(context->fs->fs_super))) return OCFS2_ET_RO_FILESYS; while (cow_len) { ret = context->get_clusters(context, cow_start, &p_cluster, &num_clusters, &ext_flags); if (ret) break; assert(ext_flags & OCFS2_EXT_REFCOUNTED); if (cow_len < num_clusters) num_clusters = cow_len; ret = ocfs2_make_clusters_writable(context, cow_start, p_cluster, num_clusters, ext_flags); if (ret) break; cow_len -= num_clusters; cow_start += num_clusters; } return ret; } /* * Starting at cpos, try to CoW write_len clusters. Don't CoW * past max_cpos. This will stop when it runs into a hole or an * unrefcounted extent. */ static int ocfs2_refcount_cow_hunk(ocfs2_cached_inode *cinode, uint32_t cpos, uint32_t write_len, uint32_t max_cpos) { int ret; uint32_t cow_start = 0, cow_len = 0; struct ocfs2_cow_context context; assert(cinode->ci_inode->i_dyn_features & OCFS2_HAS_REFCOUNT_FL); memset(&context, 0, sizeof(struct ocfs2_cow_context)); ocfs2_init_dinode_extent_tree(&context.data_et, cinode->ci_fs, (char *)cinode->ci_inode, cinode->ci_blkno); ret = ocfs2_refcount_cal_cow_clusters(cinode->ci_fs, &context.data_et, cpos, write_len, max_cpos, &cow_start, &cow_len); if (ret) goto out; assert(cow_len > 0); context.cow_start = cow_start; context.cow_len = cow_len; context.fs = cinode->ci_fs; context.get_clusters = ocfs2_di_get_clusters; context.cow_object = cinode; ret = ocfs2_malloc_block(cinode->ci_fs->fs_io, &context.ref_root_buf); if (ret) goto out; ret = ocfs2_read_refcount_block(cinode->ci_fs, cinode->ci_inode->i_refcount_loc, context.ref_root_buf); if (ret) goto out; ret = ocfs2_replace_cow(&context); ocfs2_free(&context.ref_root_buf); out: return ret; } /* * CoW any and all clusters between cpos and cpos+write_len. * Don't CoW past max_cpos. If this returns successfully, all * clusters between cpos and cpos+write_len are safe to modify. */ errcode_t ocfs2_refcount_cow(ocfs2_cached_inode *cinode, uint32_t cpos, uint32_t write_len, uint32_t max_cpos) { int ret = 0; uint32_t p_cluster, num_clusters; uint16_t ext_flags; while (write_len) { ret = ocfs2_get_clusters(cinode, cpos, &p_cluster, &num_clusters, &ext_flags); if (ret) break; if (write_len < num_clusters) num_clusters = write_len; if (ext_flags & OCFS2_EXT_REFCOUNTED) { ret = ocfs2_refcount_cow_hunk(cinode, cpos, num_clusters, max_cpos); if (ret) break; } write_len -= num_clusters; cpos += num_clusters; } if (!ret) ret = ocfs2_write_cached_inode(cinode->ci_fs, cinode); return ret; } errcode_t ocfs2_refcount_tree_get_rec(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb, uint32_t phys_cpos, uint64_t *p_blkno, uint32_t *e_cpos, uint32_t *num_clusters) { int i; errcode_t ret = 0; char *eb_buf = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_rec *rec = NULL; struct ocfs2_extent_list *el = &rb->rf_list; uint64_t e_blkno = 0; if (el->l_tree_depth) { ret = ocfs2_tree_find_leaf(fs, el, rb->rf_blkno, (char *)rb, phys_cpos, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } } for (i = el->l_next_free_rec - 1; i >= 0; i--) { rec = &el->l_recs[i]; if (rec->e_cpos <= phys_cpos) { e_blkno = rec->e_blkno; break; } } if (!e_blkno) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } *p_blkno = rec->e_blkno; *num_clusters = rec->e_leaf_clusters; if (e_cpos) *e_cpos = rec->e_cpos; out: if (eb_buf) ocfs2_free(&eb_buf); return ret; } errcode_t ocfs2_refcount_punch_hole(ocfs2_filesys *fs, uint64_t rf_blkno, uint64_t p_start, uint32_t len) { errcode_t ret; char *root_buf = NULL, *buf = NULL; struct ocfs2_refcount_rec rec; int index; uint32_t dec_len; ret = ocfs2_malloc_block(fs->fs_io, &root_buf); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, rf_blkno, root_buf); if (ret) goto out; while (len) { ret = ocfs2_get_refcount_rec(fs, root_buf, p_start, len, &rec, &index, buf); if (!rec.r_refcount) { /* There is no refcount for p_start. */ len -= rec.r_clusters; p_start += rec.r_clusters; continue; } dec_len = (p_start + len < rec.r_cpos + rec.r_clusters) ? len : (rec.r_cpos + rec.r_clusters - p_start); ret = ocfs2_decrease_refcount_rec(fs, root_buf, buf, index, p_start, dec_len, rec.r_refcount); if (ret) goto out; len -= dec_len; p_start += dec_len; } out: if (root_buf) ocfs2_free(&root_buf); if (buf) ocfs2_free(&buf); return ret; } errcode_t ocfs2_change_refcount(ocfs2_filesys *fs, uint64_t rf_blkno, uint64_t p_start, uint32_t len, uint32_t refcount) { errcode_t ret; char *root_buf = NULL, *buf = NULL; struct ocfs2_refcount_rec rec; int index, value; ret = ocfs2_malloc_block(fs->fs_io, &root_buf); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; ret = ocfs2_read_refcount_block(fs, rf_blkno, root_buf); if (ret) goto out; ret = ocfs2_get_refcount_rec(fs, root_buf, p_start, len, &rec, &index, buf); assert(rec.r_refcount != refcount && rec.r_cpos <= p_start && rec.r_cpos + rec.r_clusters >= p_start + len); value = refcount; value -= rec.r_refcount; ret = __ocfs2_increase_refcount(fs, root_buf, p_start, len, 1, value); out: if (root_buf) ocfs2_free(&root_buf); if (buf) ocfs2_free(&buf); return ret; } struct xattr_value_obj { errcode_t errcode; uint64_t p_cpos; uint32_t v_cpos; uint32_t clusters; int new_flags; int clear_flags; }; static int change_xattr_refcount(ocfs2_cached_inode *ci, char *xe_buf, uint64_t xe_blkno, struct ocfs2_xattr_entry *xe, char *value_buf, uint64_t value_blkno, void *value, int in_bucket, void *priv_data) { uint32_t p_cluster, num_clusters; uint16_t ext_flags; struct xattr_value_obj *obj = priv_data; struct ocfs2_extent_tree et; ocfs2_root_write_func write_func = NULL; struct ocfs2_xattr_value_root *xv; if (ocfs2_xattr_is_local(xe)) return 0; xv = (struct ocfs2_xattr_value_root *)value; obj->errcode = ocfs2_xattr_get_clusters(ci->ci_fs, &xv->xr_list, value_blkno, value_buf, obj->v_cpos, &p_cluster, &num_clusters, &ext_flags); if (obj->errcode) return OCFS2_XATTR_ERROR; if (p_cluster != obj->p_cpos) return 0; assert(num_clusters >= obj->clusters); if (xe_blkno == ci->ci_inode->i_blkno) write_func = ocfs2_write_inode; else if (xe_blkno == ci->ci_inode->i_xattr_loc) write_func = ocfs2_write_xattr_block; ocfs2_init_xattr_value_extent_tree(&et, ci->ci_fs, value_buf, value_blkno, write_func, xv); obj->errcode = ocfs2_change_extent_flag(ci->ci_fs, &et, obj->v_cpos, obj->clusters, ocfs2_clusters_to_blocks(ci->ci_fs, obj->p_cpos), obj->new_flags, obj->clear_flags); if (obj->errcode) goto out; if (!write_func) { assert(in_bucket); obj->errcode = ocfs2_write_xattr_bucket(ci->ci_fs, xe_blkno, xe_buf); if (obj->errcode) goto out; } return OCFS2_XATTR_ABORT; out: return OCFS2_XATTR_ERROR; } static errcode_t ocfs2_xattr_change_ext_refcount(ocfs2_filesys *fs, ocfs2_cached_inode *ci, uint32_t v_cpos, uint32_t clusters, uint64_t p_cpos, int new_flags, int clear_flags) { int iret; errcode_t ret = 0; struct xattr_value_obj obj = { .v_cpos = v_cpos, .p_cpos = p_cpos, .clusters = clusters, .new_flags = new_flags, .clear_flags = clear_flags, }; iret = ocfs2_xattr_iterate(ci, change_xattr_refcount, &obj); if (iret & OCFS2_XATTR_ERROR) ret = obj.errcode; return ret; } /* * Clear the refcount flag for an extent rec (v_cpos, clusters) of the file. * This extent rec can be found either in dinode or xattr. */ errcode_t ocfs2_change_refcount_flag(ocfs2_filesys *fs, uint64_t i_blkno, uint32_t v_cpos, uint32_t clusters, uint64_t p_cpos, int new_flags, int clear_flags) { errcode_t ret; ocfs2_cached_inode *ci = NULL; struct ocfs2_extent_tree et; uint32_t p_cluster, num_clusters; uint16_t ext_flags; ret = ocfs2_read_cached_inode(fs, i_blkno, &ci); if (ret) goto out; ret = ocfs2_get_clusters(ci, v_cpos, &p_cluster, &num_clusters, &ext_flags); if (ret) goto out; if (p_cluster == p_cpos) { /* OK, the p_cpos is in the dinode. */ assert(num_clusters >= clusters); ocfs2_init_dinode_extent_tree(&et, fs, (char *)ci->ci_inode, i_blkno); ret = ocfs2_change_extent_flag(fs, &et, v_cpos, clusters, ocfs2_clusters_to_blocks(fs, p_cpos), new_flags, clear_flags); goto out; } ret = ocfs2_xattr_change_ext_refcount(fs, ci, v_cpos, clusters, p_cpos, new_flags, clear_flags); out: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } static errcode_t create_generation(uint32_t *value) { int randfd = 0; int readlen = sizeof(*value); randfd = open("/dev/urandom", O_RDONLY); if (randfd < 0) return errno; if (read(randfd, value, readlen) != readlen) return errno; close(randfd); return 0; } errcode_t ocfs2_create_refcount_tree(ocfs2_filesys *fs, uint64_t *refcount_loc) { errcode_t ret; uint32_t generation; ret = create_generation(&generation); if (ret) return ret; return ocfs2_new_refcount_block(fs, refcount_loc, 0, generation); } errcode_t ocfs2_attach_refcount_tree(ocfs2_filesys *fs, uint64_t ino, uint64_t refcount_loc) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; struct ocfs2_refcount_block *rb; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; /* * We add the rf_count for the tree first so that * if their is any corruption before we attaching * the tree to the inode, we can check it out * easily by RF_COUNT_INVALID. */ ret = ocfs2_read_refcount_block(fs, refcount_loc, buf); if (ret) goto out; rb = (struct ocfs2_refcount_block *)buf; rb->rf_count += 1; ret = ocfs2_write_refcount_block(fs, refcount_loc, buf); if (ret) goto out; ret = ocfs2_read_inode(fs, ino, buf); if (ret) goto out; di = (struct ocfs2_dinode *)buf; assert(!(di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)); assert(!di->i_refcount_loc); di->i_refcount_loc = refcount_loc; di->i_dyn_features |= OCFS2_HAS_REFCOUNT_FL; ret = ocfs2_write_inode(fs, ino, buf); out: ocfs2_free(&buf); return ret; } struct xattr_value_cow_object { struct ocfs2_xattr_value_root *xv; uint64_t xe_blkno; uint64_t value_blkno; char *xe_buf; char *value_buf; }; static int ocfs2_xattr_value_get_clusters(struct ocfs2_cow_context *context, uint32_t v_cluster, uint32_t *p_cluster, uint32_t *num_clusters, uint16_t *extent_flags) { struct xattr_value_cow_object *obj = context->cow_object; return ocfs2_xattr_get_clusters(context->fs, &obj->xv->xr_list, obj->value_blkno, obj->value_buf, v_cluster, p_cluster, num_clusters, extent_flags); } static errcode_t ocfs2_write_xattr_bucket_in_cow(ocfs2_filesys *fs, void *para) { struct xattr_value_cow_object *obj = para; return ocfs2_write_xattr_bucket(fs, obj->xe_blkno, obj->xe_buf); } /* * Do CoW for xattr. */ errcode_t ocfs2_refcount_cow_xattr(ocfs2_cached_inode *ci, char *xe_buf, uint64_t xe_blkno, char *value_buf, uint64_t value_blkno, struct ocfs2_xattr_value_root *xv, uint32_t cpos, uint32_t write_len) { int ret; uint32_t cow_start, cow_len; struct ocfs2_cow_context context; struct ocfs2_post_refcount post_refcount; ocfs2_root_write_func write_func = NULL; struct xattr_value_cow_object value_obj; assert(ci->ci_inode->i_dyn_features & OCFS2_HAS_REFCOUNT_FL); memset(&context, 0, sizeof(struct ocfs2_cow_context)); value_obj.xv = xv; value_obj.xe_blkno = xe_blkno; value_obj.value_blkno = value_blkno; value_obj.xe_buf = xe_buf; value_obj.value_buf = value_buf; /* * Set the corresponding root write function. * If we are in the bucket, write the whole bucket by ourselves. */ if (xe_blkno == ci->ci_inode->i_blkno) write_func = ocfs2_write_inode; else if (xe_blkno == ci->ci_inode->i_xattr_loc) write_func = ocfs2_write_xattr_block; else { /* * We are in a bucket and we can't write the extent tree * root by ourself. Set post_refcount so that the whole * bucket can be written after the CoW succeeds. */ post_refcount.para = &value_obj; post_refcount.func = ocfs2_write_xattr_bucket_in_cow; context.post_refcount = &post_refcount; } ocfs2_init_xattr_value_extent_tree(&context.data_et, ci->ci_fs, value_buf, value_blkno, write_func, xv); ret = ocfs2_refcount_cal_cow_clusters(ci->ci_fs, &context.data_et, cpos, write_len, UINT_MAX, &cow_start, &cow_len); if (ret) goto out; assert(cow_len > 0); context.cow_start = cow_start; context.cow_len = cow_len; context.fs = ci->ci_fs; context.get_clusters = ocfs2_xattr_value_get_clusters; context.cow_object = &value_obj; ret = ocfs2_malloc_block(ci->ci_fs->fs_io, &context.ref_root_buf); if (ret) goto out; ret = ocfs2_read_refcount_block(ci->ci_fs, ci->ci_inode->i_refcount_loc, context.ref_root_buf); if (ret) goto out; ret = ocfs2_replace_cow(&context); if (ret) goto out; if (!write_func) ret = ocfs2_write_xattr_bucket(ci->ci_fs, xe_blkno, xe_buf); out: if (&context.ref_root_buf) ocfs2_free(&context.ref_root_buf); return ret; } ./ocfs2-tools-1.6.4/libocfs2/dir_indexed.c0000644000176100017610000010515211515637015015113 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2009, 2010 Novell. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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. */ #include #include #include #include #include "ocfs2_err.h" #include "extent_tree.h" errcode_t ocfs2_dx_dir_truncate(ocfs2_filesys *fs, uint64_t dir) { struct ocfs2_dx_root_block *dx_root; char *dx_root_buf = NULL, *di_buf = NULL; struct ocfs2_dinode *di; uint64_t dx_root_blk; errcode_t ret = 0; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; /* we have to trust i_dyn_features */ if (!S_ISDIR(di->i_mode) || !ocfs2_dir_indexed(di) || di->i_dyn_features & OCFS2_INLINE_DATA_FL) goto out; dx_root_blk = di->i_dx_root; di->i_dyn_features &= ~OCFS2_INDEXED_DIR_FL; di->i_dx_root = 0; /* update inode firstly */ ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (ret) goto out; /* inode is updated, the rested errors are not fatal */ ret = ocfs2_malloc_block(fs->fs_io, &dx_root_buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, dx_root_blk, dx_root_buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)dx_root_buf; if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) goto remove_index; ret = ocfs2_dir_indexed_tree_truncate(fs, dx_root); /* * even ocfs2_dir_indexed_tree_truncate() failed, * we still want to call ocfs2_delete_dx_root(). */ remove_index: ret = ocfs2_delete_dx_root(fs, dx_root->dr_blkno); out: if (di_buf) ocfs2_free(&di_buf); if (dx_root_buf) ocfs2_free(&dx_root_buf); return ret; } static unsigned int ocfs2_figure_dirent_hole(struct ocfs2_dir_entry *de) { unsigned int hole; if (de->inode == 0) hole = de->rec_len; else hole = de->rec_len - OCFS2_DIR_REC_LEN(de->name_len); return hole; } int ocfs2_find_max_rec_len(ocfs2_filesys *fs, char *buf) { int size, this_hole, largest_hole = 0; char *de_buf, *limit; struct ocfs2_dir_entry *de; size = ocfs2_dir_trailer_blk_off(fs); limit = buf + size; de_buf = buf; de = (struct ocfs2_dir_entry *)de_buf; do { this_hole = ocfs2_figure_dirent_hole(de); if (this_hole > largest_hole) largest_hole = this_hole; de_buf += de->rec_len; de = (struct ocfs2_dir_entry *)de_buf; } while (de_buf < limit); if (largest_hole >= OCFS2_DIR_MIN_REC_LEN) return largest_hole; return 0; } struct trailer_ctxt { struct ocfs2_dx_root_block *dx_root; struct ocfs2_dinode *di; errcode_t err; }; /* make sure the space for trailer is reserved */ static errcode_t ocfs2_check_dir_trailer_space(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t blkno, char *blk) { errcode_t ret = 0; struct ocfs2_dir_entry *dirent; unsigned int offset = 0; unsigned int toff = ocfs2_dir_trailer_blk_off(fs); unsigned int real_rec_len = 0; while(offset < fs->fs_blocksize) { dirent = (struct ocfs2_dir_entry *)(blk + offset); if (!ocfs2_check_dir_entry(fs, dirent, blk, offset)) { ret = OCFS2_ET_DIR_CORRUPTED; break; } real_rec_len = dirent->inode ? OCFS2_DIR_REC_LEN(dirent->name_len) : OCFS2_DIR_REC_LEN(1); if ((offset + real_rec_len) <= toff) goto next; if (dirent->inode) { ret = OCFS2_ET_DIR_NO_SPACE; break; } next: offset += dirent->rec_len; } return ret; } static int dir_trailer_func(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data) { struct trailer_ctxt *ctxt = (struct trailer_ctxt *)priv_data; struct ocfs2_dinode *di = ctxt->di; struct ocfs2_dx_root_block *dx_root = ctxt->dx_root; struct ocfs2_dir_block_trailer *trailer; int max_rec_len = 0, ret = 0; errcode_t err; char *blk = NULL; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) goto out; /* here we don't trust trailer, cannot use * ocfs2_read_dir_block() */ err = ocfs2_read_blocks(fs, blkno, 1, blk); if (err) { ctxt->err = err; ret = OCFS2_EXTENT_ERROR; goto out; } err = ocfs2_check_dir_trailer_space(fs, di, blkno, blk); if (err) { ctxt->err = err; ret = OCFS2_EXTENT_ERROR; goto out; } ocfs2_init_dir_trailer(fs, di, blkno, blk); max_rec_len = ocfs2_find_max_rec_len(fs, blk); trailer = ocfs2_dir_trailer_from_block(fs, blk); trailer->db_free_rec_len = max_rec_len; if (max_rec_len) { trailer->db_free_next = dx_root->dr_free_blk; dx_root->dr_free_blk = blkno; } /* comput trailer->db_check here, after writes out, * trailer is trustable */ err = ocfs2_write_dir_block(fs, di, blkno, blk); if (err) { ctxt->err = err; ret = OCFS2_EXTENT_ERROR; } out: if (blk) ocfs2_free(&blk); return ret; } static errcode_t ocfs2_init_dir_trailers(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct ocfs2_dx_root_block *dx_root) { errcode_t ret = 0; struct trailer_ctxt ctxt; if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { ret = OCFS2_ET_INODE_NOT_VALID; goto out; } ctxt.di = di; ctxt.dx_root = dx_root; ctxt.err = 0; ret = ocfs2_block_iterate_inode(fs, di, 0, dir_trailer_func, &ctxt); /* callback dir_trailer_func() may have error which can not * return to its caller directly. If dir_trailer_func() sets * error in ctxt.err, we should take this REAL error other * than the value returned by ocfs2_block_iterate_inode(). */ if (ctxt.err) ret = ctxt.err; out: return ret; } static void ocfs2_dx_entry_list_insert(struct ocfs2_dx_entry_list *entry_list, struct ocfs2_dx_hinfo *hinfo, uint64_t dirent_blk) { int i; struct ocfs2_dx_entry *dx_entry; i = entry_list->de_num_used; dx_entry = &entry_list->de_entries[i]; memset(dx_entry, 0, sizeof(struct ocfs2_dx_entry)); dx_entry->dx_major_hash = hinfo->major_hash; dx_entry->dx_minor_hash = hinfo->minor_hash; dx_entry->dx_dirent_blk = dirent_blk; entry_list->de_num_used += 1; } struct dx_insert_ctxt { uint64_t dir_blkno; uint64_t dx_root_blkno; ocfs2_filesys *fs; errcode_t err; }; inline static int ocfs2_inline_dx_has_space(struct ocfs2_dx_root_block *dx_root) { struct ocfs2_dx_entry_list *entry_list; entry_list = &dx_root->dr_entries; if (entry_list->de_num_used >= entry_list->de_count) return 0; return 1; } static struct ocfs2_dx_leaf **ocfs2_dx_dir_alloc_leaves(ocfs2_filesys *fs, int *ret_num_leaves) { errcode_t num_dx_leaves = ocfs2_clusters_to_blocks(fs, 1); char **dx_leaves_buf = NULL; dx_leaves_buf = calloc(num_dx_leaves, sizeof (void *)); if (dx_leaves_buf && ret_num_leaves) *ret_num_leaves = num_dx_leaves; return (struct ocfs2_dx_leaf **)dx_leaves_buf; } static errcode_t ocfs2_dx_dir_format_cluster(ocfs2_filesys *fs, struct ocfs2_dx_leaf **dx_leaves, int num_dx_leaves, uint64_t start_blk) { errcode_t ret; int i; struct ocfs2_dx_leaf *dx_leaf; char *blk; for (i = 0; i < num_dx_leaves; i++) { ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) goto out; dx_leaves[i] = (struct ocfs2_dx_leaf *)blk; dx_leaf = (struct ocfs2_dx_leaf *)blk; memset(dx_leaf, 0, fs->fs_blocksize); strcpy((char *)dx_leaf->dl_signature, OCFS2_DX_LEAF_SIGNATURE); dx_leaf->dl_fs_generation = fs->fs_super->i_fs_generation; dx_leaf->dl_blkno = start_blk + i; dx_leaf->dl_list.de_count = ocfs2_dx_entries_per_leaf(fs->fs_blocksize); ret = ocfs2_write_dx_leaf(fs, dx_leaf->dl_blkno, dx_leaf); if (ret) goto out; } ret = 0; out: return ret; } static inline unsigned int __ocfs2_dx_dir_hash_idx(ocfs2_filesys *fs, uint32_t minor_hash) { unsigned int cbits, bbits, dx_mask; cbits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; bbits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; dx_mask = (1 << (cbits - bbits)) -1; return (minor_hash & dx_mask); } static inline unsigned int ocfs2_dx_dir_hash_idx(ocfs2_filesys *fs, struct ocfs2_dx_hinfo *hinfo) { return __ocfs2_dx_dir_hash_idx(fs, hinfo->minor_hash); } static void ocfs2_dx_dir_leaf_insert_tail(struct ocfs2_dx_leaf *dx_leaf, struct ocfs2_dx_entry *dx_new_entry) { int i; i = dx_leaf->dl_list.de_num_used; dx_leaf->dl_list.de_entries[i] = *dx_new_entry; dx_leaf->dl_list.de_num_used += 1; } static errcode_t ocfs2_expand_inline_dx_root(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root) { errcode_t ret; int num_dx_leaves, i, j; uint64_t start_blkno = 0; uint32_t clusters_found = 0; struct ocfs2_dx_leaf **dx_leaves = NULL; struct ocfs2_dx_leaf *target_leaf; struct ocfs2_dx_entry_list *entry_list; struct ocfs2_extent_tree et; struct ocfs2_dx_entry *dx_entry; dx_leaves = ocfs2_dx_dir_alloc_leaves(fs, &num_dx_leaves); if (!dx_leaves) { ret = OCFS2_ET_NO_MEMORY; goto out; } ret = ocfs2_new_clusters(fs, 1, 1, &start_blkno, &clusters_found); if (ret) goto out; assert(clusters_found == 1); ret = ocfs2_dx_dir_format_cluster(fs, dx_leaves, num_dx_leaves, start_blkno); if (ret) goto out; /* * Transfer the entries from inline dx_root into the appropriate * block */ entry_list = &dx_root->dr_entries; for (i = 0; i < entry_list->de_num_used; i++) { dx_entry = &entry_list->de_entries[i]; j = __ocfs2_dx_dir_hash_idx(fs, dx_entry->dx_minor_hash); target_leaf = (struct ocfs2_dx_leaf *)dx_leaves[j]; ocfs2_dx_dir_leaf_insert_tail(target_leaf, dx_entry); } /* * Write out all leaves. * If ocfs2_write_dx_leaf() failed, since dx_root is not cleared * yet, and the leaves are not inserted into indexed tree yet, * this cluster will be recoganized as orphan in blocks scan of * fsck.ocfs2 */ for (i = 0; i < num_dx_leaves; i ++) { target_leaf = (struct ocfs2_dx_leaf *)dx_leaves[i]; ret = ocfs2_write_dx_leaf(fs, target_leaf->dl_blkno, target_leaf); if (ret) goto out; } dx_root->dr_flags &= ~OCFS2_DX_FLAG_INLINE; memset(&dx_root->dr_list, 0, fs->fs_blocksize - offsetof(struct ocfs2_dx_root_block, dr_list)); dx_root->dr_list.l_count = ocfs2_extent_recs_per_dx_root(fs->fs_blocksize); /* This should never fail considering we start with an empty * dx_root */ ocfs2_init_dx_root_extent_tree(&et, fs, (char *)dx_root, dx_root->dr_blkno); ret = ocfs2_tree_insert_extent(fs, &et, 0, start_blkno, 1, 0); if (ret) goto out; out: return ret; } static errcode_t ocfs2_dx_dir_lookup_rec(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, struct ocfs2_extent_list *el, uint32_t major_hash, uint32_t *ret_cpos, uint64_t *ret_phys_blkno, unsigned int *ret_clen) { errcode_t ret = 0; int i, found; struct ocfs2_extent_block *eb; struct ocfs2_extent_rec *rec = NULL; char *eb_buf = NULL; if (el->l_tree_depth) { ret = ocfs2_tree_find_leaf(fs, &dx_root->dr_list, dx_root->dr_blkno, (char *)dx_root, major_hash, &eb_buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)eb_buf; el = &eb->h_list; if (el->l_tree_depth) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } found = 0; for (i = el->l_next_free_rec - 1; i >= 0; i--) { rec = &el->l_recs[i]; if (rec->e_cpos <= major_hash) { found = 1; break; } } if (!found) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } if (ret_phys_blkno) *ret_phys_blkno = rec->e_blkno; if (ret_cpos) *ret_cpos = rec->e_cpos; if (ret_clen) *ret_clen = rec->e_leaf_clusters; out: if (eb_buf) ocfs2_free(&eb_buf); return ret; } errcode_t ocfs2_dx_dir_lookup(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, struct ocfs2_extent_list *el, struct ocfs2_dx_hinfo *hinfo, uint32_t *ret_cpos, uint64_t *ret_phys_blkno) { errcode_t ret = 0; unsigned int cend = 0, clen = 0; uint32_t cpos = 0; uint64_t blkno = 0; uint32_t name_hash = hinfo->major_hash; ret = ocfs2_dx_dir_lookup_rec(fs, dx_root, el, name_hash, &cpos, &blkno, &clen); if (ret) goto out; cend = cpos + clen; if (name_hash >= cend) { blkno += ocfs2_clusters_to_blocks(fs, clen - 1); cpos += clen - 1; } else { blkno += ocfs2_clusters_to_blocks(fs, name_hash - cpos); cpos = name_hash; } blkno += ocfs2_dx_dir_hash_idx(fs, hinfo); if (ret_phys_blkno) *ret_phys_blkno = blkno; if (ret_cpos) *ret_cpos = cpos; out: return ret; } static int dx_leaf_sort_cmp(const void *a, const void *b) { const struct ocfs2_dx_entry *e1 = a; const struct ocfs2_dx_entry *e2 = b; uint32_t major_hash1 = e1->dx_major_hash; uint32_t major_hash2 = e2->dx_major_hash; uint32_t minor_hash1 = e1->dx_minor_hash; uint32_t minor_hash2 = e2->dx_minor_hash; if (major_hash1 > major_hash2) return 1; if (major_hash1 < major_hash2) return -1; /* it is not strictly necessary to sort by minor */ if (minor_hash1 > minor_hash2) return 1; if (minor_hash1 < minor_hash2) return -1; return 0; } static void dx_leaf_sort_swap(void *a, void *b, int size) { struct ocfs2_dx_entry *e1 = a; struct ocfs2_dx_entry *e2 = b; struct ocfs2_dx_entry tmp; assert(size == sizeof (struct ocfs2_dx_entry)); tmp = *e1; *e1 = *e2; *e2 = tmp; } static int ocfs2_dx_leaf_same_major(struct ocfs2_dx_leaf *dx_leaf) { struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list; int i, num = dl_list->de_num_used; for (i = 0; i < (num - 1); i++) { if (dl_list->de_entries[i].dx_major_hash != dl_list->de_entries[i + 1].dx_major_hash) return 0; } return 1; } /* * Find the optimal value to split this leaf on. This expects the leaf * entries to be in sorted order. * * leaf_cpos is the cpos of the leaf we're splitting. insert_hash is * the hash we want to insert. * * This function is only concerned with the major hash - that which * determines which cluster an item belongs to. */ static int ocfs2_dx_dir_find_leaf_split(struct ocfs2_dx_leaf *dx_leaf, uint32_t leaf_cpos, uint32_t insert_hash, uint32_t *split_hash) { struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list; int i, num_used = dl_list->de_num_used; int allsame; /* * There's a couple rare, but nasty corner cases we have to * check for here. All of them involve a leaf where all value * have the same hash, which is what we look for first. * * Most of the time, all of the above is false, and we simply * pick the median value for a split. */ allsame = ocfs2_dx_leaf_same_major(dx_leaf); if (allsame) { uint32_t val = dl_list->de_entries[0].dx_major_hash; if (val == insert_hash) { /* * No matter where we would choose to split, * the new entry would want to occupy the same * block as these. Since there's no space left * in their existing block, we know there * won't be space after the split. */ return OCFS2_ET_DIR_NO_SPACE; } if (val == leaf_cpos) { /* * Because val is the same as leaf_cpos (which * is the smallest value this leaf can have), * yet is not equal to insert_hash, then we * know that insert_hash *must* be larger than * val (and leaf_cpos). At least cpos+1 in value. * * We also know then, that there cannot be an * adjacent extent (otherwise we'd be looking * at it). Choosing this value gives us a * chance to get some continguousness. */ *split_hash = leaf_cpos + 1; return 0; } if (val > insert_hash) { /* * val can not be the same as insert_hash, and * also must be larger than leaf_cpos. Also, * we know that there can't be a leaf between * cpos and val, otherwise the entries with * hash 'val' would be there. */ *split_hash = val; return 0; } *split_hash = insert_hash; return 0; } /* * Since the records are sorted and the checks above * guaranteed that not all records in this block are the same, * we simple travel forward, from the median, and pick the 1st * record whose value is larger than leaf_cpos. */ for (i = (num_used /2); i < num_used; i++) { if (dl_list->de_entries[i].dx_major_hash > leaf_cpos) break; } assert(i < num_used); /* Should be impossible */ *split_hash = dl_list->de_entries[i].dx_major_hash; return 0; } static errcode_t ocfs2_read_dx_leaves(ocfs2_filesys *fs, uint64_t start, int num, struct ocfs2_dx_leaf **dx_leaves) { errcode_t ret; int i; struct ocfs2_dx_leaf *dx_leaf; for (i = 0; i < num; i++) { assert(!dx_leaves[i]); ret = ocfs2_malloc_block(fs->fs_io, (char **)&dx_leaf); if (ret) goto bail; ret = ocfs2_read_dx_leaf(fs, start + i, (char *)dx_leaf); if (ret) goto bail; dx_leaves[i] = dx_leaf; } goto out; bail: for (; i >= 0; i--) { if (dx_leaves[i]) ocfs2_free(&dx_leaves[i]); } out: return ret; } static errcode_t __ocfs2_dx_dir_new_cluster(ocfs2_filesys *fs, uint32_t cpos, struct ocfs2_dx_leaf **dx_leaves, int num_dx_leaves, uint64_t *ret_phys_blkno) { errcode_t ret; uint32_t num; uint64_t phys; ret = ocfs2_new_clusters(fs, 1, 1, &phys, &num); if (ret) goto out; assert(num == 1); ret = ocfs2_dx_dir_format_cluster(fs, dx_leaves, num_dx_leaves, phys); if (ret) goto out; *ret_phys_blkno = phys; out: return ret; } static errcode_t ocfs2_dx_dir_new_cluster(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint64_t *phys_blocknr, struct ocfs2_dx_leaf **dx_leaves, int num_dx_leaves) { errcode_t ret; uint64_t blkno; ret = __ocfs2_dx_dir_new_cluster(fs, cpos, dx_leaves, num_dx_leaves, &blkno); if (ret) goto out; *phys_blocknr = blkno; ret = ocfs2_tree_insert_extent(fs, et, cpos, blkno, 1, 0); out: return ret; } static errcode_t ocfs2_dx_dir_transfer_leaf(ocfs2_filesys *fs, uint32_t split_hash, struct ocfs2_dx_leaf *tmp_dx_leaf, struct ocfs2_dx_leaf **orig_dx_leaves, uint64_t orig_dx_leaves_blkno, struct ocfs2_dx_leaf **new_dx_leaves, uint64_t new_dx_leaves_blkno, int num_dx_leaves) { errcode_t ret; int i, j, num_used; uint32_t major_hash; struct ocfs2_dx_leaf *orig_dx_leaf, *new_dx_leaf; struct ocfs2_dx_entry_list *orig_list, *new_list, *tmp_list; struct ocfs2_dx_entry *dx_entry; tmp_list = &tmp_dx_leaf->dl_list; for (i = 0; i < num_dx_leaves; i++) { orig_dx_leaf = orig_dx_leaves[i]; orig_list = &orig_dx_leaf->dl_list; new_dx_leaf = new_dx_leaves[i]; new_list = &new_dx_leaf->dl_list; num_used = orig_list->de_num_used; memcpy(tmp_dx_leaf, orig_dx_leaf, fs->fs_blocksize); tmp_list->de_num_used = 0; memset(&tmp_list->de_entries, 0, sizeof(struct ocfs2_dx_entry) * num_used); for (j = 0; j < num_used; j++) { dx_entry = &orig_list->de_entries[j]; major_hash = dx_entry->dx_major_hash; if (major_hash >= split_hash) ocfs2_dx_dir_leaf_insert_tail(new_dx_leaf, dx_entry); else ocfs2_dx_dir_leaf_insert_tail(tmp_dx_leaf, dx_entry); } memcpy(orig_dx_leaf, tmp_dx_leaf, fs->fs_blocksize); ret = ocfs2_write_dx_leaf(fs, orig_dx_leaves_blkno + i, (char *)orig_dx_leaf); if (ret) goto out; ret = ocfs2_write_dx_leaf(fs, new_dx_leaves_blkno + i, (char *)new_dx_leaf); if (ret) goto out; } out: return ret; } static int ocfs2_dx_dir_free_leaves(ocfs2_filesys *fs, struct ocfs2_dx_leaf **dx_leaves) { int i, num; num = ocfs2_clusters_to_blocks(fs, 1); for (i = 0; i < num; i++) { if (dx_leaves[i]) ocfs2_free(&dx_leaves[i]); } free(dx_leaves); return 0; } /* from Linux kernel lib/sort.c */ static void ocfs2_sort(void *base, size_t num, size_t size, int (*cmp_func)(const void *, const void *), void (*swap_func)(void *, void *, int size)) { /* pre-scale counters for performance */ int i = (num/2 - 1) * size, n = num * size, c, r; /* heapify */ for (; i >= 0; i -= size) { for (r = i; r * 2 + size < n; r = c) { c = r * 2 + size; if (c < n - size && cmp_func(base + c, base + c + size) < 0) c += size; if (cmp_func(base + r, base + c) >= 0) break; swap_func(base + r, base + c, size); } } /* sort */ for (i = n - size; i > 0; i -= size) { swap_func(base, base + i, size); for (r = 0; r * 2 + size < i; r = c) { c = r * 2 + size; if (c < i - size && cmp_func(base + c, base + c + size) < 0) c += size; if (cmp_func(base + r, base + c) >= 0) break; swap_func(base + r, base + c, size); } } } static errcode_t ocfs2_dx_dir_rebalance(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, struct ocfs2_dx_leaf *dx_leaf, struct ocfs2_dx_hinfo *hinfo, uint32_t leaf_cpos, uint64_t leaf_blkno) { struct ocfs2_extent_tree et; struct ocfs2_dx_leaf **orig_dx_leaves = NULL; struct ocfs2_dx_leaf **new_dx_leaves = NULL; struct ocfs2_dx_leaf *tmp_dx_leaf = NULL; uint32_t insert_hash = hinfo->major_hash; uint32_t split_hash, cpos; uint64_t orig_leaves_start, new_leaves_start; errcode_t ret; int num_used, num_dx_leaves; ocfs2_init_dx_root_extent_tree(&et, fs, (char *)dx_root, dx_root->dr_blkno); if (dx_root->dr_clusters == UINT_MAX) { ret = OCFS2_ET_DIR_NO_SPACE; goto out; } num_used = dx_leaf->dl_list.de_num_used; if (num_used < dx_leaf->dl_list.de_count) { ret = OCFS2_ET_DX_BALANCE_EMPTY_LEAF; goto out; } orig_dx_leaves = ocfs2_dx_dir_alloc_leaves(fs, &num_dx_leaves); if (!orig_dx_leaves) { ret = OCFS2_ET_NO_MEMORY; goto out; } new_dx_leaves = ocfs2_dx_dir_alloc_leaves(fs, NULL); if (!new_dx_leaves) { ret = OCFS2_ET_NO_MEMORY; goto out; } ocfs2_sort(dx_leaf->dl_list.de_entries, num_used, sizeof(struct ocfs2_dx_entry), dx_leaf_sort_cmp, dx_leaf_sort_swap); ret = ocfs2_dx_dir_find_leaf_split(dx_leaf, leaf_cpos, insert_hash, &split_hash); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, (char **)(&tmp_dx_leaf)); if (ret) goto out; orig_leaves_start = ocfs2_block_to_cluster_start(fs, leaf_blkno); ret = ocfs2_read_dx_leaves(fs, orig_leaves_start, num_dx_leaves, orig_dx_leaves); if (ret) goto out; cpos = split_hash; ret = ocfs2_dx_dir_new_cluster(fs, &et, cpos, &new_leaves_start, new_dx_leaves, num_dx_leaves); if (ret) goto out; ret = ocfs2_dx_dir_transfer_leaf(fs, split_hash, tmp_dx_leaf, orig_dx_leaves, orig_leaves_start, new_dx_leaves, new_leaves_start, num_dx_leaves); out: if (tmp_dx_leaf) ocfs2_free((char **)(&tmp_dx_leaf)); if (orig_dx_leaves) ocfs2_dx_dir_free_leaves(fs, orig_dx_leaves); if (new_dx_leaves) ocfs2_dx_dir_free_leaves(fs, new_dx_leaves); return ret; } static errcode_t ocfs2_find_dir_space_dx(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, const char *name, int namelen, struct ocfs2_dir_lookup_result *lookup) { errcode_t ret; int rebalanced = 0; struct ocfs2_dx_leaf *dx_leaf; char *dx_leaf_buf = NULL; uint64_t blkno; uint32_t leaf_cpos; ret = ocfs2_malloc_block(fs->fs_io, &dx_leaf_buf); if (ret) goto out; restart_search: ret = ocfs2_dx_dir_lookup(fs, dx_root, &dx_root->dr_list, &lookup->dl_hinfo, &leaf_cpos, &blkno); if (ret) goto out; ret = ocfs2_read_dx_leaf(fs, blkno, dx_leaf_buf); if (ret) goto out; dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_buf; if (dx_leaf->dl_list.de_num_used >= dx_leaf->dl_list.de_count) { if (rebalanced) { /* * Rebalancing should have provided us with * space in an appropriate leaf. */ ret = OCFS2_ET_DIR_NO_SPACE; goto out; } ret = ocfs2_dx_dir_rebalance(fs, dx_root, dx_leaf, &lookup->dl_hinfo, leaf_cpos, blkno); if (ret) goto out; rebalanced = 1; goto restart_search; } lookup->dl_dx_leaf_blkno = blkno; out: if (dx_leaf_buf) ocfs2_free(&dx_leaf_buf); return ret; } /* * Hashing code adapted from ext3 */ #define DELTA 0x9E3779B9 static void TEA_transform(uint32_t buf[4], uint32_t const in[]) { uint32_t sum = 0; uint32_t b0 = buf[0], b1 = buf[1]; uint32_t a = in[0], b = in[1], c = in[2], d = in[3]; int n = 16; do { sum += DELTA; b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); } while (--n); buf[0] += b0; buf[1] += b1; } static void str2hashbuf(const char *msg, int len, uint32_t *buf, int num) { uint32_t pad, val; int i; pad = (uint32_t)len | ((uint32_t)len << 8); pad |= pad << 16; val = pad; if (len > (num * 4)) len = num * 4; for (i = 0; i < len; i++) { if ((i % 4) == 0) val = pad; val = msg[i] + (val << 8); if ((i % 4) == 3) { *buf++ = val; val = pad; num --; } } if (--num >= 0) *buf++ = val; while(--num >= 0) *buf++ = pad; } void ocfs2_dx_dir_name_hash(ocfs2_filesys *fs, const char *name, int len, struct ocfs2_dx_hinfo *hinfo) { const char *p; uint32_t in[8], buf[4]; /* * XXX: Is this really necessary, if the index is never looked * at by readdir? Is a hash value of '0' a bad idea ? */ if ((len == 1 && !strncmp(".", name, 1)) || (len == 2 && !strncmp("..", name, 2))) { buf[0] = buf[1] = 0; goto out; } memcpy(buf, OCFS2_RAW_SB(fs->fs_super)->s_dx_seed, sizeof(buf)); p = name; while(len > 0) { str2hashbuf(p, len, in, 4); TEA_transform(buf, in); len -= 16; p += 16; } out: hinfo->major_hash = buf[0]; hinfo->minor_hash = buf[1]; } static int ocfs2_dx_dir_insert(struct ocfs2_dir_entry *dentry, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { int ret = 0; errcode_t err; char *dx_buf = NULL; char *dx_leaf_buf = NULL; struct ocfs2_dx_root_block *dx_root = NULL; struct ocfs2_dx_leaf *dx_leaf = NULL; struct ocfs2_dir_lookup_result lookup; struct ocfs2_dx_entry_list *entry_list; struct dx_insert_ctxt *ctxt = (struct dx_insert_ctxt *)priv_data; ocfs2_filesys *fs = ctxt->fs; uint64_t dx_root_blkno = ctxt->dx_root_blkno; int write_dx_leaf = 0; err = ocfs2_malloc_block(fs->fs_io, &dx_buf); if (err) goto set_err; err = ocfs2_malloc_block(fs->fs_io, &dx_leaf_buf); if (err) goto set_err; err = ocfs2_read_dx_root(fs, dx_root_blkno, dx_buf); if (err) goto set_err; dx_root = (struct ocfs2_dx_root_block *)dx_buf; memset(&lookup, 0, sizeof(struct ocfs2_dir_lookup_result)); ocfs2_dx_dir_name_hash(fs, dentry->name, dentry->name_len, &lookup.dl_hinfo); if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) { if (ocfs2_inline_dx_has_space(dx_root)) { entry_list = &dx_root->dr_entries; goto insert_into_entries; } else { /* root block is full, expand it to an extent */ err = ocfs2_expand_inline_dx_root(fs, dx_root); if (err) goto set_err; } } err = ocfs2_find_dir_space_dx(fs, dx_root, dentry->name, dentry->name_len, &lookup); if (err) goto set_err; err = ocfs2_read_dx_leaf(fs, lookup.dl_dx_leaf_blkno, dx_leaf_buf); if (err) goto set_err; dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_buf; entry_list = &dx_leaf->dl_list; write_dx_leaf = 1; insert_into_entries: ocfs2_dx_entry_list_insert(entry_list, &lookup.dl_hinfo, blocknr); if (write_dx_leaf) { err = ocfs2_write_dx_leaf(fs, dx_leaf->dl_blkno, dx_leaf); if (err) goto set_err; } dx_root->dr_num_entries += 1; err = ocfs2_write_dx_root(fs, dx_root_blkno, dx_buf); if (!err) goto out; set_err: ctxt->err = err; ret = OCFS2_DIRENT_ABORT; out: if (dx_leaf_buf) ocfs2_free(&dx_leaf_buf); if (dx_buf) ocfs2_free(&dx_buf); return ret; } errcode_t ocfs2_dx_dir_insert_entry(ocfs2_filesys *fs, uint64_t dir, const char *name, uint64_t ino, uint64_t blkno) { struct ocfs2_dir_entry dummy_de; struct dx_insert_ctxt dummy_ctxt; char *di_buf = NULL; struct ocfs2_dinode *di; errcode_t ret = 0; if (!ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super))) goto out; assert(name); memset(&dummy_de, 0, sizeof(struct ocfs2_dir_entry)); memcpy(dummy_de.name, name, strlen(name)); dummy_de.name_len = strlen(name); ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; if (!(di->i_dyn_features & OCFS2_INDEXED_DIR_FL)) goto out; memset(&dummy_ctxt, 0, sizeof(struct dx_insert_ctxt)); dummy_ctxt.dir_blkno = dir; dummy_ctxt.fs = fs; dummy_ctxt.dx_root_blkno = di->i_dx_root; ret = ocfs2_dx_dir_insert(&dummy_de, blkno, 0, fs->fs_blocksize, NULL, &dummy_ctxt); if (ret) ret = dummy_ctxt.err; out: if (di_buf) ocfs2_free(&di_buf); return ret; } /* * This function overwite the indexed dir attribute of * the given inode. The caller should make sure the dir's * indexed tree is truncated. * Currently tunefs.ocfs2 is the only user, before calling * this function, tunefs.ocfs2 makes sure there is space * for directory trailer. So directory entry moves here. */ errcode_t ocfs2_dx_dir_build(ocfs2_filesys *fs, uint64_t dir) { errcode_t ret = 0, err; uint64_t dr_blkno; char *dx_buf = NULL, *di_buf = NULL; struct ocfs2_dinode *di; struct ocfs2_dx_root_block *dx_root; struct dx_insert_ctxt ctxt; ocfs2_quota_hash *usrhash = NULL, *grphash = NULL; uint32_t uid, gid; long long change; ret = ocfs2_load_fs_quota_info(fs); if (ret) goto out; ret = ocfs2_init_quota_change(fs, &usrhash, &grphash); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; if ((ocfs2_dir_indexed(di)) || (di->i_dyn_features & OCFS2_INLINE_DATA_FL)) goto out; ret = ocfs2_new_dx_root(fs, di, &dr_blkno); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &dx_buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, dr_blkno, dx_buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)dx_buf; ret = ocfs2_init_dir_trailers(fs, di, dx_root); if (ret) goto out; dx_root->dr_dir_blkno = di->i_blkno; dx_root->dr_num_entries = 0; dx_root->dr_entries.de_count = ocfs2_dx_entries_per_root(fs->fs_blocksize); di->i_dx_root = dr_blkno; ret = ocfs2_write_dx_root(fs, dr_blkno, dx_buf); if (ret) goto out; ret = ocfs2_write_inode(fs, dir, di_buf); if (ret) goto out; ctxt.dir_blkno = dir; ctxt.dx_root_blkno = dr_blkno; ctxt.fs = fs; ctxt.err = 0; ret = ocfs2_dir_iterate(fs, dir, 0, NULL, ocfs2_dx_dir_insert, &ctxt); if (ctxt.err) ret = ctxt.err; if (ret) goto out; ret = ocfs2_read_dx_root(fs, dr_blkno, dx_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, dir, di_buf); if (ret) goto out; /* set inode to use indexed-dirs */ di->i_dyn_features |= OCFS2_INDEXED_DIR_FL; ret = ocfs2_write_inode(fs, dir, di_buf); if(ret) goto out; /* check quota for dx_leaf */ change = ocfs2_clusters_to_bytes(fs, dx_root->dr_clusters); uid = di->i_uid; gid = di->i_gid; ret = ocfs2_apply_quota_change(fs, usrhash, grphash, uid, gid, change, 0); if (ret) { /* exceed quota, truncate the indexed tree */ ret = ocfs2_dx_dir_truncate(fs, dir); } out: err = ocfs2_finish_quota_change(fs, usrhash, grphash); if (!ret) ret = err; if (di_buf) ocfs2_free(&di_buf); if (dx_buf) ocfs2_free(&dx_buf); return ret; } void ocfs2_dx_list_remove_entry(struct ocfs2_dx_entry_list *entry_list, int index) { int num_used = entry_list->de_num_used; if (num_used == 1 || index == (num_used - 1)) goto clear; memmove(&entry_list->de_entries[index], &entry_list->de_entries[index + 1], (num_used - index - 1)*sizeof(struct ocfs2_dx_entry)); clear: num_used --; memset(&entry_list->de_entries[num_used], 0, sizeof(struct ocfs2_dx_entry)); entry_list->de_num_used = num_used; } static int ocfs2_match(int len, const char *name, struct ocfs2_dir_entry *de) { if (len != de->name_len) return 0; if (!de->inode) return 0; return !memcmp((char *)name, de->name, len); } int ocfs2_check_dir_entry(ocfs2_filesys *fs, struct ocfs2_dir_entry *de, char *dir_buf, unsigned int offset) { int rlen = de->rec_len; int ret = 1; if ((rlen < OCFS2_DIR_REC_LEN(1)) || (rlen % 4 != 0) || (rlen < OCFS2_DIR_REC_LEN(de->name_len)) || (((char *)de - dir_buf) > fs->fs_blocksize)) ret = 0; return ret; } int ocfs2_search_dirblock(ocfs2_filesys *fs, char *dir_buf, const char *name, int namelen, unsigned int bytes, struct ocfs2_dir_entry **res_dir) { struct ocfs2_dir_entry *de; char *dlimit, *de_buf; int de_len, offset = 0; int ret = 0; de_buf = (char *)dir_buf; dlimit = de_buf + bytes; while(de_buf < dlimit) { de = (struct ocfs2_dir_entry *)de_buf; if ((de_buf + namelen <= dlimit) && ocfs2_match(namelen, name, de)) { if (!ocfs2_check_dir_entry(fs, de, dir_buf, offset)) { ret = -1; goto out; } if (res_dir) *res_dir = de; ret = 1; goto out; } de_len = de->rec_len; if (de_len <= 0) { ret = -1; goto out; } de_buf += de_len; offset += de_len; } out: return ret; } errcode_t ocfs2_dx_dir_search(ocfs2_filesys *fs, const char *name, int namelen, struct ocfs2_dx_root_block *dx_root, struct ocfs2_dir_lookup_result *lookup) { errcode_t ret; char *di_buf = NULL, *dir_buf = NULL, *dx_leaf_buf = NULL; struct ocfs2_dx_entry_list *entry_list; struct ocfs2_dx_leaf *dx_leaf; struct ocfs2_dx_entry *dx_entry; struct ocfs2_dir_entry *dir_ent; uint32_t leaf_cpos; uint64_t blkno; int i, found; if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) entry_list = &dx_root->dr_entries; else { ret = ocfs2_dx_dir_lookup(fs, dx_root, &dx_root->dr_list, &lookup->dl_hinfo, &leaf_cpos, &blkno); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &dx_leaf_buf); if (ret) goto out; ret = ocfs2_read_dx_leaf(fs, blkno, dx_leaf_buf); if (ret) goto out; dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_buf; entry_list = &dx_leaf->dl_list; } assert(entry_list->de_count > 0); assert(entry_list->de_num_used > 0); assert(dx_root->dr_num_entries > 0); ret = ocfs2_malloc_block(fs->fs_io, &dir_buf); if (ret) goto out; found = 0; for (i = 0; i < entry_list->de_num_used; i++) { dx_entry = &entry_list->de_entries[i]; if ((lookup->dl_hinfo.major_hash != dx_entry->dx_major_hash) || (lookup->dl_hinfo.minor_hash != dx_entry->dx_minor_hash)) continue; ret = ocfs2_read_blocks(fs, dx_entry->dx_dirent_blk, 1, dir_buf); if (ret) goto out; found = ocfs2_search_dirblock(fs, dir_buf, name, namelen, fs->fs_blocksize, &dir_ent); if (found == 1) break; if (found == -1) { ret = OCFS2_ET_DIR_CORRUPTED; goto out; } } if (found <= 0) { ret = OCFS2_ET_DIRENT_NOT_FOUND; goto out; } lookup->dl_leaf = dir_buf; lookup->dl_leaf_blkno = dx_entry->dx_dirent_blk; lookup->dl_entry = dir_ent; lookup->dl_dx_entry = dx_entry; lookup->dl_dx_entry_idx = i; if (!(dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)) { lookup->dl_dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_buf; lookup->dl_dx_leaf_blkno = blkno; } ret = 0; out: if (di_buf) ocfs2_free(&di_buf); if (ret) { if (dir_buf) ocfs2_free(&dir_buf); if (dx_leaf_buf) ocfs2_free(&dx_leaf_buf); } return ret; } void release_lookup_res(struct ocfs2_dir_lookup_result *res) { if (res->dl_leaf) ocfs2_free(&res->dl_leaf); if (res->dl_dx_leaf) ocfs2_free(&res->dl_dx_leaf); } ./ocfs2-tools-1.6.4/libocfs2/bitmap.h0000644000176100017610000001155711500500544014111 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * bitmap.h * * Structures for allocation bitmaps for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker */ #ifndef _BITMAP_H #define _BITMAP_H #include "ocfs2/kernel-rbtree.h" struct ocfs2_bitmap_region { struct rb_node br_node; uint64_t br_start_bit; /* Bit offset. */ int br_bitmap_start; /* bit start in br_bitmap. */ int br_valid_bits; /* bit length valid in br_bitmap. */ int br_total_bits; /* set_bit() and friends can't handle bitmaps larger than int offsets */ size_t br_bytes; int br_set_bits; uint8_t *br_bitmap; void *br_private; }; struct ocfs2_bitmap_operations { errcode_t (*set_bit)(ocfs2_bitmap *bitmap, uint64_t bit, int *oldval); errcode_t (*clear_bit)(ocfs2_bitmap *bitmap, uint64_t bit, int *oldval); errcode_t (*test_bit)(ocfs2_bitmap *bitmap, uint64_t bit, int *val); errcode_t (*find_next_set)(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); errcode_t (*find_next_clear)(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); int (*merge_region)(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *prev, struct ocfs2_bitmap_region *next); errcode_t (*read_bitmap)(ocfs2_bitmap *bitmap); errcode_t (*write_bitmap)(ocfs2_bitmap *bitmap); void (*destroy_notify)(ocfs2_bitmap *bitmap); void (*bit_change_notify)(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br, uint64_t bitno, int new_val); errcode_t (*alloc_range)(ocfs2_bitmap *bitmap, uint64_t min_len, uint64_t len, uint64_t *first_bit, uint64_t *bits_found); errcode_t (*clear_range)(ocfs2_bitmap *bitmap, uint64_t len, uint64_t first_bit); }; struct _ocfs2_bitmap { ocfs2_filesys *b_fs; uint64_t b_set_bits; uint64_t b_total_bits; char *b_description; struct ocfs2_bitmap_operations *b_ops; struct rb_root b_regions; void *b_private; }; errcode_t ocfs2_bitmap_new(ocfs2_filesys *fs, uint64_t total_bits, const char *description, struct ocfs2_bitmap_operations *ops, void *private_data, ocfs2_bitmap **ret_bitmap); errcode_t ocfs2_bitmap_alloc_region(ocfs2_bitmap *bitmap, uint64_t start_bit, int bitmap_start, int total_bits, struct ocfs2_bitmap_region **ret_br); void ocfs2_bitmap_free_region(struct ocfs2_bitmap_region *br); errcode_t ocfs2_bitmap_realloc_region(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br, int total_bits); errcode_t ocfs2_bitmap_insert_region(ocfs2_bitmap *bitmap, struct ocfs2_bitmap_region *br); typedef errcode_t (*ocfs2_bitmap_foreach_func)(struct ocfs2_bitmap_region *br, void *private_data); errcode_t ocfs2_bitmap_foreach_region(ocfs2_bitmap *bitmap, ocfs2_bitmap_foreach_func func, void *private_data); errcode_t ocfs2_bitmap_set_generic(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval); errcode_t ocfs2_bitmap_clear_generic(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval); errcode_t ocfs2_bitmap_test_generic(ocfs2_bitmap *bitmap, uint64_t bitno, int *val); errcode_t ocfs2_bitmap_find_next_set_generic(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); errcode_t ocfs2_bitmap_find_next_clear_generic(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); errcode_t ocfs2_bitmap_alloc_range_generic(ocfs2_bitmap *bitmap, uint64_t min_len, uint64_t len, uint64_t *first_bit, uint64_t *bits_found); errcode_t ocfs2_bitmap_clear_range_generic(ocfs2_bitmap *bitmap, uint64_t len, uint64_t first_bit); errcode_t ocfs2_bitmap_set_holes(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval); errcode_t ocfs2_bitmap_clear_holes(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval); errcode_t ocfs2_bitmap_test_holes(ocfs2_bitmap *bitmap, uint64_t bitno, int *val); errcode_t ocfs2_bitmap_find_next_set_holes(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); errcode_t ocfs2_bitmap_find_next_clear_holes(ocfs2_bitmap *bitmap, uint64_t start, uint64_t *found); #endif /* _BITMAP_H */ ./ocfs2-tools-1.6.4/libocfs2/crc32table.h0000664000176100017610000002433611170734140014566 00000000000000/* this file is generated - do not edit */ /* * This file is generated in the kernel sources by lib/gen_crc32table.c. * The following includes and defines are for our usage. */ #include #include #if __BYTE_ORDER == __LITTLE_ENDIAN # define tole(x) ((uint32_t)(x)) # define tobe(x) ((uint32_t)__bswap_constant_32(x)) #elif __BYTE_ORDER == __BIG_ENDIAN # define tole(x) ((uint32_t)__bswap_constant_32(x)) # define tobe(x) ((uint32_t)(x)) #else # error Invalid byte order __BYTE_ORDER #endif static const uint32_t crc32table_le[] = { tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL), tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L), tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L), tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L), tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL), tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L), tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL), tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L), tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L), tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL), tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L), tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L), tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L), tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL), tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L), tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL), tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL), tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L), tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L), tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L), tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL), tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L), tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL), tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L), tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L), tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL), tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L), tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L), tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L), tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL), tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L), tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL), tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL), tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L), tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L), tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L), tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL), tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L), tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL), tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L), tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L), tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL), tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L), tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L), tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L), tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL), tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L), tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL), tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL), tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L), tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L), tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L), tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL), tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L), tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL), tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L), tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L), tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL), tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L), tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L), tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L), tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL), tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L), tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL) }; static const uint32_t crc32table_be[] = { tobe(0x00000000L), tobe(0x04c11db7L), tobe(0x09823b6eL), tobe(0x0d4326d9L), tobe(0x130476dcL), tobe(0x17c56b6bL), tobe(0x1a864db2L), tobe(0x1e475005L), tobe(0x2608edb8L), tobe(0x22c9f00fL), tobe(0x2f8ad6d6L), tobe(0x2b4bcb61L), tobe(0x350c9b64L), tobe(0x31cd86d3L), tobe(0x3c8ea00aL), tobe(0x384fbdbdL), tobe(0x4c11db70L), tobe(0x48d0c6c7L), tobe(0x4593e01eL), tobe(0x4152fda9L), tobe(0x5f15adacL), tobe(0x5bd4b01bL), tobe(0x569796c2L), tobe(0x52568b75L), tobe(0x6a1936c8L), tobe(0x6ed82b7fL), tobe(0x639b0da6L), tobe(0x675a1011L), tobe(0x791d4014L), tobe(0x7ddc5da3L), tobe(0x709f7b7aL), tobe(0x745e66cdL), tobe(0x9823b6e0L), tobe(0x9ce2ab57L), tobe(0x91a18d8eL), tobe(0x95609039L), tobe(0x8b27c03cL), tobe(0x8fe6dd8bL), tobe(0x82a5fb52L), tobe(0x8664e6e5L), tobe(0xbe2b5b58L), tobe(0xbaea46efL), tobe(0xb7a96036L), tobe(0xb3687d81L), tobe(0xad2f2d84L), tobe(0xa9ee3033L), tobe(0xa4ad16eaL), tobe(0xa06c0b5dL), tobe(0xd4326d90L), tobe(0xd0f37027L), tobe(0xddb056feL), tobe(0xd9714b49L), tobe(0xc7361b4cL), tobe(0xc3f706fbL), tobe(0xceb42022L), tobe(0xca753d95L), tobe(0xf23a8028L), tobe(0xf6fb9d9fL), tobe(0xfbb8bb46L), tobe(0xff79a6f1L), tobe(0xe13ef6f4L), tobe(0xe5ffeb43L), tobe(0xe8bccd9aL), tobe(0xec7dd02dL), tobe(0x34867077L), tobe(0x30476dc0L), tobe(0x3d044b19L), tobe(0x39c556aeL), tobe(0x278206abL), tobe(0x23431b1cL), tobe(0x2e003dc5L), tobe(0x2ac12072L), tobe(0x128e9dcfL), tobe(0x164f8078L), tobe(0x1b0ca6a1L), tobe(0x1fcdbb16L), tobe(0x018aeb13L), tobe(0x054bf6a4L), tobe(0x0808d07dL), tobe(0x0cc9cdcaL), tobe(0x7897ab07L), tobe(0x7c56b6b0L), tobe(0x71159069L), tobe(0x75d48ddeL), tobe(0x6b93dddbL), tobe(0x6f52c06cL), tobe(0x6211e6b5L), tobe(0x66d0fb02L), tobe(0x5e9f46bfL), tobe(0x5a5e5b08L), tobe(0x571d7dd1L), tobe(0x53dc6066L), tobe(0x4d9b3063L), tobe(0x495a2dd4L), tobe(0x44190b0dL), tobe(0x40d816baL), tobe(0xaca5c697L), tobe(0xa864db20L), tobe(0xa527fdf9L), tobe(0xa1e6e04eL), tobe(0xbfa1b04bL), tobe(0xbb60adfcL), tobe(0xb6238b25L), tobe(0xb2e29692L), tobe(0x8aad2b2fL), tobe(0x8e6c3698L), tobe(0x832f1041L), tobe(0x87ee0df6L), tobe(0x99a95df3L), tobe(0x9d684044L), tobe(0x902b669dL), tobe(0x94ea7b2aL), tobe(0xe0b41de7L), tobe(0xe4750050L), tobe(0xe9362689L), tobe(0xedf73b3eL), tobe(0xf3b06b3bL), tobe(0xf771768cL), tobe(0xfa325055L), tobe(0xfef34de2L), tobe(0xc6bcf05fL), tobe(0xc27dede8L), tobe(0xcf3ecb31L), tobe(0xcbffd686L), tobe(0xd5b88683L), tobe(0xd1799b34L), tobe(0xdc3abdedL), tobe(0xd8fba05aL), tobe(0x690ce0eeL), tobe(0x6dcdfd59L), tobe(0x608edb80L), tobe(0x644fc637L), tobe(0x7a089632L), tobe(0x7ec98b85L), tobe(0x738aad5cL), tobe(0x774bb0ebL), tobe(0x4f040d56L), tobe(0x4bc510e1L), tobe(0x46863638L), tobe(0x42472b8fL), tobe(0x5c007b8aL), tobe(0x58c1663dL), tobe(0x558240e4L), tobe(0x51435d53L), tobe(0x251d3b9eL), tobe(0x21dc2629L), tobe(0x2c9f00f0L), tobe(0x285e1d47L), tobe(0x36194d42L), tobe(0x32d850f5L), tobe(0x3f9b762cL), tobe(0x3b5a6b9bL), tobe(0x0315d626L), tobe(0x07d4cb91L), tobe(0x0a97ed48L), tobe(0x0e56f0ffL), tobe(0x1011a0faL), tobe(0x14d0bd4dL), tobe(0x19939b94L), tobe(0x1d528623L), tobe(0xf12f560eL), tobe(0xf5ee4bb9L), tobe(0xf8ad6d60L), tobe(0xfc6c70d7L), tobe(0xe22b20d2L), tobe(0xe6ea3d65L), tobe(0xeba91bbcL), tobe(0xef68060bL), tobe(0xd727bbb6L), tobe(0xd3e6a601L), tobe(0xdea580d8L), tobe(0xda649d6fL), tobe(0xc423cd6aL), tobe(0xc0e2d0ddL), tobe(0xcda1f604L), tobe(0xc960ebb3L), tobe(0xbd3e8d7eL), tobe(0xb9ff90c9L), tobe(0xb4bcb610L), tobe(0xb07daba7L), tobe(0xae3afba2L), tobe(0xaafbe615L), tobe(0xa7b8c0ccL), tobe(0xa379dd7bL), tobe(0x9b3660c6L), tobe(0x9ff77d71L), tobe(0x92b45ba8L), tobe(0x9675461fL), tobe(0x8832161aL), tobe(0x8cf30badL), tobe(0x81b02d74L), tobe(0x857130c3L), tobe(0x5d8a9099L), tobe(0x594b8d2eL), tobe(0x5408abf7L), tobe(0x50c9b640L), tobe(0x4e8ee645L), tobe(0x4a4ffbf2L), tobe(0x470cdd2bL), tobe(0x43cdc09cL), tobe(0x7b827d21L), tobe(0x7f436096L), tobe(0x7200464fL), tobe(0x76c15bf8L), tobe(0x68860bfdL), tobe(0x6c47164aL), tobe(0x61043093L), tobe(0x65c52d24L), tobe(0x119b4be9L), tobe(0x155a565eL), tobe(0x18197087L), tobe(0x1cd86d30L), tobe(0x029f3d35L), tobe(0x065e2082L), tobe(0x0b1d065bL), tobe(0x0fdc1becL), tobe(0x3793a651L), tobe(0x3352bbe6L), tobe(0x3e119d3fL), tobe(0x3ad08088L), tobe(0x2497d08dL), tobe(0x2056cd3aL), tobe(0x2d15ebe3L), tobe(0x29d4f654L), tobe(0xc5a92679L), tobe(0xc1683bceL), tobe(0xcc2b1d17L), tobe(0xc8ea00a0L), tobe(0xd6ad50a5L), tobe(0xd26c4d12L), tobe(0xdf2f6bcbL), tobe(0xdbee767cL), tobe(0xe3a1cbc1L), tobe(0xe760d676L), tobe(0xea23f0afL), tobe(0xeee2ed18L), tobe(0xf0a5bd1dL), tobe(0xf464a0aaL), tobe(0xf9278673L), tobe(0xfde69bc4L), tobe(0x89b8fd09L), tobe(0x8d79e0beL), tobe(0x803ac667L), tobe(0x84fbdbd0L), tobe(0x9abc8bd5L), tobe(0x9e7d9662L), tobe(0x933eb0bbL), tobe(0x97ffad0cL), tobe(0xafb010b1L), tobe(0xab710d06L), tobe(0xa6322bdfL), tobe(0xa2f33668L), tobe(0xbcb4666dL), tobe(0xb8757bdaL), tobe(0xb5365d03L), tobe(0xb1f740b4L) }; ./ocfs2-tools-1.6.4/libocfs2/dir_iterate.h0000644000176100017610000000346511500500544015127 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dir_iterate.h * * Structures for dir iteration for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker */ #ifndef _DIR_ITERATE_H #define _DIR_ITERATE_H struct dir_context { uint64_t dir; int flags; struct ocfs2_dinode *di; char *buf; int (*func)(uint64_t dir, int entry, struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data); void *priv_data; errcode_t errcode; }; extern int ocfs2_process_dir_block(ocfs2_filesys *fs, uint64_t blocknr, uint64_t blockcnt, uint16_t ext_flags, void *priv_data); #define OCFS2_DIR_PAD 4 #define OCFS2_DIR_ROUND (OCFS2_DIR_PAD - 1) #define OCFS2_DIR_MEMBER_LEN offsetof(struct ocfs2_dir_entry, name) #define OCFS2_DIR_REC_LEN(name_len) (((name_len) + OCFS2_DIR_MEMBER_LEN + \ OCFS2_DIR_ROUND) & \ ~OCFS2_DIR_ROUND) #endif /* _DIR_ITERATE_H */ ./ocfs2-tools-1.6.4/libocfs2/dir_util.h0000644000176100017610000000224111115551035014441 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dir_util.h * * Structures for dir iteration for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker */ #ifndef _DIR_UTIL_H #define _DIR_UTIL_H static inline int is_dots(const char *name, unsigned int len) { if (len == 0) return 0; if (name[0] == '.') { if (len == 1) return 1; if (len == 2 && name[1] == '.') return 1; } return 0; } #endif /* _DIR_UTIL_H */ ./ocfs2-tools-1.6.4/libocfs2/extent_map.h0000644000176100017610000000237611115551036015004 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extent_map.h * * Internal extent map structures for the OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * Authors: Joel Becker */ #ifndef _EXTENT_MAP_H #define _EXTENT_MAP_H #include "ocfs2/kernel-rbtree.h" typedef struct _ocfs2_extent_map_entry ocfs2_extent_map_entry; struct _ocfs2_extent_map { struct rb_root em_extents; uint32_t em_clusters; }; struct _ocfs2_extent_map_entry { struct rb_node e_node; int e_tree_depth; struct ocfs2_extent_rec e_rec; }; #endif /* _EXTENT_MAP_H */ ./ocfs2-tools-1.6.4/libocfs2/extent_tree.h0000644000176100017610000001327011500500544015155 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extent_tree.h * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ /* Useful typedef for passing around writing functions for extent tree root. */ typedef errcode_t (*ocfs2_root_write_func)(ocfs2_filesys *fs, uint64_t blkno, char *root_buf); struct ocfs2_extent_tree { struct ocfs2_extent_tree_operations *et_ops; char *et_root_buf; uint64_t et_root_blkno; ocfs2_root_write_func et_root_write; struct ocfs2_extent_list *et_root_el; void *et_object; uint32_t et_max_leaf_clusters; }; enum ocfs2_contig_type { CONTIG_NONE = 0, CONTIG_LEFT, CONTIG_RIGHT, CONTIG_LEFTRIGHT, }; /* * Operations for a specific extent tree type. * * To implement an on-disk btree (extent tree) type in ocfs2, add * an ocfs2_extent_tree_operations structure and the matching * ocfs2_init__extent_tree() function. That's pretty much it * for the allocation portion of the extent tree. */ struct ocfs2_extent_tree_operations { /* * last_eb_blk is the block number of the right most leaf extent * block. Most on-disk structures containing an extent tree store * this value for fast access. The ->eo_set_last_eb_blk() and * ->eo_get_last_eb_blk() operations access this value. They are * both required. */ void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et, uint64_t blkno); uint64_t (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et); /* * The on-disk structure usually keeps track of how many total * clusters are stored in this extent tree. This function updates * that value. new_clusters is the delta, and must be * added to the total. Required. */ void (*eo_update_clusters)(/*struct inode *inode,*/ struct ocfs2_extent_tree *et, uint32_t new_clusters); uint32_t (*eo_get_clusters)(struct ocfs2_extent_tree *et); /* * If ->eo_insert_check() exists, it is called before rec is * inserted into the extent tree. It is optional. */ /* int (*eo_insert_check)(struct inode *inode, struct ocfs2_extent_tree *et, struct ocfs2_extent_rec *rec); int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et); */ int (*eo_sanity_check)(struct ocfs2_extent_tree *et); /* * -------------------------------------------------------------- * The remaining are internal to ocfs2_extent_tree and don't have * accessor functions */ /* * ->eo_fill_root_el() takes et->et_object and sets et->et_root_el. * It is required. */ void (*eo_fill_root_el)(struct ocfs2_extent_tree *et); /* * ->eo_fill_max_leaf_clusters sets et->et_max_leaf_clusters if * it exists. If it does not, et->et_max_leaf_clusters is set * to 0 (unlimited). Optional. */ void (*eo_fill_max_leaf_clusters)(ocfs2_filesys *fs, struct ocfs2_extent_tree *et); /* * ->eo_extent_contig test whether the 2 ocfs2_extent_rec * are contiguous or not. Optional. Don't need to set it if use * ocfs2_extent_rec as the tree leaf. */ enum ocfs2_contig_type (*eo_extent_contig)(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_extent_rec *ext, struct ocfs2_extent_rec *insert_rec); }; void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno); void ocfs2_init_refcount_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno); void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno, ocfs2_root_write_func write, struct ocfs2_xattr_value_root *xv); void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno); errcode_t ocfs2_tree_insert_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag); int ocfs2_change_extent_flag(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t len, uint64_t p_blkno, int new_flags, int clear_flags); int ocfs2_remove_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t len); /* * Structures which describe a path through a btree, and functions to * manipulate them. * * The idea here is to be as generic as possible with the tree * manipulation code. */ struct ocfs2_path_item { uint64_t blkno; char *buf; struct ocfs2_extent_list *el; }; #define OCFS2_MAX_PATH_DEPTH 5 struct ocfs2_path { int p_tree_depth; struct ocfs2_path_item p_node[OCFS2_MAX_PATH_DEPTH]; }; #define path_root_blkno(_path) ((_path)->p_node[0].blkno) #define path_root_buf(_path) ((_path)->p_node[0].buf) #define path_root_el(_path) ((_path)->p_node[0].el) #define path_leaf_blkno(_path) ((_path)->p_node[(_path)->p_tree_depth].blkno) #define path_leaf_buf(_path) ((_path)->p_node[(_path)->p_tree_depth].buf) #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) #define path_num_items(_path) ((_path)->p_tree_depth + 1) struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et); int ocfs2_find_path(ocfs2_filesys *fs, struct ocfs2_path *path, uint32_t cpos); void ocfs2_free_path(struct ocfs2_path *path); ./ocfs2-tools-1.6.4/libocfs2/refcount.h0000644000176100017610000000217511453177334014474 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * refcount.h * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef _LIBOCFS2_REFCOUNT_H_ #define _LIBOCFS2_REFCOUNT_H_ typedef errcode_t (ocfs2_post_refcount_func)(ocfs2_filesys *fs, void *para); /* * Some refcount caller need to do more work after we modify the data b-tree * during refcount operation(including CoW and add refcount flag), and make the * transaction complete. So it must give us this structure so that we can do it * within our transaction. * */ struct ocfs2_post_refcount { ocfs2_post_refcount_func *func; /* real function. */ void *para; }; #endif /* _LIBOCFS2_REFCOUNT_H_ */ ./ocfs2-tools-1.6.4/libocfs2/ocfs2_err.et0000644000176100017610000001115011500500544014667 00000000000000# # ocfs2_err.et # # Error codes for the OCFS2 userspace library. # # Copyright (C) 2004, 2007 Oracle. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License, version 2, as published by the Free Software Foundation. # # 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 021110-1307, USA. # error_table ocfs ec OCFS2_ET_NAMED_DEVICE_NOT_FOUND, "Device name specified was not found" ec OCFS2_ET_BAD_DEVICE_NAME, "Illegal or malformed device name" ec OCFS2_ET_IO, "I/O error on channel" ec OCFS2_ET_SHORT_READ, "Attempt to read block from filesystem resulted in short read" ec OCFS2_ET_SHORT_WRITE, "Attempt to write block to the filesystem resulted in short write" ec OCFS2_ET_NO_MEMORY, "Memory allocation failed" ec OCFS2_ET_INVALID_ARGUMENT, "Invalid argument passed to OCFS2 library" ec OCFS2_ET_OCFS_REV, "Device contains an OCFS volume" ec OCFS2_ET_BAD_MAGIC, "Bad magic number in superblock" ec OCFS2_ET_UNEXPECTED_BLOCK_SIZE, "Filesystem has unexpected block size" ec OCFS2_ET_CORRUPT_SUPERBLOCK, "The OCFS2 superblock is corrupt" ec OCFS2_ET_UNSUPP_FEATURE, "Unsupported feature(s) found" ec OCFS2_ET_RO_UNSUPP_FEATURE, "Unsupported read-only feature(s) found" ec OCFS2_ET_CONFLICTING_FEATURES, "Conflicting features specified" ec OCFS2_ET_BAD_INODE_MAGIC, "Bad magic number in inode" ec OCFS2_ET_BAD_BLKNO, "Invalid block number" ec OCFS2_ET_RO_FILESYS, "Attempt to write to filesystem opened read-only" ec OCFS2_ET_JOURNAL_TOO_SMALL, "Journal must be at least 1024 blocks" ec OCFS2_ET_BAD_JOURNAL_SUPERBLOCK_MAGIC, "Bad magic number in journal superblock" ec OCFS2_ET_BAD_JOURNAL_REVOKE, "Invalid revoke record in journal" ec OCFS2_ET_BAD_JOURNAL_TAG, "Invalid block tag in journal" ec OCFS2_ET_INODE_NOT_VALID, "Inode is not valid (active)" ec OCFS2_ET_INODE_CANNOT_BE_ITERATED, "Inode type does not contain extents" ec OCFS2_ET_BAD_EXTENT_BLOCK_MAGIC, "Bad magic number in extent block" ec OCFS2_ET_CORRUPT_EXTENT_BLOCK, "Extent block is corrupt" ec OCFS2_ET_DIR_CORRUPTED, "OCFS2 directory corrupted" ec OCFS2_ET_NO_DIRECTORY, "OCFS2 inode is not a directory" ec OCFS2_ET_DIRENT_NOT_FOUND, "Directory entry not found" ec OCFS2_ET_FILE_NOT_FOUND, "File not found by ocfs2_lookup" ec OCFS2_ET_DIR_NO_SPACE, "No free space in the directory" ec OCFS2_ET_INVALID_BIT, "Bit does not exist in bitmap range" ec OCFS2_ET_INTERNAL_FAILURE, "Internal logic faliure" ec OCFS2_ET_BAD_GROUP_DESC_MAGIC, "Bad magic number in group descriptor" ec OCFS2_ET_CORRUPT_GROUP_DESC, "Group descriptor is corrupt" ec OCFS2_ET_CORRUPT_CHAIN, "Chain allocator is corrupt" ec OCFS2_ET_INVALID_EXTENT_LOOKUP, "Invalid range passed to extent map lookup" ec OCFS2_ET_EXTENT_NOT_FOUND, "No mapping exists for the given extent range" ec OCFS2_ET_DUPLICATE_BLOCK, "Duplicate block discovered" ec OCFS2_ET_BIT_NOT_FOUND, "Unable to find available bit" ec OCFS2_ET_FREEING_UNALLOCATED_REGION, "Attempting to free unallocated region" ec OCFS2_ET_EXPAND_DIR_ERR, "Unable to expand directory" ec OCFS2_ET_NO_SPACE, "No space available" ec OCFS2_ET_ITERATION_COMPLETE, "Iteration complete" ec OCFS2_ET_SYMLINK_LOOP, "Too many symbolic links encountered" ec OCFS2_ET_BAD_HEARTBEAT_FILE, "Invalid heartbeat file" ec OCFS2_ET_UNKNOWN_FILESYSTEM, "Unknown filesystem" ec OCFS2_ET_BLOCK_SIZE_TOO_SMALL_FOR_HARDWARE, "The block size is smaller than the sector size on this device" ec OCFS2_ET_INVALID_LOCKRES, "The lock name is invalid" ec OCFS2_ET_NO_IONICE, "Can't find ionice" ec OCFS2_ET_NO_BACKUP_SUPER, "Backup superblock not found" ec OCFS2_ET_TOO_MANY_SLOTS, "Too many slots for slot map" ec OCFS2_ET_CANNOT_INLINE_DATA, "Can't write the data inline" ec OCFS2_ET_BAD_DIR_BLOCK_MAGIC, "Bad magic number in directory block" ec OCFS2_ET_BAD_XATTR_BLOCK_MAGIC, "Bad magic number in xattr block" ec OCFS2_ET_UNKNOWN_FEATURE, "Unknown feature" ec OCFS2_ET_CORRUPT_QUOTA_FILE, "Quota file is corrupted" ec OCFS2_ET_CANNOT_DETERMINE_SECTOR_SIZE, "Cannot determine sector size" ec OCFS2_ET_DX_BALANCE_EMPTY_LEAF, "Trying to rebalance empty leaf for indexed dir" ec OCFS2_ET_NONEMTY_QUOTA_HASH, "Freeing non-empty quota hash" end ./ocfs2-tools-1.6.4/fsck.ocfs2/0000775000176100017610000000000011515641641013005 500000000000000./ocfs2-tools-1.6.4/fsck.ocfs2/include/0000775000176100017610000000000011515641641014430 500000000000000./ocfs2-tools-1.6.4/fsck.ocfs2/include/fsck.h0000644000176100017610000000565011453177334015457 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * fsck.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_FSCK_H__ #define __O2FSCK_FSCK_H__ #include "icount.h" #include "dirblocks.h" struct refcount_file; typedef struct _o2fsck_state { ocfs2_filesys *ost_fs; ocfs2_cached_inode *ost_global_inode_alloc; ocfs2_cached_inode **ost_inode_allocs; ocfs2_bitmap *ost_dir_inodes; ocfs2_bitmap *ost_reg_inodes; ocfs2_bitmap *ost_allocated_clusters; ocfs2_bitmap *ost_duplicate_clusters; /* This is no more than a cache of what we know the i_link_count * in each inode to currently be. If an inode is marked in used_inodes * this had better be up to date. */ o2fsck_icount *ost_icount_in_inodes; /* this records references to each inode from other directory * entries, including '.' and '..'. */ o2fsck_icount *ost_icount_refs; o2fsck_dirblocks ost_dirblocks; uint32_t ost_fs_generation; uint64_t ost_lostfound_ino; uint32_t ost_num_clusters; struct rb_root ost_dir_parents; struct rb_root ost_refcount_trees; struct refcount_file *ost_latest_file; unsigned ost_ask:1, /* confirm with the user */ ost_answer:1, /* answer if we don't ask the user */ ost_force:1, /* -f supplied; force check */ ost_skip_o2cb:1,/* -F: ignore cluster services */ ost_write_inode_alloc_asked:1, ost_write_inode_alloc:1, ost_write_error:1, ost_write_cluster_alloc_asked:1, ost_write_cluster_alloc:1, ost_saw_error:1, /* if we think there are still errors * on disk we'll mark the sb as having * errors as we exit */ ost_stale_mounts:1, /* set when reading publish blocks * that still indicated mounted */ ost_fix_fs_gen:1, ost_has_journal_dirty:1, ost_compress_dirs:1; errcode_t ost_err; } o2fsck_state; errcode_t o2fsck_state_reinit(ocfs2_filesys *fs, o2fsck_state *ost); /* The idea is to let someone off-site run fsck and have it give us * enough information to diagnose problems with */ extern int verbose; #define verbosef(fmt, args...) do { \ if (verbose) \ printf("%s:%d | " fmt, __FUNCTION__, __LINE__, args);\ } while (0) #endif /* __O2FSCK_FSCK_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/xattr.h0000664000176100017610000000142011170734140015652 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * xattr.h * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef __O2FSCK_XATTR_H__ #define __O2FSCK_XATTR_H__ #include "fsck.h" errcode_t o2fsck_check_xattr(o2fsck_state *ost, struct ocfs2_dinode *di); #endif /* __O2FSCK_XATTR_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/dirblocks.h0000644000176100017610000000355111500500544016465 00000000000000/* * dirblocks.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_DIRBLOCKS_H__ #define __O2FSCK_DIRBLOCKS_H__ #include "ocfs2/ocfs2.h" #include "ocfs2/kernel-rbtree.h" typedef struct _o2fsck_dirblocks { struct rb_root db_root; } o2fsck_dirblocks; typedef struct _o2fsck_dirblock_entry { struct rb_node e_node; uint64_t e_ino; uint64_t e_blkno; uint64_t e_blkcount; } o2fsck_dirblock_entry; typedef unsigned (*dirblock_iterator)(o2fsck_dirblock_entry *, void *priv_data); errcode_t o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino, uint64_t blkno, uint64_t blkcount); struct _o2fsck_state; void o2fsck_dir_block_iterate(struct _o2fsck_state *ost, dirblock_iterator func, void *priv_data); uint64_t o2fsck_search_reidx_dir(struct rb_root *root, uint64_t dino); errcode_t o2fsck_try_add_reidx_dir(struct rb_root *root, uint64_t dino); errcode_t o2fsck_rebuild_indexed_dirs(ocfs2_filesys *fs, struct rb_root *root); errcode_t o2fsck_check_dir_index(struct _o2fsck_state *ost, struct ocfs2_dinode *di); #endif /* __O2FSCK_DIRBLOCKS_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/dirparents.h0000644000176100017610000000354211115551035016667 00000000000000/* * dirparents.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_DIRPARENTS_H__ #define __O2FSCK_DIRPARENTS_H__ #include "ocfs2/kernel-rbtree.h" typedef struct _o2fsck_dir_parent { struct rb_node dp_node; uint64_t dp_ino; /* The dir inode in question. */ uint64_t dp_dot_dot; /* The parent according to the dir's own * '..' entry */ uint64_t dp_dirent; /* The inode that has a dirent which points * to this directory. */ /* used by pass3 to walk the dir_parent structs and ensure * connectivity */ uint64_t dp_loop_no; unsigned dp_connected:1, dp_in_orphan_dir:1; } o2fsck_dir_parent; errcode_t o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino, uint64_t dot_dot, uint64_t dirent, unsigned in_orphan_dir); o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root, uint64_t ino); o2fsck_dir_parent *o2fsck_dir_parent_first(struct rb_root *root); o2fsck_dir_parent *o2fsck_dir_parent_next(o2fsck_dir_parent *from); void ocfsck_remove_dir_parent(struct rb_root *root, uint64_t ino); #endif /* __O2FSCK_DIRPARENTS_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/extent.h0000644000176100017610000000413411453177334016034 00000000000000/* * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. */ #ifndef __O2FSCK_EXTENT_H__ #define __O2FSCK_EXTENT_H__ #include "fsck.h" typedef errcode_t (check_leaf_er_func)(o2fsck_state *ost, uint64_t owner, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *er, int *changed, void *para); typedef errcode_t (mark_leaf_er_alloc_func)(o2fsck_state *ost, struct ocfs2_extent_rec *er, uint32_t clusters, void *para); struct extent_info { uint64_t ei_max_size; uint64_t ei_clusters; uint64_t ei_last_eb_blk; uint16_t ei_expected_depth; unsigned ei_expect_depth:1; check_leaf_er_func *chk_rec_func; mark_leaf_er_alloc_func *mark_rec_alloc_func; void *para; }; errcode_t o2fsck_check_extents(o2fsck_state *ost, struct ocfs2_dinode *di); errcode_t check_el(o2fsck_state *ost, struct extent_info *ei, uint64_t owner, struct ocfs2_extent_list *el, uint16_t max_recs, int *changed); errcode_t o2fsck_check_extent_rec(o2fsck_state *ost, uint64_t owner, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *er, int *changed, void *para); errcode_t o2fsck_mark_tree_clusters_allocated(o2fsck_state *ost, struct ocfs2_extent_rec *rec, uint32_t clusters, void *para); #endif /* __O2FSCK_EXTENT_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/icount.h0000644000176100017610000000302311115551035016007 00000000000000/* * icount.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_ICOUNT_H__ #define __O2FSCK_ICOUNT_H__ #include "ocfs2/ocfs2.h" #include "ocfs2/kernel-rbtree.h" typedef struct _o2fsck_icount { ocfs2_bitmap *ic_single_bm; struct rb_root ic_multiple_tree; } o2fsck_icount; errcode_t o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno, uint16_t count); uint16_t o2fsck_icount_get(o2fsck_icount *icount, uint64_t blkno); errcode_t o2fsck_icount_new(ocfs2_filesys *fs, o2fsck_icount **ret); void o2fsck_icount_free(o2fsck_icount *icount); void o2fsck_icount_delta(o2fsck_icount *icount, uint64_t blkno, int delta); errcode_t o2fsck_icount_next_blkno(o2fsck_icount *icount, uint64_t start, uint64_t *found); #endif /* __O2FSCK_ICOUNT_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/journal.h0000664000176100017610000000230511170734140016165 00000000000000/* * journal.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_JOURNAL_H__ #define __O2FSCK_JOURNAL_H__ #include "fsck.h" errcode_t o2fsck_replay_journals(ocfs2_filesys *fs, int *replayed); errcode_t o2fsck_should_replay_journals(ocfs2_filesys *fs, int *should, int *has_dirty); errcode_t o2fsck_clear_journal_flags(o2fsck_state *ost); errcode_t o2fsck_check_journals(o2fsck_state *ost); #endif /* __O2FSCK_JOURNAL_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass0.h0000664000176100017610000000173110673531132015546 00000000000000/* * pass0.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_PASS0_H__ #define __O2FSCK_PASS0_H__ #include "fsck.h" errcode_t o2fsck_pass0(o2fsck_state *ost); #endif /* __O2FSCK_PASS0_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass1.h0000664000176100017610000000201310673531132015541 00000000000000/* * pass1.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_PASS1_H__ #define __O2FSCK_PASS1_H__ #include "fsck.h" errcode_t o2fsck_pass1(o2fsck_state *ost); void o2fsck_free_inode_allocs(o2fsck_state *ost); #endif /* __O2FSCK_PASS1_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass1b.h0000644000176100017610000000123711346242240015705 00000000000000/* * pass1b.h * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef __O2FSCK_PASS1B_H__ #define __O2FSCK_PASS1B_H__ #include "fsck.h" errcode_t ocfs2_pass1_dups(o2fsck_state *ost); #endif /* __O2FSCK_PASS1_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass2.h0000664000176100017610000000203510673531132015546 00000000000000/* * pass2.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_PASS2_H__ #define __O2FSCK_PASS2_H__ #include "fsck.h" errcode_t o2fsck_pass2(o2fsck_state *ost); int o2fsck_test_inode_allocated(o2fsck_state *ost, uint64_t blkno); #endif /* __O2FSCK_PASS2_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass3.h0000664000176100017610000000203010673531132015542 00000000000000/* * pass3.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_PASS3_H__ #define __O2FSCK_PASS3_H__ #include "fsck.h" errcode_t o2fsck_pass3(o2fsck_state *ost); void o2fsck_reconnect_file(o2fsck_state *ost, uint64_t inode); #endif /* __O2FSCK_PASS3_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass4.h0000664000176100017610000000203411170734140015544 00000000000000/* * pass4.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_PASS4_H__ #define __O2FSCK_PASS4_H__ #include "fsck.h" errcode_t replay_orphan_dir(o2fsck_state *ost, int slot_recovery); errcode_t o2fsck_pass4(o2fsck_state *ost); #endif /* __O2FSCK_PASS4_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/pass5.h0000644000176100017610000000135211453177334015557 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * pass5.h * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef __O2FSCK_PASS5_H__ #define __O2FSCK_PASS5_H__ #include "fsck.h" errcode_t o2fsck_pass5(o2fsck_state *ost); #endif /* __O2FSCK_PASS4_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/problem.h0000664000176100017610000000414610673531132016163 00000000000000/* * problem.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_PROBLEM_H__ #define __O2FSCK_PROBLEM_H__ /* prompt flags. */ #define PY (1 << 0) /* default to yes when asked and no answer forced */ #define PN (1 << 1) /* default to no when asked and no answer forced */ #include "fsck.h" /* returns non-zero for yes and zero for no. The caller is expected to * provide a thorough description of the state and the action that will * be taken depending on the answer. Without \n termination. * * The code argument is a digit that identifies the error. it is used by * input to regression testing utils and referenced in fsck.ocfs2.checks(8). * each code is only supposed to have one call site. we create this * funny symbol so that the 'check-prompt-callers' makefile target * can go groveling through nm to find out if a code has more than * one call site. */ #define prompt(ost, flags, code, fmt...) ({ \ static int fsck_prompt_callers_with_code_##code = __LINE__; \ int _ret = fsck_prompt_callers_with_code_##code; \ _ret = prompt_input(ost, flags, code, fmt); \ _ret; \ }) struct prompt_code { const char *str; }; #include "../prompt-codes.h" int prompt_input(o2fsck_state *ost, unsigned flags, struct prompt_code code, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); #endif /* __O2FSCK_PROBLEM_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/refcount.h0000644000176100017610000000203611453177334016351 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * refcount.h * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef __O2FSCK_REFCOUNT_H__ #define __O2FSCK_REFCOUNT_H__ #include "fsck.h" errcode_t o2fsck_check_refcount_tree(o2fsck_state *ost, struct ocfs2_dinode *di); errcode_t o2fsck_mark_clusters_refcounted(o2fsck_state *ost, uint64_t rf_blkno, uint64_t i_blkno, uint64_t p_cpos, uint32_t clusters, uint32_t v_cpos); errcode_t o2fsck_check_mark_refcounted_clusters(o2fsck_state *ost); #endif /* __O2FSCK_REFCOUNT_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/slot_recovery.h0000664000176100017610000000164111170734140017414 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * slot_recovery.c * * Slot recovery handler. * * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef __O2FSCK_SLOT_RECOVERY_H__ #define __O2FSCK_SLOT_RECOVERY_H__ #include "fsck.h" errcode_t o2fsck_replay_truncate_logs(ocfs2_filesys *fs); errcode_t o2fsck_replay_local_allocs(ocfs2_filesys *fs); errcode_t o2fsck_replay_orphan_dirs(o2fsck_state *ost); #endif /* __O2FSCK_SLOT_RECOVERY_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/strings.h0000644000176100017610000000264411115551035016207 00000000000000/* * strings.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_STRINGS_H__ #define __O2FSCK_STRINGS_H__ #include "ocfs2/ocfs2.h" #include "ocfs2/kernel-rbtree.h" typedef struct _o2fsck_strings { struct rb_root s_root; size_t s_allocated; } o2fsck_strings; int o2fsck_strings_exists(o2fsck_strings *strings, char *string, size_t strlen); errcode_t o2fsck_strings_insert(o2fsck_strings *strings, char *string, size_t strlen, int *is_dup); void o2fsck_strings_init(o2fsck_strings *strings); void o2fsck_strings_free(o2fsck_strings *strings); size_t o2fsck_strings_bytes_allocated(o2fsck_strings *strings); #endif /* __O2FSCK_STRINGS_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/include/util.h0000644000176100017610000000643311346242240015474 00000000000000/* * util.h * * Copyright (C) 2002 Oracle Corporation. All rights reserved. * * 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 021110-1307, USA. * * Author: Zach Brown */ #ifndef __O2FSCK_UTIL_H__ #define __O2FSCK_UTIL_H__ #include #include "fsck.h" /* we duplicate e2fsck's error codes to make everyone's life easy */ #define FSCK_OK 0 /* No errors */ #define FSCK_NONDESTRUCT 1 /* File system errors corrected */ #define FSCK_REBOOT 2 /* System should be rebooted */ #define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */ #define FSCK_ERROR 8 /* Operational error */ #define FSCK_USAGE 16 /* Usage or syntax error */ #define FSCK_CANCELED 32 /* Aborted with a signal or ^C */ #define FSCK_LIBRARY 128 /* Shared library error */ /* Managing the I/O cache */ enum o2fsck_cache_hint { O2FSCK_CACHE_MODE_NONE = 0, O2FSCK_CACHE_MODE_JOURNAL, /* Enough of a cache to replay a journal */ O2FSCK_CACHE_MODE_FULL, /* Enough of a cache to recover the filesystem */ }; void o2fsck_init_cache(o2fsck_state *ost, enum o2fsck_cache_hint hint); int o2fsck_worth_caching(int blocks_to_read); void o2fsck_reset_blocks_cached(void); void o2fsck_write_inode(o2fsck_state *ost, uint64_t blkno, struct ocfs2_dinode *di); void o2fsck_mark_cluster_allocated(o2fsck_state *ost, uint32_t cluster); void o2fsck_mark_clusters_allocated(o2fsck_state *ost, uint32_t cluster, uint32_t num); void o2fsck_mark_cluster_unallocated(o2fsck_state *ost, uint32_t cluster); errcode_t o2fsck_type_from_dinode(o2fsck_state *ost, uint64_t ino, uint8_t *type); errcode_t o2fsck_read_publish(o2fsck_state *ost); size_t o2fsck_bitcount(unsigned char *bytes, size_t len); errcode_t handle_slots_system_file(ocfs2_filesys *fs, int type, errcode_t (*func)(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot)); /* How to abort but clean up the cluster state */ void o2fsck_abort(void); /* * Wrap the ocfs2 bitmap functions to abort when errors are found. They're * not supposed to fail, so we want to handle it. */ void __o2fsck_bitmap_set(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval, const char *where); void __o2fsck_bitmap_clear(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval, const char *where); /* These wrappers pass the caller into __o2fsck_bitmap_*() */ #define o2fsck_bitmap_set(_map, _bit, _old) \ __o2fsck_bitmap_set((_map), (_bit), (_old), __FUNCTION__) #define o2fsck_bitmap_clear(_map, _bit, _old) \ __o2fsck_bitmap_clear((_map), (_bit), (_old), __FUNCTION__); #endif /* __O2FSCK_UTIL_H__ */ ./ocfs2-tools-1.6.4/fsck.ocfs2/Makefile0000644000176100017610000000455311453177334014376 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make sbindir = $(root_sbindir) SBIN_PROGRAMS = fsck.ocfs2 DEFINES += -DVERSION=\"$(VERSION)\" INCLUDES = -I$(TOPDIR)/include -Iinclude LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2 LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm $(DL_LIBS) LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a ifndef OCFS2_DYNAMIC_FSCK LDFLAGS += -static endif CFILES = fsck.c \ dirblocks.c \ dirparents.c \ extent.c \ icount.c \ journal.c \ pass0.c \ pass1.c \ pass1b.c \ pass2.c \ pass3.c \ pass4.c \ pass5.c \ problem.c \ refcount.c \ slot_recovery.c \ strings.c \ util.c \ xattr.c HFILES = include/fsck.h \ include/xattr.h \ include/dirblocks.h \ include/dirparents.h \ include/extent.h \ include/icount.h \ include/journal.h \ include/pass0.h \ include/pass1.h \ include/pass1b.h \ include/pass2.h \ include/pass3.h \ include/pass4.h \ include/pass5.h \ include/problem.h \ include/refcount.h \ include/slot_recovery.h \ include/strings.h \ include/util.h OBJS = $(subst .c,.o,$(CFILES)) MANS = fsck.ocfs2.8 fsck.ocfs2.checks.8 DIST_FILES = $(CFILES) $(HFILES) $(addsuffix .in,$(MANS)) DIST_RULES = dist-subdircreate dist-subdircreate: $(TOPDIR)/mkinstalldirs $(DIST_DIR)/include fsck.ocfs2: $(OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LINK) $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) $(COM_ERR_LIBS) $(OBJS): prompt-codes.h # make it hard to add a prompt call # without documenting what it does prompt-codes.h: fsck.ocfs2.checks.8.in @echo generating $@ by parsing $^ @rm -f .$@.tmp @( echo '#ifndef __PROMPT_CODES_H__'; \ echo '#define __PROMPT_CODES_H__'; \ for a in `grep '^.SS ".*"' $^ | awk -F\" '{print $$2}'`; do\ echo '#define PR_'$$a' \'; \ echo ' (struct prompt_code){ .str = "'$$a'" }';\ done; \ echo '#endif'; \ ) > $@ .PHONY: check-prompt-dups check-prompt-dups: fsck.ocfs2 @rm -f .$@.tmp @nm $^ | \ awk -F'[ .]' '/fsck_prompt_callers_with_code/ {print $$3}' | \ sort | uniq -c | awk '($$1 > 1){print $$0}' > .$@.tmp @cat .$@.tmp @test ! -s .$@.tmp CLEAN_RULES += o2fsck-clean .PHONY: o2fsck-clean o2fsck-clean: rm -f prompt-codes.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/fsck.ocfs2/fsck.ocfs2.80000664000176100017610000001042611515641632014762 00000000000000.TH "fsck.ocfs2" "8" "September 2010" "Version 1.6.4" "OCFS2 Manual Pages" .SH "NAME" fsck.ocfs2 \- Check an \fIOCFS2\fR file system. .SH "SYNOPSIS" \fBfsck.ocfs2\fR [ \fB\-pafFGnuvVy\fR ] [ \fB\-b\fR \fIsuperblock block\fR ] [ \fB\-B\fR \fIblock size\fR ] \fIdevice\fR .SH "DESCRIPTION" .PP \fBfsck.ocfs2\fR is used to check an OCFS2 file system. \fIdevice\fR is the file where the file system is stored (e.g. \fI/dev/sda1\fR). It will almost always be a device file but a regular file will work as well. .SH "OPTIONS" .TP \fB\-a\fR This option does the same thing as the \fB-p\fR option. It is provided for backwards compatibility only: it is suggested that people use the \fB-p\fR option whenever possible. .TP \fB\-b\fR \fIsuperblock block\fR Normally, \fBfsck.ocfs2\fR will read the superblock from the first block of the device. This option specifies an alternate block that the superblock should be read from. (Use \fB\-r\fR instead of this option.) .TP \fB\-B\fR \fIblocksize\fR The \fIblock size\fR, specified in bytes, can range from 512 to 4096. A value of 0, the default, is used to indicate that the blocksize should be automatically detected. .TP \fB\-D\fR Optimize directories in filesystem. This option causes fsck.ocfs2 to coalesce the directory entries in order to improve the filesystem performance. .TP \fB\-f\fR Force checking even if the file system is clean. .TP \fB\-F\fR By default \fBfsck.ocfs2\fR will check with the cluster services to ensure that the volume is not in-use (mounted) on any node in the cluster before proceeding. \fB-F\fR skips this check and should only be used when it can be guaranteed that the volume is not mounted on any node in the cluster. \fBWARNING: If the cluster check is disabled and the volume is mounted on one or more nodes, file system corruption is very likely. If unsure, do not use this option.\fR .TP \fB\-G\fR Usually \fBfsck.ocfs2\fR will silently assume inodes whose generation number does not match the generation number of the super block are unused inodes. This option causes \fBfsck.ocfs2\fR to ask the user if these inodes should in fact be marked unused. .TP \fB\-n\fR Give the 'no' answer to all questions that fsck will ask. This guarantees that the file system will not be modified and the device will be opened read-only. The output of \fBfsck.ocfs2\fR with this option can be redirected to produce a record of a file system's faults. .TP \fB\-p\fR Automatically repair ("preen") the file system. This option will cause \fBfsck.ocfs2\fR to automatically fix any problem that can be safely corrected without human intervention. If there are problems that require intervention, the descriptions will be printed and fsck.ocfs2 will exit with the value 4 logically or'd into the exit code. (See the \fBEXIT CODE\fR section.) This option is normally used by the system's boot scripts. .TP \fB\-r\fR \fIbackup-number\fR \fImkfs.ocfs2\fR makes upto 6 backup copies of the superblock at offsets 1G, 4G, 16G, 64G, 256G and 1T depending on the size of the volume. Use this option to specify the backup, 1 thru 6, to use to recover the superblock. .TP \fB\-y\fR Give the 'yes' answer to all questions that fsck will ask. This will repair all faults that \fBfsck.ocfs2\fR finds but will not give the operator a chance to intervene if \fBfsck.ocfs2\fR decides that it wants to drastically repair the file system. .TP \fB\-v\fR This option causes \fBfsck.ocfs2\fR to produce a very large amount of debugging output. .TP \fB\-V\fR Print version information and exit. .SH EXIT CODE The exit code returned by \fBfsck.ocfs2\fR is the sum of the following conditions: .br \ 0\ \-\ No errors .br \ 1\ \-\ File system errors corrected .br \ 2\ \-\ File system errors corrected, system should .br \ \ \ \ be rebooted .br \ 4\ \-\ File system errors left uncorrected .br \ 8\ \-\ Operational error .br \ 16\ \-\ Usage or syntax error .br \ 32\ \-\ fsck.ocfs2 canceled by user request .br \ 128\ \-\ Shared library error .br .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR debugfs.ocfs2(8) .BR tunefs.ocfs2(8) .BR mounted.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation. This man page entry derives some text, especially the exit code summary, from .BR e2fsck(8) by Theodore Y. Ts'o . .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/fsck.ocfs2/fsck.ocfs2.checks.80000664000176100017610000012702311515641632016223 00000000000000.TH "fsck.ocfs2.checks" "8" "September 2010" "Version 1.6.4" "OCFS2 Manual Pages" .SH "NAME" fsck.ocfs2.checks \- Consistency checks that .BR fsck.ocfs2(8) performs and its means for fixing inconsistencies. .SH "DESCRIPTION" .PP .BR fsck.ocfs2(8) is used to check an OCFS2 file system. It performs many consistency checks and will offer to fix faults that it finds. This man page lists the problems it may find and describes their fixes. The problems are indexed by the error number that .BR fsck.ocfs2(8) emits when it describes the problem and asks if it should be fixed. The prompts are constructed such that answering 'no' results in no changes to the file system. This may result in errors later on that stop .BR fsck.ocfs2(8) from proceeding. .SH "CHECKS" \" escape.c .SS "EB_BLKNO" Extent blocks contain a record of the disk block where they are located. An extent block was found at a block that didn't match its recorded location. Answering yes will update the data structure in the extent block to reflect its real location on disk. .SS "EB_GEN" Extent blocks are created with a generation number to match the generation number of the volume at the time of creation. An extent block was found which contains a generation number that doesn't match. Answering yes implies that the generation number is correct and that the extent block is from a previous file system. The extent block will be ignored and the file that contains it will lose the data it referenced. .SS "EB_GEN_FIX" Extent blocks are created with a generation number to match the generation number of the volume at the time of creation. An extent block was found which contains a generation number that doesn't match. Answering yes implies that the generation number in the extent block is incorrect and that the extent block is valid. The generation number in the block is updated to match the generation number in the volume. .SS "EXTENT_MARKED_UNWRITTEN" An extent record has the UNWRITTEN flag set, but the filesystem feature set does not include unwritten extents. Answering yes clears the UNWRITTEN flag. This is safe to do; as the feature is disabled anyway. .SS "EXTENT_MARKED_REFCOUNTED" An extent record has the REFCOUNTED flag set, but neither the filesystem nor the file has the REFCOUNTED flag set. Answering yes clears the REFCOUNTED flag. .SS "EXTENT_BLKNO_UNALIGNED" The block that marks the start of an extent should always fall on the start of a cluster. An extent was found that starts part-way into a cluster. Answering yes moves the start of the extent back to the start of the addressed cluster. This may add data to the middle of the file that contains this extent. .SS "EXTENT_CLUSTERS_OVERRUN" An extent was found which claims to contain clusters which are beyond the end of the volume. Answering yes clamps the extent to the end of the volume. This may result in a reduced file size for the file that contains the extent, but it couldn't have addressed those final clusters anyway. One can imagine this problem arising if there are problems shrinking a volume. .SS "EXTENT_EB_INVALID" Deep extent trees are built by forming a tree out of extent blocks. An extent tree references an invalid extent block. Answering yes stops the tree from referencing the invalid extent block. This may truncate data from the file which contains the tree. .SS "EXTENT_LIST_DEPTH" Extent lists contain a record of their depth in the tree. An extent list was found whose recorded depth doesn't match the position they have in the tree. Answering yes updates the depth field in the list to match the tree on disk. .SS "EXTENT_LIST_COUNT" The number of entries in an extent list is bounded by either the size of the inode or the size of the block which contains it. An extent list was found which claims to have more entries than would fit in its container. Answering yes updates the count field in the extent list to match the container. Answering no to this question may stop further fixes from being done because the count value can not be trusted. .SS "EXTENT_LIST_FREE" The number of free entries in an extent list must be less than the total number of entries in the list. A list was found which claims to have more free entries than possible entries. Answering yes sets the number of free entries in the list equal to the total possible entries. .SS "EXTENT_BLKNO_RANGE" An extent record was found which references a block which can not be referenced by an extent. The referenced block is either very early in the volume, and thus reserved, or beyond the end of the volume. Answering yes removes this extent record from the tree. This may remove data from the file which owns the tree but any such data was inaccessible. .SS "CHAIN_CPG" The bitmap inode indicates a different clusters per group than the group descriptor. This value is typically static and only modified by tunefs during volume resize and that too only on volumes having only one cluster group. Answering yes updates the clusters per group on the bitmap inode to the corresponding value in the group descriptor. .SS "SUPERBLOCK_CLUSTERS" The super block indicates a different total clusters value than the global bitmap. This is only possible due to a failed volume resize operation. Answering yes updates the total clusters in the super block to the value specified in the global bitmap. .SS "FIXED_CHAIN_CLUSTERS" The global bitmap inode was repaired, resulting in a change to the total cluster count of the filesystem. Answering yes updates the total clusters in the super block to the value specified in the global bitmap. \" pass0.c .SS "GROUP_UNEXPECTED_DESC" The group descriptors that make up the global bitmap chain allocator reside at predictable locations on disk. A group descriptor was found in the global bitmap allocator which isn't at one of these locations and so shouldn't be in the allocator. Answering yes removes this descriptor from the global bitmap allocator. .SS "GROUP_EXPECTED_DESC" The group descriptors that make up the global bitmap chain allocator reside at predictable locations on disk. A group descriptor at one of these locations was not linked into the global bitmap allocator. Answering yes will relink this group into the allocator. .SS "GROUP_GEN" A group descriptor was found with a generation number that doesn't match the generation number of the volume. Answering yes sets the group descriptor's generation equal to the generation number in the volume. .SS "GROUP_PARENT" Group descriptors contain a pointer to the allocator inode which contains the chain they belong to. A group descriptor was found in an allocator inode that doesn't match the descriptor's parent pointer. Answering yes updates the group descriptor's parent pointer to match the inode it resides in. .SS "GROUP_DUPLICATE" Group descriptors contain a pointer to the allocator inode which contains the chain they belong to. A group descriptor was found in two allocator inodes so it may be duplicated. Answering yes removes the group descriptor from current allocator inode. .SS "GROUP_BLKNO" Group descriptors have a field which records their block location on disk. A group descriptor was found at a given location but is recorded as being located somewhere else. Answering yes updates the group descriptor's recorded location to match where it actually is found on disk. .SS "GROUP_CHAIN" Group descriptors are found in a number of different singly-linked chains in an allocator inode. A group descriptor records the chain number that it is linked in. A group descriptor was found whose chain field doesn't match the chain it was found in. Answering yes sets the group descriptor's chain field to match the chain it is found in. .SS "GROUP_FREE_BITS" A group descriptor records the number of bits in its bitmap that are free. A group descriptor was found which claims to have more free bits than are valid in its bitmap. Answering yes decreases the number of recorded free bits so that it equals the total number of bits in the group descriptor's bitmap. .SS "CHAIN_COUNT" The chain list embedded in an inode is limited by the block size and the number of bytes consumed by the rest of the inode. A chain list header was found which claimed that there are more entries in the list then could fit in the inode. Answering yes resets the header's cl_count member to the maximum size allowed by the block size after accounting for the space consumed by the inode. .SS "CHAIN_NEXT_FREE" This is identical to CHAIN_COUNT except that it is testing and fixing the pointer to the next free list entry recorded in the cl_next_free_rec member instead of the total number of entries. .SS "CHAIN_EMPTY" Chain entries need to be packed such that there are no chains without descriptors found before the chain that is marked as free by the chain header. A chain without descriptors was found found before that chain that was marked free. Answering yes will remove the unused chain and shift the remaining chains forward in the list. .SS "CHAIN_I_CLUSTERS" Chain allocator inodes have an i_clusters value that represents the number of clusters used by the allocator. An inode was found whose i_clusters value doesn't match the number of clusters its chains cover. Answering yes updates i_clusters in the inode to reflect what was actually found by walking the chain. .SS "CHAIN_I_SIZE" Chain allocator inodes multiply the number of bytes per cluster by the their i_clusters value and store it in i_size. An inode was found which didn't have the correct value in its i_size. Answering yes updates i_size to be the product of i_clusters and the cluster size. Nothing else uses this value, and previous versions of tools didn't calculate it properly, so don't be too worried if this error appears. .SS "CHAIN_GROUP_BITS" The inode that contains an embedded chain list has fields which record the total number of bits covered by the chain as well as the amount free. These fields didn't match what was found in the chain. Answering yes updates the fields in the inode to reflect what was actually found by walking the chain. .SS "CHAIN_HEAD_LINK_RANGE" The header that starts a chain tried to reference a group descriptor at a block number that couldn't be valid. Answering yes will clear the reference to this invalid block and truncate the chain that it started. .SS "CHAIN_LINK_GEN" A reference was made to a group descriptor whose generation number doesn't match the generation of the volume. Answering yes to this question implies that the group descriptor is invalid and the chain is truncated at the point that it referred to this invalid group descriptor. Answering no to this question considers the group descriptor as valid and its generation may be fixed. .SS "CHAIN_LINK_MAGIC" Chains are built by chain headers and group descriptors which are linked together by block references. A reference was made to a group descriptor at a given block but a valid group descriptor signature wasn't found at that block. Answering yes clears the reference to this invalid block and truncates the chain at the point of the reference. .SS "CHAIN_LINK_RANGE" Chains are built by chain headers and group descriptors which are linked together by block references. A reference a block was found which can't possibly be valid because it was either too small or extended beyond the volume. Answering yes truncates the chain in question by zeroing the invalid block reference. This shortens the chain in question and could result in more fixes later if the part of the chain that couldn't be referenced was valid at some point. .SS "CHAIN_BITS" A chain's header contains members which record the total number of bits in the chain as well as the number of bits that are free. After walking through a chain it was found that the number of bits recorded in its header don't match what was found by totalling up the group descriptors. Answering yes updates the c_total and c_free members of the header to reflect what was found in the group descriptors in the chain. .SS "DISCONTIG_BG_DEPTH" A discontiguous block group has an extent list which records all the clusters allocated to it. Discontiguous block groups only support extent lists with a tree depth of 0. A block group claims to have a tree depth greater than 0. Answering yes will set the tree depth of the extent list to 0. .SS "DISCONTIG_BG_COUNT" A discontiguous block group has an extent list which records all the clusters allocated to it. A block group claims to have more records than can actually fit. Answering yes will set the record count to the maximum possible. .SS "DISCONTIG_BG_REC_RANGE" Block groups set aside clusters to be used for metadata. A discontiguous block group claims to contain clusters beyond the end of the volume. Answering yes will remove the block group. .SS "DISCONTIG_BG_CORRUPT_LEAVES" A discontiguous block group has an extent list which records all the clusters allocated to it. A group has more than one extent claiming to have an impossible number of clusters. Answering yes will remove the block group. .SS "DISCONTIG_BG_CLUSTERS" Extent records in a discontiguous block group were found having more clusters allocated then a block group can have. Answering yes will remove the block group. .SS "DISCONTIG_BG_LESS_CLUSTERS" Extent records in a discontiguous block group were found having less clusters allocated then a block group can have. Answering yes will remove the block group. .SS "DISCONTIG_BG_NEXT_FREE_REC" A discontiguous block group has an extent list which records all the clusters allocated to it. A group was found with fewer filled in extents than it claims to have. The filled in extents describe a complete and correct group. Answering yes will set the used extent count to the number of filled extents. .SS "DISCONTIG_BG_LIST_CORRUPT" A discontiguous block group has an extent list which records all the clusters allocated to it. The group claims to have more extents than is possible, and the existing extents contain errors. Answering yes will remove the block group. .SS "DISCONTIG_BG_REC_CORRUPT" A discontiguous block group has a extent list which records all the clusters allocated to it. A group was found with one extent claiming too many clusters but the sum of the remaining extents are equal to the total clusters a group must have. Answering yes will remove the block group. .SS "DISCONTIG_BG_LEAF_CLUSTERS" A discontiguous block group has a extent list which records all the clusters allocated to it. A group was found with one extent claiming too many clusters, but the remaining extents are correct. Answering yes will set the number of the clusters on the broken extent to the difference between the total clusters a group must have and the sum of the remaining extents. \" pass1.c .SS "INODE_ALLOC_REPAIR" The inode allocator did not accurately reflect the set of inodes that are free and in use in the volume. Answering yes will update the inode allocator bitmaps. Each bit that doesn't match the state of its inode will be inverted. .SS "INODE_SUBALLOC" Each inode records the node whose allocator is responsible for the inode. An inode was found in a given node's allocator but the inode itself claimed to belong to a different node. Answering yes will correct the inode to point to the node's allocator that it belongs to. .SS "LALLOC_SIZE" Each node has a local allocator contained in a block that is used to allocate clusters in batches. A node's local allocator claims to reflect more bytes than are possible for the volume's block size. Answering yes decreases the local allocator's size to reflect the volume's block size. .SS "LALLOC_NZ_USED" A given node's local allocator isn't in use but it claims to have bits in use in its bitmap. Answering yes zeros this used field. .SS "LALLOC_NZ_BM" A given node's local allocator isn't in use but it has a field which records the bitmap as starting at a non-zero cluster offset. Answering yes zeros the bm_off field. .SS "LALLOC_BM_OVERRUN" Each local allocator contains a reference to the first cluster that its bitmap addresses. A given local allocator was found which references a starting cluster that is beyond the end of the volume. Answering yes resets the given local allocator. No allocated data will be lost. .SS "LALLOC_BM_SIZE" The given local allocator claims to cover more bits than are possible for the size in bytes of its bitmap. Answering yes decreases the number of bits the allocator covers to reflect the size in bytes of the bitmap and resets the allocator. No allocated data will be lost. .SS "LALLOC_BM_STRADDLE" The given local allocator claims to cover a region of clusters which extents beyond the end of the volume. Answering yes resets the given local allocator. No allocated data will be lost. .SS "LALLOC_USED_OVERRUN" The given local allocator claims to have more bits in use than it has total bits in its bitmap. Answering yes decreases the number of bits used so that it equals the total number of available bits. .SS "LALLOC_CLEAR" A local allocator inode was found to have problems. This gives the operator a chance to just reset the local allocator inode. Answering yes clears the local allocator. No information is lost but the global bitmap allocator may need to be updated to reflect clusters that were reserved for the local allocator but were free. .SS "DEALLOC_COUNT" The given truncate log inode contains a count that is greater than the value that is possible given the size of the inode. Answering yes resets the count value to the possible maximum. .SS "DEALLOC_USED" The given truncate log inode claims to have more records in use than it is possible to store in the inode. Answering yes resets the record of the number used to the maximum value possible. .SS "TRUNCATE_REC_START_RANGE" A truncate record was found which claims to start at a cluster that is beyond the number of clusters in the volume. Answering yes will clear the truncate record. This may result in previously freed space being marked as allocated. This will be fixed up later as the allocator is updated to match what is used by the file system. .SS "TRUNCATE_REC_WRAP" Clusters are recorded as 32bit values. A truncate record was found which claims to have enough clusters to cause this value to wrap. This could never be the case and is a sure sign of corruption. Answering yes will clear the truncate record. This may result in previously freed space being marked as allocated. This will be fixed up later as the allocator is updated to match what is used by the file system. .SS "TRUNCATE_REC_RANGE" A truncate record was found which claims to reference a region of clusters which partially extends beyond the number of clusters in the volume. Answering yes will clear the truncate record. This may result in previously freed space being marked as allocated. This will be fixed up later as the allocator is updated to match what is used by the file system. .SS "INODE_GEN" Inodes are created with a generation number to match the generation number of the volume at the time of creation. An Inode was found which contains a generation number that doesn't match. Answering yes implies that the generation number is correct and that the inode is from a previous file system. The inode will be recorded as free. .SS "INODE_GEN_FIX" Inodes are created with a generation number to match the generation number of the volume at the time of creation. An inode was found which contains a generation number that doesn't match. Answering yes implies that the generation number in the inode is incorrect and that the inode is valid. The generation number in the inode is updated to match the generation number in the volume. .SS "INODE_BLKNO" Inodes contain a field that must match the block that they reside in. An inode was found at a block that doesn't match the field in the inode. Answering yes updates the field to match the inode's position on disk. .SS "ROOT_NOTDIR" The super block contains a reference to the inode that contains the root directory. This block was found to contain an inode that isn't a directory. Answering yes clears this inode. The operator will be asked to recreate the root directory at a point in the near future. .SS "INODE_NZ_DTIME" Inodes contain a field describing the time at which they were deleted. This can not be set for an inode that is still in use. An inode was found which is in use but which contains a non-zero dtime. Answering yes implies that the inode is still valid and resets its dtime to zero. .SS "LINK_FAST_DATA" The target name for a symbolic link is stored either as file contents for that inode or in the inode structure itself on disk. Only small destination names are stored in the inode structure. The i_blocks field of the inode indicates that the name is stored in the inode when it is zero. An inode was found that has both i_blocks set to zero and file contents. Answering yes clears the inode and so deletes the link. .SS "LINK_NULLTERM" The targets of links on disk must be null terminated. A link was found whose target wasn't null terminated. Answering yes clears the inode and so deletes the link. .SS "LINK_SIZE" The size of a link on disk must match the length of its target string. A link was found whose size does not. Answering yes updates the link's size to reflect the length of its target string. .SS "LINK_BLOCKS" Links can not be sparse. There must be exactly as many blocks allocated as are needed to cover its size. A link was found which doesn't have enough blocks allocated to cover its size. Answering yes clears the link's inode thus deleting the link. .SS "DIR_ZERO" Directories must at least contain a block that has the "." and ".." entries. A directory was found which doesn't contain any blocks. Answering yes to this question clears the directory's inode thus deleting the directory. .SS "INODE_SIZE" Certain inodes record the size of the data they reference in an i_size field. This can be the number of bytes in a file, directory, or symlink target which are stored in data mapped by extents of clusters. This error occurs when the extent lists are walked and the amount of data found does not match what is stored in i_size. Answering yes to this question updates the inode's i_size to match the amount of data referenced by the extent lists. It is vitally important that i_size matches the extent lists and so answering yes is strongly encouraged. .SS "INODE_SPARSE_SIZE" Certain inodes record the size of the data they reference in an i_size field. This can be the number of bytes in a file, directory, or symlink target which are stored in data mapped by extents of clusters. This error occurs when a sparse inode was found that had data allocated past its i_size. Answering yes to this question will update the inode's i_size to cover all of its allocated storage. It is vitally important that i_size matches the extent lists and so answering yes is strongly encouraged. .SS "INODE_INLINE_SIZE" Inodes can only fit a certain amount of inline data. This inode has its data inline but claims an i_size larger than will actually fit. Answering yes to this question updates the inode's i_size to the maximum available inline space. .SS "INODE_CLUSTERS" Inodes contain a record of how many clusters are allocated to them. An inode was found whose recorded number of clusters doesn't match the number of blocks that were found associated with the inode. Answering yes resets the inode's number of clusters to reflect the number of blocks that were associated with the file. .SS "INODE_SPARSE_CLUSTERS" Inodes contain a record of how many clusters are allocated to them. An sparse inode was found whose recorded number of clusters doesn't match the number of blocks that were found associated with the inode. Answering yes resets the inode's number of clusters to reflect the number of blocks that were associated with the file. .SS "INODE_INLINE_CLUSTERS" Inlined inode should not have allocated clusters. An inode who has inline data flag set was found with clusters allocated. Answering yes resets the inode's number of clusters to zero. .SS "LALLOC_REPAIR" An active local allocator did not accurately reflect the set of clusters that are free and in use in its region. Answering yes will update the local allocator bitmap. Each bit that doesn't match the use of its cluster will be inverted. .SS "LALLOC_USED" A local allocator records the number of bits that are used in its bitmap. An allocator was found whose used value doesn't reflect the number of bits that are set in its bitmap. Answering yes sets the used value to match the number of bits set in the allocator's bitmap. .SS "CLUSTER_ALLOC_BIT" A specific cluster's use didn't match the setting of its bit in the cluster allocator. Answering yes will invert the bit in the allocator to match the use of the cluster -- either allocated and in use or free. .SS "REFCOUNT_FLAG_INVALID" Refcount file can only exist in a volume with refcount supported, Fsck has found that a file in a non-refcount volume has refcount flag set. Answering yes remove this flag from the file. .SS "REFCOUNT_LOC_INVALID" Refcount loc can only be valid if the file has refcount flag set. Fsck has found that a file has refcount loc while it does't have refcount flag set. Answering yes reset refcount loc to zero for the file. .SS "RB_BLKNO" refcount blocks contain a record of the disk block where they are located. An refcount block was found at a block that didn't match its recorded location. Answering yes will update the data structure in the refcount block to reflect its real location on disk. .SS "RB_GEN" Refcount blocks are created with a generation number to match the generation number of the volume at the time of creation. An refcount block was found which contains a generation number that doesn't match. Answering yes implies that the generation number is correct and that the refcount block is from a previous file system. The refcount block will be removed and the file that uses it will lose the refcounted information, but it may be regenerated later. .SS "RB_GEN_FIX" Refcount blocks are created with a generation number to match the generation number of the volume at the time of creation. An refcount block was found which contains a generation number that doesn't match. Answering yes implies that the generation number in the refcount block is incorrect and that the refcount block is valid. The generation number in the block is updated to match the generation number in the volume. .SS "RB_PARENT" refcount blocks contain a record of the parent this disk block belongs to. An refcount block was found storing a wrong parent location. Answering yes will update the data structure in the refcount block to reflect its parent's real location on disk. .SS "REFCOUNT_LIST_COUNT" The number of entries in a refcount list is bounded by the size of the block which contains it. An refcount list was found which claims to have more entries than would fit in its container. Answering yes updates the count field in the refcount list to match the container. Answering no to this question may stop further fixes from being done because the count value can not be trusted. .SS "REFCOUNT_LIST_USED" The number of free entries in a refcount list must be less than the total number of entries in the list. A list was found which claims to have more free entries than possible entries. Answering yes sets the number of free entries in the list equal to the total possible entries. .SS "REFCOUNT_CLUSTER_RANGE" A refcount record was found which references a cluster which can not be referenced by a refcount. The referenced cluster is either very early in the volume, and thus reserved, or beyond the end of the volume. Answering yes removes this refcount record from the tree. .SS "REFCOUNT_CLUSTER_COLLISION" A refcount record was found which references a cluster which has a collision with the previous valid refcount record. Answering yes removes this refcount record from the tree. .SS "REFCOUNT_LIST_EMPTY" A refcount list was found which has no refcount record in it. It is normally caused by a corrupted refcount record. Answering yes removes this refcount block from the tree. It will be re-generated in refcounted extent records handler if all the other information is sane. .SS "REFCOUNT_BLOCK_INVALID" Refcount block stores the refcount record for physical clusters of a file. It is found refering an invalid refcount block. Answering yes remove this refcount block. .SS "REFCOUNT_CLUSTERS" Refcount tree contains a record of how many clusters are allocated to them. A tree was found whose recorded number of clusters doesn't match the number of blocks that were found associated with it. Answering yes resets the number of clusters to reflect the real number of clusters that were associated with the tree. .SS "REFCOUNT_ROOT_BLOCK_INVALID" Root refcount block is the root of the refcount record for a file. It is found refering an invalid refcount block. Answering yes remove this refcount block and clear refcount flag from this file. .SS "REFCOUNT_REC_REDUNDANT" Refcount record is used to store the refcount for physical clusters. Some refcount record is found to have no physical clusters corresponding to it. Answering yes remove the refcount record. .SS "REFCOUNT_COUNT_INVALID" Refcount record is used to store the refcount for physical clusters. A record record is found whichs claims the wrong refcount for some physical clusters. Answering yes update the corresponding refcount record. .SS "REFCOUNT_COUNT" Refcount tree contains a record of how many files refering to this tree. A tree was found whose recorded number of files doesn't match the real files refering to the tree. Answering yes resets the number of files to reflect the real number of files that were associated with the tree. \" pass1b.c .SS "DUP_CLUSTERS_SYSFILE_CLONE" A system file inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. System files may be cloned but may not be deleted. Allocation system files may not be cloned or deleted. Answering yes will copy the data of this inode to newly allocated extents. This will break the claim on the overcommitted clusters. .SS "DUP_CLUSTERS_CLONE" An inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. Answering yes will copy the data of this inode to newly allocated extents. This will break the claim on the overcommitted clusters. .SS "DUP_CLUSTERS_DELETE" An inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. Answering yes will remove this inode, thus breaking its claim on the overcommitted clusters. .SS "DUP_CLUSTERS_ADD_REFCOUNT" An inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. Answering yes will try to add a refcount record for all these inodes, so that they will share the cluster. \" pass2.c .SS "DIRENT_DOTTY_DUP" There can be only one instance of both the "." and ".." entries in a directory. A directory entry was found which duplicated one of these entries. Answering yes will remove the duplicate directory entry. .SS "DIRENT_NOT_DOTTY" The first and second directory entries in a directory must be "." and ".." respectively. One of these directory entries was found to not match these rules. Answering yes will force the directory entry to be either "." or "..". This might consume otherwise valid entries and cause some files to appear in lost+found. .SS "DIRENT_DOT_INODE" The inode field of the "." directory entry must refer to the directory inode that contains the given directory block. A "." entry was found which doesn't do so. Answering yes sets the directory entry's inode reference to the parent directory that contains the entry. .SS "DIRENT_DOT_EXCESS" A "." directory entry was found whose lengths exceeds the amount required for the single dot in the name. Answering yes creates another empty directory entry in this excess space. .SS "DIRENT_ZERO" A directory entry was found with a zero length name. Answering yes clears the directory entry so its space can be reused. .SS "DIRENT_NAME_CHARS" Directory entries can not contain either the NULL character (ASCII 0) or the forward slash (ASCII 47). A directory entry was found which contains either. Answering yes will change each instance of these forbidden characters into a period (ASCII 46). .SS "DIRENT_INODE_RANGE" Each directory entry contains a inode field which the entry's name corresponds to. An entry was found which referenced an inode number that is invalid for the current volume. Answering yes clears this entry so its space can be reused. If the entry once corresponded to a real inode and was corrupted this inode may appear in lost+found. .SS "DIRENT_INODE_FREE" Each directory entry contains a inode field which the entry's name corresponds to. An entry was found which referenced an inode number that isn't in use. Answering yes clears this directory entry. .SS "DIRENT_TYPE" Each directory entry contains a field which describes the type of file that the entry refers to. An entry was found whose type doesn't match the inode it is referring to. Answering yes resets the entry's type to match the target inode. .SS "DIR_PARENT_DUP" Each directory can only be pointed to by one directory entry in a parent directory. A directory entry was found which was the second entry to point to a given directory inode. Answering yes clears this entry which was the second to refer to a given directory. This reflects the policy that hard links to directories are not allowed. .SS "DIRENT_DUPLICATE" File names within a directory must be unique. A file name occurred in more than one directory entry in a given directory. Answering yes renames the duplicate entry to a name that doesn't collide with recent entries and is unlikely to collide with future entries in the directory. .SS "DIRENT_LENGTH" There are very few directory entry lengths that are valid. The lengths must be greater than the minimum required to record a single character directory, be rounded to 12 bytes, be within the amount of space remaining in a directory block, and be properly rounded for the size of the name of the directory entry. An entry was found which didn't meet these criteria. Answering yes will try to repair the directory entry. This runs a very good chance of invalidating all the entries in the directory block. Orphaned inodes may appear in lost+found. .SS "DIR_TRAILER_INODE" A directory block trailer is a fake directory entry at the end of the block. The trailer has compatibility fields for when it is viewed as a directory entry. The inode field must be zero. Answering yes will set the inode field to zero. .SS "DIR_TRAILER_NAME_LEN" A directory block trailer is a fake directory entry at the end of the block. The trailer has compatibility fields for when it is viewed as a directory entry. The name length field must be zero. Answering yes will set the name length field to zero. .SS "DIR_TRAILER_REC_LEN" A directory block trailer is a fake directory entry at the end of the block. The trailer has compatibility fields for when it is viewed as a directory entry. The record length field must be equal to the size of the trailer. Answering yes will set the record length field to the size of the trailer. .SS "DIR_TRAILER_BLKNO" A directory block trailer is a fake directory entry at the end of the block. The self-referential block number is incorrect. Answering yes will set the block number to the correct block on disk. .SS "DIR_TRAILER_PARENT_INODE" A directory block trailer is a fake directory entry at the end of the block. It has a pointer to the directory inode it belongs to. This pointer is incorrect. Answering yes will set the parent inode pointer to the inode referencing this directory block. \" pass3.c .SS "ROOT_DIR_MISSING" The super block contains a reference to the inode that serves as the root directory. This reference points to an inode that isn't in use. Answering yes will create a new inode and update the super block to refer to this inode as the root directory. .SS "LOSTFOUND_MISSING" The super block contains a reference to the inode that serves as the lost+found directory. This reference points to an inode that isn't in use. Answering yes will create a new lost+found directory in the root directory. .SS "DIR_NOT_CONNECTED" Every directory in the file system should be reachable by a directory entry in its parent directory. This is verified by walking every directory in the system. A directory inode was found during this walk which doesn't have a parent directory entry. Answering yes moves this directory entry into the lost+found directory and gives it a name based on its inode number. .SS "DIR_DOTDOT" A directory inode's ".." directory entry must refer to the parent directory. A directory was found whose ".." doesn't refer to its parent. Answering yes will read the directory block for the given directory and update its ".." entry to reflect its parent. \" pass4.c .SS "INODE_NOT_CONNECTED" Most all inodes in the system should be referenced by a directory entry. An inode was found which isn't referred to by any directory entry. Answering yes moves this inode into the lost+found directory and gives it a name based on its inode number. .SS "INODE_COUNT" Each inode records the number of directory entries that refer to it. An inode was found whose recorded count doesn't match the number of entries that refer to it. Answering yes sets the inode's count to match the number of referring directory entries. .SS "INODE_ORPHANED" While files are being deleted they are placed in an internal directory. If the machine crashes while this is taking place the files will be left in this directory. Fsck has found an inode in this directory and would like to finish the job of truncating and removing it. Answering yes removes the file data associated with the inode and frees the inode. .SS "RECOVER_BACKUP_SUPERBLOCK" When \fIfsck.ocfs2\fR successfully uses the specified backup superblock, it provides the user with this option to overwrite the existing superblock with that backup. Answering yes will refresh the superblock from the backup. Answering no will only disable the copying of the backup superblock and will not effect the remaining \fIfsck.ocfs2\fR processing. .SS "ORPHAN_DIR_MISSING" While files are being deleted they are placed in an internal directory, named orphan directory. If an orphan directory does not exist, an OCFS2 volume cannot be mounted successfully. Fsck has found the orphan directory is missing and would like to create it for future use. Answering yes creates the orphan directory in the system directory. .SS "JOURNAL_FILE_INVALID" OCFS2 uses JDB for journalling and some journal files exist in the system directory. Fsck has found some journal files that are invalid. Answering yes to this question will regenerate the invalid journal files. .SS "JOURNAL_UNKNOWN_FEATURE" Fsck has found some journal files with unknown features. Other journals on the filesystem have only known features, so this is likely a corruption. If you think your filesystem may be newer than this version of fsck.ocfs2, say N here and grab the latest version of fsck.ocfs2. Answering yes resets the journal features to match other journals. .SS "JOURNAL_MISSING_FEATURE" Fsck has found some journal files have features that are not set on all journal files. All journals on filesystem should have the same set of features. Answering yes will set all journals to the union of set features. .SS "JOURNAL_TOO_SMALL" Fsck has found some journal files are too small. Answering yes extends these journals. .SS "RECOVER_CLUSTER_INFO" The currently active cluster stack is different than the one the filesystem is configured for. Thus, fsck.ocfs2 cannot determine whether the filesystem is mounted on an another node or not. The recommended solution is to exit and run fsck.ocfs2 on this device from a node that has the appropriate active cluster stack. However, you can proceed with the fsck if you are sure that the volume is not in use on any node. Answering yes reconfigures the filesystem to use the current cluster stack. DANGER: YOU MUST BE ABSOLUTELY SURE THAT NO OTHER NODE IS USING THIS FILESYSTEM BEFORE CONTINUING. OTHERWISE, YOU CAN CORRUPT THE FILESYSTEM AND LOSE DATA. .SS "INLINE_DATA_FLAG_INVALID" Inline file can only exist in a volume with inline supported, Fsck has found that a file in a non-inline volume has inline flag set. Answering yes remove this flag from the file. .SS "INLINE_DATA_COUNT_INVALID" For an inline file, there is a limit for id2.id_data.id_count. Fsck has found that this value isn't right. Answering yes change this value to the right number. .SS "XATTR_BLOCK_INVALID" Extended attributes are stored off an extended attribute block referenced by the inode. This inode references an invalid extended attribute block. Answering yes will remove this block. .SS "XATTR_COUNT_INVALID" The count of extended attributes in an inode, block, or bucket does not match the number of entries found by fsck. Answering yes will change this to the correct count. .SS "XATTR_ENTRY_INVALID" An extended attribute entry points to already used space. Answering yes will remove this entry. .SS "XATTR_NAME_OFFSET_INVALID" The name_offset field of an extended attribute entry is not correct. Without a correct name_offset field, the entry cannot be used. Answering yes will remove this entry. .SS "XATTR_VALUE_INVALID" The value region of an extended attribute points to already used space. Answering yes will remove this entry. .SS "XATTR_LOCATION_INVALID" The xe_local field and xe_value_size field of an extended attribute entry does not match. So the entry cannot be used. Answering yes will remove this entry. .SS "XATTR_HASH_INVALID" Extended attributes use a hash of their name for lookup purposes. The name_hash of this extended attribute entry is not correct. Answering yes will change this to the correct hash. .SS "XATTR_FREE_START_INVALID" Extended attributes use free_start to indicate the offset of the free space in inode, block, or bucket. The free_start field of this object is not correct. Answering yes will change this to the correct offset. .SS "XATTR_VALUE_LEN_INVALID" Extended attributes use name_value_len to store the total length of all entry's name and value in inode, block or bucket. the name_value_len filed of this object is not correct. Answering yes will change this to the correct value. .SS "XATTR_BUCKET_COUNT_INVALID" The count of extended attributes bucket pointed by one extent record does not match the number of buckets found by fsck. Answering yes will change this to the correct count. \" pass5.c .SS "QMAGIC_INVALID" The magic number in the header of quota file does not match the proper number. Answering yes will make fsck use values in the quota file header anyway. .SS "QTREE_BLK_INVALID" Block with references to other blocks with quota data is corrupted. Answering yes will make fsck use references in the block. .SS "DQBLK_INVALID" The structure with quota limits was found in a corrupted block. Answering yes will use the values of limits for the user / group. .SS "DUP_DQBLK_INVALID" The structure with quota limits was found in a corrupted block and fsck has already found quota limits for this user / group. Answering yes will use new values of limits for the user / group. .SS "DUP_DQBLK_VALID" The structure with quota limits was found in a correct block but fsck has already found quota limits for this user / group. Answering yes will use new values of limits for the user / group. .SS "IV_DX_TREE" A directory index was found on an inode but that feature is not enabled on the file system. Answering yes will truncate the invalid index. .SS "DX_LOOKUP_FAILED" A directory entry is missing an entry in the directory index. The missing index entry will cause lookups on this name to fail. Answering yes will rebuild the directory index, restoring the missing entry. .SH "SEE ALSO" .BR fsck.ocfs2(8) .SH "AUTHORS" Oracle Corporation. .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/fsck.ocfs2/fsck.c0000664000176100017610000006271511506552637014040 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * Roughly o2fsck performs the following operations. Each pass' file has * more details. * * journal.c: try and replay the journal for each node * pass0.c: make sure all the chain allocators are consistent * pass1.c: walk allocated inodes and verify them, including their extents * reflect valid inodes in the inode chain allocators * reflect allocated clusters in the cluster chain allocator * pass2.c: verify directory entries, record some linkage metadata * pass3.c: make sure all dirs are reachable * pass4.c: resolve inode's link counts, move disconnected inodes to lost+found * pass5.c: load global quota file, merge node-local quota files to global * quota file, recompute quota usage and recreate quota files * * When hacking on this keep the following in mind: * * - fsck -n is a good read-only on-site diagnostic tool. This means that fsck * _should not_ write to the file system unless it has asked prompt() to do * so. It should also not exit if prompt() returns 0. prompt() should give * as much detail as possible as it becomes an error log. * - to make life simpler, memory allocation is a fatal error. It would be * very exciting to have allocation failure trick fsck -y into tearing * apart the fs because it didn't have memorty to track what was in use. * We should have reasonable memory demands in relation to the size of * the fs. * - I'm still of mixed opinions about IO errors. For now they're fatal. * One needs to dd a volume off a busted device before fixing it. * thoughts? */ #include #include #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "fsck.h" #include "icount.h" #include "journal.h" #include "pass0.h" #include "pass1.h" #include "pass2.h" #include "pass3.h" #include "pass4.h" #include "pass5.h" #include "problem.h" #include "util.h" #include "slot_recovery.h" int verbose = 0; static char *whoami = "fsck.ocfs2"; static o2fsck_state _ost; static int cluster_locked = 0; static void mark_magical_clusters(o2fsck_state *ost); static void handle_signal(int sig) { switch (sig) { case SIGTERM: case SIGINT: printf("\nProcess Interrupted.\n"); if (cluster_locked && _ost.ost_fs->fs_dlm_ctxt) { ocfs2_release_cluster(_ost.ost_fs); cluster_locked = 0; } if (_ost.ost_fs->fs_dlm_ctxt) ocfs2_shutdown_dlm(_ost.ost_fs, whoami); if (_ost.ost_fs) ocfs2_close(_ost.ost_fs); exit(1); } return ; } /* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock */ static void block_signals(int how) { sigset_t sigs; sigfillset(&sigs); sigdelset(&sigs, SIGTRAP); sigdelset(&sigs, SIGSEGV); sigprocmask(how, &sigs, NULL); } static void print_usage(void) { fprintf(stderr, "Usage: fsck.ocfs2 {-y|-n|-p} [ -fGnuvVy ] [ -b superblock block ]\n" " [ -B block size ] [-r num] device\n" "\n" "Critical flags for emergency repair:\n" " -n Check but don't change the file system\n" " -y Answer 'yes' to all repair questions\n" " -p Automatic repair (no questions, only safe repairs)\n" " -f Force checking even if file system is clean\n" " -F Ignore cluster locking (dangerous!)\n" " -r restore backup superblock(dangerous!)\n" "\n" "Less critical flags:\n" " -b superblock Treat given block as the super block\n" " -B blocksize Force the given block size\n" " -G Ask to fix mismatched inode generations\n" " -u Access the device with buffering\n" " -V Output fsck.ocfs2's version\n" " -v Provide verbose debugging output\n" ); } static uint64_t read_number(const char *num) { uint64_t val; char *ptr; val = strtoull(num, &ptr, 0); if (!ptr || *ptr) return 0; return val; } extern int opterr, optind; extern char *optarg; static errcode_t o2fsck_state_init(ocfs2_filesys *fs, o2fsck_state *ost) { errcode_t ret; ret = o2fsck_icount_new(fs, &ost->ost_icount_in_inodes); if (ret) { com_err(whoami, ret, "while allocating inode icount"); return ret; } ret = o2fsck_icount_new(fs, &ost->ost_icount_refs); if (ret) { com_err(whoami, ret, "while allocating reference icount"); return ret; } ret = ocfs2_block_bitmap_new(fs, "directory inodes", &ost->ost_dir_inodes); if (ret) { com_err(whoami, ret, "while allocating dir inodes bitmap"); return ret; } ret = ocfs2_block_bitmap_new(fs, "regular file inodes", &ost->ost_reg_inodes); if (ret) { com_err(whoami, ret, "while allocating reg inodes bitmap"); return ret; } ret = ocfs2_cluster_bitmap_new(fs, "allocated clusters", &ost->ost_allocated_clusters); if (ret) { com_err(whoami, ret, "while allocating a bitmap to track " "allocated clusters"); return ret; } return 0; } errcode_t o2fsck_state_reinit(ocfs2_filesys *fs, o2fsck_state *ost) { errcode_t ret; ocfs2_bitmap_free(ost->ost_dir_inodes); ost->ost_dir_inodes = NULL; ocfs2_bitmap_free(ost->ost_reg_inodes); ost->ost_reg_inodes = NULL; ocfs2_bitmap_free(ost->ost_allocated_clusters); ost->ost_allocated_clusters = NULL; if (ost->ost_duplicate_clusters) { ocfs2_bitmap_free(ost->ost_duplicate_clusters); ost->ost_duplicate_clusters = NULL; } o2fsck_icount_free(ost->ost_icount_in_inodes); ost->ost_icount_in_inodes = NULL; o2fsck_icount_free(ost->ost_icount_refs); ost->ost_icount_refs = NULL; ret = o2fsck_state_init(fs, ost); if (ret) { com_err(whoami, ret, "while intializing o2fsck_state."); return ret; } mark_magical_clusters(ost); return 0; } static errcode_t check_superblock(o2fsck_state *ost) { struct ocfs2_dinode *di = ost->ost_fs->fs_super; struct ocfs2_super_block *sb = OCFS2_RAW_SB(di); errcode_t ret = 0; if (sb->s_max_slots == 0) { printf("The superblock max_slots field is set to 0.\n"); ret = OCFS2_ET_CORRUPT_SUPERBLOCK; } ost->ost_fs_generation = di->i_fs_generation; /* XXX do we want checking for different revisions of ocfs2? */ return ret; } static errcode_t write_out_superblock(o2fsck_state *ost) { struct ocfs2_dinode *di = ost->ost_fs->fs_super; struct ocfs2_super_block *sb = OCFS2_RAW_SB(di); if (sb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG) sb->s_feature_incompat &= ~OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG; if (sb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG) { sb->s_feature_incompat &= ~OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG; sb->s_tunefs_flag = 0; } if (ost->ost_num_clusters) di->i_clusters = ost->ost_num_clusters; sb->s_errors = ost->ost_saw_error; sb->s_lastcheck = time(NULL); sb->s_mnt_count = 0; return ocfs2_write_super(ost->ost_fs); } static void scale_time(time_t secs, unsigned *scaled, char **units) { if (secs < 60) { *units = "seconds"; goto done; } secs /= 60; if (secs < 60) { *units = "minutes"; goto done; } secs /= 60; if (secs < 24) { *units = "hours"; goto done; } secs /= 24; *units = "days"; done: *scaled = secs; } /* avoid "warning: `%c' yields only last 2 digits of year in some locales" */ static size_t ftso_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { return strftime(s, max, fmt, tm); } static int fs_is_clean(o2fsck_state *ost, char *filename) { struct ocfs2_super_block *sb = OCFS2_RAW_SB(ost->ost_fs->fs_super); time_t now = time(NULL); time_t next = sb->s_lastcheck + sb->s_checkinterval; static char reason[4096] = {'\0', }; struct tm local; if (ost->ost_force) strcpy(reason, "was run with -f"); else if ((OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG)) strcpy(reason, "incomplete volume resize detected"); else if ((OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG)) strcpy(reason, "incomplete tunefs operation detected"); else if (sb->s_state & OCFS2_ERROR_FS) strcpy(reason, "contains a file system with errors"); else if (sb->s_max_mnt_count > 0 && sb->s_mnt_count > sb->s_max_mnt_count) { sprintf(reason, "has been mounted %u times without being " "checked", sb->s_mnt_count); } else if (sb->s_checkinterval > 0 && now >= next) { unsigned scaled_time; char *scaled_units; scale_time(now - sb->s_lastcheck, &scaled_time, &scaled_units); sprintf(reason, "has gone %u %s without being checked", scaled_time, scaled_units); } if (reason[0]) { printf("%s %s, check forced.\n", filename, reason); return 0; } reason[0] = '\0'; if (sb->s_max_mnt_count > 0) sprintf(reason, "after %u additional mounts", sb->s_max_mnt_count - sb->s_mnt_count); if (sb->s_checkinterval > 0) { localtime_r(&next, &local); if (reason[0]) ftso_strftime(reason + strlen(reason), sizeof(reason) - strlen(reason), " or by %c, whichever comes first", &local); else ftso_strftime(reason, sizeof(reason), "by %c", &local); } printf("%s is clean.", filename); if (reason[0]) printf(" It will be checked %s.\n", reason); return 1; } static void print_label(o2fsck_state *ost) { unsigned char *label = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_label; size_t i, max = sizeof(OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_label); for(i = 0; i < max && label[i]; i++) { if (isprint(label[i])) printf("%c", label[i]); else printf("."); } if (i == 0) printf(""); printf("\n"); } static void print_uuid(o2fsck_state *ost) { unsigned char *uuid = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_uuid; size_t i, max = sizeof(OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_uuid); for(i = 0; i < max; i++) printf("%02X", uuid[i]); printf("\n"); } static void mark_magical_clusters(o2fsck_state *ost) { uint32_t cluster; cluster = ocfs2_blocks_to_clusters(ost->ost_fs, ost->ost_fs->fs_first_cg_blkno); if (cluster != 0) o2fsck_mark_clusters_allocated(ost, 0, cluster); } static void print_version(void) { fprintf(stderr, "%s %s\n", whoami, VERSION); } static errcode_t open_and_check(o2fsck_state *ost, char *filename, int open_flags, uint64_t blkno, uint64_t blksize) { errcode_t ret; ret = ocfs2_open(filename, open_flags, blkno, blksize, &ost->ost_fs); if (ret) { com_err(whoami, ret, "while opening \"%s\"", filename); goto out; } ret = check_superblock(ost); if (ret) { printf("fsck saw unrecoverable errors in the super block and " "will not continue.\n"); goto out; } out: return ret; } static errcode_t maybe_replay_journals(o2fsck_state *ost, char *filename, int open_flags, uint64_t blkno, uint64_t blksize) { int replayed = 0, should = 0, has_dirty = 0; errcode_t ret = 0; ret = o2fsck_should_replay_journals(ost->ost_fs, &should, &has_dirty); if (ret) goto out; ost->ost_has_journal_dirty = has_dirty ? 1 : 0; if (!should) goto out; if (!(ost->ost_fs->fs_flags & OCFS2_FLAG_RW)) { printf("** Skipping journal replay because -n was " "given. There may be spurious errors that " "journal replay would fix. **\n"); goto out; } printf("%s wasn't cleanly unmounted by all nodes. Attempting to " "replay the journals for nodes that didn't unmount cleanly\n", filename); /* journal replay is careful not to use ost as we only really * build it up after spraying the journal all over the disk * and reopening */ ret = o2fsck_replay_journals(ost->ost_fs, &replayed); if (ret) goto out; /* if the journals were replayed we close the fs and start * over */ if (!replayed) goto out; ret = ocfs2_close(ost->ost_fs); if (ret) { com_err(whoami, ret, "while closing \"%s\"", filename); goto out; } ret = open_and_check(ost, filename, open_flags, blkno, blksize); out: return ret; } /* * Do the slot recovery, replay truncate log, local aloc and orphan dir. * If there is any error, a force check is enabled. */ static errcode_t o2fsck_slot_recovery(o2fsck_state *ost) { errcode_t ret = 0; if (!(ost->ost_fs->fs_flags & OCFS2_FLAG_RW)) { printf("** Skipping slot recovery because -n was " "given. **\n"); goto out; } ret = o2fsck_replay_local_allocs(ost->ost_fs); if (ret) goto out; ret = o2fsck_replay_truncate_logs(ost->ost_fs); if (ret) goto out; /* * If the user want a force-check, orphan_dir will be * replayed after the full check. */ if (!ost->ost_force) { ret = o2fsck_replay_orphan_dirs(ost); if (ret) com_err(whoami, ret, "while trying to replay the orphan" " directory"); } out: return ret; } static errcode_t recover_backup_super(o2fsck_state *ost, char* device, int sb_num) { errcode_t ret; uint64_t offsets[OCFS2_MAX_BACKUP_SUPERBLOCKS], blksize, sb; ocfs2_filesys *fs = NULL; if (sb_num < 1 || sb_num > OCFS2_MAX_BACKUP_SUPERBLOCKS) return -1; ocfs2_get_backup_super_offsets(NULL, offsets, ARRAY_SIZE(offsets)); /* iterate all the blocksize to get the right one. */ for (blksize = OCFS2_MIN_BLOCKSIZE; blksize <= OCFS2_MAX_BLOCKSIZE; blksize <<= 1) { sb = offsets[sb_num - 1] / blksize; /* Here we just give the possible value of block num and * block size to ocfs2_open and this function will check * them and return '0' if they meet the right one. */ ret = ocfs2_open(device, OCFS2_FLAG_RW, sb, blksize, &fs); if (!ret) break; } if (ret) goto bail; /* recover the backup information to superblock. */ if (prompt(ost, PN, PR_RECOVER_BACKUP_SUPERBLOCK, "Recover superblock information from backup block" "#%"PRIu64"?", sb)) { fs->fs_super->i_blkno = OCFS2_SUPER_BLOCK_BLKNO; ret = ocfs2_write_primary_super(fs); if (ret) goto bail; } /* no matter whether the user recover the superblock or not above, * we should return 0 in case the superblock can be opened * without the recovery. */ ret = 0; bail: if (fs) ocfs2_close(fs); return ret; } static errcode_t recover_cluster_info(o2fsck_state *ost) { errcode_t ret; struct o2cb_cluster_desc disk = {NULL, NULL}, running = {NULL, NULL}; ret = o2cb_running_cluster_desc(&running); if (ret) goto bail; ret = ocfs2_fill_cluster_desc(ost->ost_fs, &disk); if (ret) goto bail; /* * If the disk matches the running cluster, there is nothing we * can fix. */ if ((!running.c_stack && !disk.c_stack) || (running.c_stack && running.c_cluster && disk.c_stack && disk.c_cluster && !strcmp(running.c_stack, disk.c_stack) && !strcmp(running.c_cluster, disk.c_cluster))) goto bail; /* recover the backup information to superblock. */ if (prompt(ost, PN, PR_RECOVER_CLUSTER_INFO, "The running cluster is using the %s stack%s%s, but " "the filesystem is configured for the %s stack%s%s. " "Thus, %s cannot determine whether the filesystem is in " "use. %s can reconfigure the filesystem to use the " "currently running cluster configuration. DANGER: " "YOU MUST BE ABSOLUTELY SURE THAT NO OTHER NODE IS " "USING THIS FILESYSTEM BEFORE MODIFYING ITS CLUSTER " "CONFIGURATION. Recover cluster configuration " "information the running cluster?", running.c_stack ? running.c_stack : "classic o2cb", running.c_stack ? " with the cluster name " : "", running.c_stack ? running.c_cluster : "", disk.c_stack ? disk.c_stack : "classic o2cb", disk.c_stack ? " with the cluster name " : "", disk.c_stack ? disk.c_cluster : "", whoami, whoami)) { ret = ocfs2_set_cluster_desc(ost->ost_fs, &running); if (ret) goto bail; } /* no matter whether the user recover the superblock or not above, * we should return 0 in case the superblock can be opened * without the recovery. */ ret = 0; bail: o2cb_free_cluster_desc(&running); o2cb_free_cluster_desc(&disk); return ret; } int main(int argc, char **argv) { char *filename; int64_t blkno, blksize; o2fsck_state *ost = &_ost; int c, open_flags = OCFS2_FLAG_RW | OCFS2_FLAG_STRICT_COMPAT_CHECK; int sb_num = 0; int fsck_mask = FSCK_OK; int slot_recover_err = 0; errcode_t ret; int mount_flags; int proceed = 1; memset(ost, 0, sizeof(o2fsck_state)); ost->ost_ask = 1; ost->ost_dirblocks.db_root = RB_ROOT; ost->ost_dir_parents = RB_ROOT; ost->ost_refcount_trees = RB_ROOT; /* These mean "autodetect" */ blksize = 0; blkno = 0; initialize_ocfs_error_table(); initialize_o2dl_error_table(); initialize_o2cb_error_table(); setlinebuf(stderr); setlinebuf(stdout); while((c = getopt(argc, argv, "b:B:DfFGnupavVyr:")) != EOF) { switch (c) { case 'b': blkno = read_number(optarg); if (blkno < OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid blkno: %s\n", optarg); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } break; case 'B': blksize = read_number(optarg); if (blksize < OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blksize: %s\n", optarg); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } break; case 'D': ost->ost_compress_dirs = 1; break; case 'F': ost->ost_skip_o2cb = 1; break; case 'f': ost->ost_force = 1; break; case 'G': ost->ost_fix_fs_gen = 1; break; case 'n': open_flags &= ~OCFS2_FLAG_RW; open_flags |= OCFS2_FLAG_RO; /* Fall through */ case 'a': case 'p': /* * Like extN, -a maps to -p, which is * 'preen'. This means only fix things * that don't require human interaction. * Unlike extN, this is only journal * replay for now. To make it smarter, * ost->ost_answer needs to learn a * new mode. */ ost->ost_ask = 0; ost->ost_answer = 0; break; case 'y': ost->ost_ask = 0; ost->ost_answer = 1; break; case 'u': open_flags |= OCFS2_FLAG_BUFFERED; break; case 'v': verbose = 1; break; case 'V': print_version(); exit(FSCK_USAGE); break; case 'r': sb_num = read_number(optarg); break; default: fsck_mask |= FSCK_USAGE; print_usage(); goto out; break; } } if (!(open_flags & OCFS2_FLAG_RW) && ost->ost_compress_dirs) { fprintf(stderr, "Compress directories (-D) incompatible with read-only mode\n"); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } if (blksize % OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blocksize: %"PRId64"\n", blksize); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } filename = argv[optind]; print_version(); ret = ocfs2_check_if_mounted(filename, &mount_flags); if (ret) { com_err(whoami, ret, "while determining whether %s is mounted.", filename); fsck_mask |= FSCK_ERROR; goto out; } if (mount_flags & (OCFS2_MF_MOUNTED | OCFS2_MF_BUSY)) { if (!(open_flags & OCFS2_FLAG_RW)) fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 (read-" "only) on a mounted filesystem may detect " "invalid errors.\n\n"); else fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 on a " "mounted filesystem may cause SEVERE " "filesystem damage.\n\n"); proceed = 0; } if (proceed && ost->ost_skip_o2cb) { fprintf(stdout, "\nWARNING!!! You have disabled the cluster check. " "Continue only if you\nare absolutely sure that NO " "node has this filesystem mounted or is\notherwise " "accessing it. If unsure, do NOT continue.\n\n"); proceed = 0; } if (!proceed) { fprintf(stdout, "Do you really want to continue (y/N): "); if (toupper(getchar()) != 'Y') { printf("Aborting operation.\n"); fsck_mask |= FSCK_CANCELED; goto out; } } if (signal(SIGTERM, handle_signal) == SIG_ERR) { com_err(whoami, 0, "Could not set SIGTERM"); exit(1); } if (signal(SIGINT, handle_signal) == SIG_ERR) { com_err(whoami, 0, "Could not set SIGINT"); exit(1); } /* recover superblock should be called at first. */ if (sb_num) { ret = recover_backup_super(ost, filename, sb_num); if (ret) { com_err(whoami, ret, "recover superblock failed.\n"); fsck_mask |= FSCK_ERROR; goto out; } } ret = open_and_check(ost, filename, open_flags, blkno, blksize); if (ret) { fsck_mask |= FSCK_ERROR; goto out; } if (open_flags & OCFS2_FLAG_RW && !ost->ost_skip_o2cb && !ocfs2_mount_local(ost->ost_fs)) { ret = o2cb_init(); if (ret) { com_err(whoami, ret, "while initializing the cluster"); goto close; } block_signals(SIG_BLOCK); ret = ocfs2_initialize_dlm(ost->ost_fs, whoami); if (ret == O2CB_ET_INVALID_STACK_NAME) { block_signals(SIG_UNBLOCK); ret = recover_cluster_info(ost); if (ret) { com_err(whoami, ret, "while recovering cluster information"); goto close; } block_signals(SIG_BLOCK); ret = ocfs2_initialize_dlm(ost->ost_fs, whoami); } if (ret) { block_signals(SIG_UNBLOCK); com_err(whoami, ret, "while initializing the DLM"); goto close; } ret = ocfs2_lock_down_cluster(ost->ost_fs); if (ret) { block_signals(SIG_UNBLOCK); com_err(whoami, ret, "while locking down the cluster"); goto close; } cluster_locked = 1; block_signals(SIG_UNBLOCK); } printf("Checking OCFS2 filesystem in %s:\n", filename); printf(" Label: "); print_label(ost); printf(" UUID: "); print_uuid(ost); printf(" Number of blocks: %"PRIu64"\n", ost->ost_fs->fs_blocks); printf(" Block size: %u\n", ost->ost_fs->fs_blocksize); printf(" Number of clusters: %"PRIu32"\n", ost->ost_fs->fs_clusters); printf(" Cluster size: %u\n", ost->ost_fs->fs_clustersize); printf(" Number of slots: %u\n\n", OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots); /* Let's get enough of a cache to replay the journals */ o2fsck_init_cache(ost, O2FSCK_CACHE_MODE_JOURNAL); if (open_flags & OCFS2_FLAG_RW) { ret = o2fsck_check_journals(ost); if (ret) { printf("fsck saw unrecoverable errors in the journal " "files and will not continue.\n"); goto unlock; } } ret = maybe_replay_journals(ost, filename, open_flags, blkno, blksize); if (ret) { printf("fsck encountered unrecoverable errors while " "replaying the journals and will not continue\n"); fsck_mask |= FSCK_ERROR; goto unlock; } /* Grow the cache */ o2fsck_init_cache(ost, O2FSCK_CACHE_MODE_FULL); /* allocate all this junk after we've replayed the journal and the * sb should be stable */ if (o2fsck_state_init(ost->ost_fs, ost)) { fprintf(stderr, "error allocating run-time state, exiting..\n"); fsck_mask |= FSCK_ERROR; goto unlock; } ret = o2fsck_slot_recovery(ost); if (ret) { printf("fsck encountered errors while recovering slot " "information, check forced.\n"); slot_recover_err = 1; ost->ost_force = 1; } if (fs_is_clean(ost, filename)) { fsck_mask = FSCK_OK; goto clear_dirty_flag; } #if 0 o2fsck_mark_block_used(ost, 0); o2fsck_mark_block_used(ost, 1); o2fsck_mark_block_used(ost, OCFS2_SUPER_BLOCK_BLKNO); #endif mark_magical_clusters(ost); /* XXX we don't use the bad blocks inode, do we? */ /* XXX for now it is assumed that errors returned from a pass * are fatal. these can be fixed over time. */ ret = o2fsck_pass0(ost); if (ret) { com_err(whoami, ret, "while performing pass 0"); goto done; } ret = o2fsck_pass1(ost); if (ret) { com_err(whoami, ret, "while performing pass 1"); goto done; } ret = o2fsck_pass2(ost); if (ret) { com_err(whoami, ret, "while performing pass 2"); goto done; } ret = o2fsck_pass3(ost); if (ret) { com_err(whoami, ret, "while performing pass 3"); goto done; } ret = o2fsck_pass4(ost); if (ret) { com_err(whoami, ret, "while performing pass 4"); goto done; } ret = o2fsck_pass5(ost); if (ret) { com_err(whoami, ret, "while performing pass 5"); goto done; } done: if (ret) fsck_mask |= FSCK_ERROR; else { fsck_mask = FSCK_OK; ost->ost_saw_error = 0; printf("All passes succeeded.\n"); } clear_dirty_flag: if (ost->ost_fs->fs_flags & OCFS2_FLAG_RW) { ret = write_out_superblock(ost); if (ret) com_err(whoami, ret, "while writing back the " "superblock(s)"); if (fsck_mask == FSCK_OK) { if (slot_recover_err) { ret = o2fsck_slot_recovery(ost); if (ret) { com_err(whoami, ret, "while doing slot " "recovery."); goto unlock; } } ret = o2fsck_clear_journal_flags(ost); if (ret) { com_err(whoami, ret, "while clear dirty " "journal flag."); goto unlock; } ret = ocfs2_format_slot_map(ost->ost_fs); if (ret) com_err(whoami, ret, "while format slot " "map."); } } unlock: block_signals(SIG_BLOCK); if (ost->ost_fs->fs_dlm_ctxt) ocfs2_release_cluster(ost->ost_fs); cluster_locked = 0; block_signals(SIG_UNBLOCK); close: block_signals(SIG_BLOCK); if (ost->ost_fs->fs_dlm_ctxt) ocfs2_shutdown_dlm(ost->ost_fs, whoami); block_signals(SIG_UNBLOCK); ret = ocfs2_close(ost->ost_fs); if (ret) { com_err(whoami, ret, "while closing file \"%s\"", filename); /* XXX I wonder about this error.. */ fsck_mask |= FSCK_ERROR; } out: return fsck_mask; } ./ocfs2-tools-1.6.4/fsck.ocfs2/dirblocks.c0000644000176100017610000001463411500500543015040 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * Just a simple rbtree wrapper to record directory blocks and the inodes * that own them. */ #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "fsck.h" #include "dirblocks.h" #include "util.h" #include "extent.h" errcode_t o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino, uint64_t blkno, uint64_t blkcount) { struct rb_node ** p = &db->db_root.rb_node; struct rb_node * parent = NULL; o2fsck_dirblock_entry *dbe, *tmp_dbe; errcode_t ret = 0; ret = ocfs2_malloc0(sizeof(o2fsck_dirblock_entry), &dbe); if (ret) goto out; dbe->e_ino = ino; dbe->e_blkno = blkno; dbe->e_blkcount = blkcount; while (*p) { parent = *p; tmp_dbe = rb_entry(parent, o2fsck_dirblock_entry, e_node); if (dbe->e_blkno < tmp_dbe->e_blkno) p = &(*p)->rb_left; else if (dbe->e_blkno > tmp_dbe->e_blkno) p = &(*p)->rb_right; } rb_link_node(&dbe->e_node, parent, p); rb_insert_color(&dbe->e_node, &db->db_root); out: return ret; } /* * Go through the dirblocks pre-filling them. We try to coalesce adjacent * ones. Don't care to return errors, because it's a cache pre-fill. */ static int try_to_cache(ocfs2_filesys *fs, struct rb_node *node, char *pre_cache_buf, int pre_cache_blocks) { int cached_blocks = 0; o2fsck_dirblock_entry *dbe; uint64_t io_blkno = 0, next_blkno = 0; int count = 0; errcode_t err; uint64_t blocks_seen = 0; o2fsck_reset_blocks_cached(); for (; node; node = rb_next(node)) { blocks_seen++; dbe = rb_entry(node, o2fsck_dirblock_entry, e_node); if (io_blkno) { assert(count); assert(next_blkno > io_blkno); if ((next_blkno == dbe->e_blkno) && (count < pre_cache_blocks)) { count++; next_blkno++; continue; } if (!o2fsck_worth_caching(count)) { io_blkno = 0; break; } err = ocfs2_read_blocks(fs, io_blkno, count, pre_cache_buf); io_blkno = 0; next_blkno = 0; if (err) break; cached_blocks += count; count = 0; } assert(!io_blkno); io_blkno = dbe->e_blkno; next_blkno = io_blkno + 1; count = 1; } /* Catch the last pre-fill buffer */ if (io_blkno && o2fsck_worth_caching(count)) { assert(count); err = ocfs2_read_blocks(fs, io_blkno, count, pre_cache_buf); if (!err) cached_blocks += count; } return cached_blocks; } uint64_t o2fsck_search_reidx_dir(struct rb_root *root, uint64_t dino) { struct rb_node *node = root->rb_node; o2fsck_dirblock_entry *dbe; while (node) { dbe = rb_entry(node, o2fsck_dirblock_entry, e_node); if (dino < dbe->e_ino) node = node->rb_left; else if (dino > dbe->e_ino) node = node->rb_right; else return dbe->e_ino; } return 0; } static errcode_t o2fsck_add_reidx_dir_ino(struct rb_root *root, uint64_t dino) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; o2fsck_dirblock_entry *dp, *tmp_dp; errcode_t ret = 0; ret = ocfs2_malloc0(sizeof (o2fsck_dirblock_entry), &dp); if (ret) goto out; dp->e_ino = dino; while(*p) { parent = *p; tmp_dp = rb_entry(parent, o2fsck_dirblock_entry, e_node); if (dp->e_ino < tmp_dp->e_ino) p = &(*p)->rb_left; else if (dp->e_ino > tmp_dp->e_ino) p = &(*p)->rb_right; else { ret = OCFS2_ET_INTERNAL_FAILURE; ocfs2_free(&dp); goto out; } } rb_link_node(&dp->e_node, parent, p); rb_insert_color(&dp->e_node, root); out: return ret; } errcode_t o2fsck_try_add_reidx_dir(struct rb_root *root, uint64_t dino) { errcode_t ret = 0; uint64_t ino; ino = o2fsck_search_reidx_dir(root, dino); if (ino) goto out; ret = o2fsck_add_reidx_dir_ino(root, dino); out: return ret; } void o2fsck_dir_block_iterate(o2fsck_state *ost, dirblock_iterator func, void *priv_data) { o2fsck_dirblocks *db = &ost->ost_dirblocks; ocfs2_filesys *fs = ost->ost_fs; o2fsck_dirblock_entry *dbe; struct rb_node *node; unsigned ret; errcode_t err; char *pre_cache_buf = NULL; int pre_cache_blocks = ocfs2_blocks_in_bytes(fs, 1024 * 1024); int cached_blocks = 0; o2fsck_reset_blocks_cached(); if (o2fsck_worth_caching(1)) { err = ocfs2_malloc_blocks(fs->fs_io, pre_cache_blocks, &pre_cache_buf); if (err) verbosef("Unable to allocate dirblock pre-cache " "buffer, %s\n", "ignoring"); } for (node = rb_first(&db->db_root); node; node = rb_next(node)) { if (!cached_blocks && pre_cache_buf) cached_blocks = try_to_cache(fs, node, pre_cache_buf, pre_cache_blocks); dbe = rb_entry(node, o2fsck_dirblock_entry, e_node); ret = func(dbe, priv_data); if (ret & OCFS2_DIRENT_ABORT) break; if (cached_blocks) cached_blocks--; } if (pre_cache_buf) ocfs2_free(&pre_cache_buf); } static errcode_t ocfs2_rebuild_indexed_dir(ocfs2_filesys *fs, uint64_t ino) { errcode_t ret = 0; char *di_buf = NULL; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &di_buf); if (ret) goto out; ret = ocfs2_read_inode(fs, ino, di_buf); if (ret) goto out; di = (struct ocfs2_dinode *)di_buf; /* do not rebuild indexed tree for inline directory */ if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) goto out; ret = ocfs2_dx_dir_truncate(fs, ino); if (ret) goto out; ret = ocfs2_dx_dir_build(fs, ino); out: if (di_buf) ocfs2_free(&di_buf); return ret; } errcode_t o2fsck_rebuild_indexed_dirs(ocfs2_filesys *fs, struct rb_root *root) { struct rb_node *node; o2fsck_dirblock_entry *dbe; uint64_t ino; errcode_t ret = 0; for (node = rb_first(root); node; node = rb_next(node)) { dbe = rb_entry(node, o2fsck_dirblock_entry, e_node); ino = dbe->e_ino; ret = ocfs2_rebuild_indexed_dir(fs, ino); if (ret) goto out; } out: return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/dirparents.c0000644000176100017610000000664711453177334015263 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * An rbtree to record a directory's parent information. _dirent records * the inode who had a directory entry that points to the directory in * question. _dot_dot records the inode that the directory's ".." points to; * who it thinks its parent is. */ #include #include #include #include #include "ocfs2/ocfs2.h" #include "fsck.h" #include "dirparents.h" #include "util.h" /* XXX callers are supposed to make sure they don't call with dup inodes. * we'll see. */ errcode_t o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino, uint64_t dot_dot, uint64_t dirent, unsigned in_orphan_dir) { struct rb_node ** p = &root->rb_node; struct rb_node * parent = NULL; o2fsck_dir_parent *dp, *tmp_dp; errcode_t ret = 0; dp = calloc(1, sizeof(*dp)); if (dp == NULL) { ret = OCFS2_ET_NO_MEMORY; goto out; } dp->dp_ino = ino; dp->dp_dot_dot = dot_dot; dp->dp_dirent = dirent; dp->dp_connected = 0; dp->dp_loop_no = 0; dp->dp_in_orphan_dir = in_orphan_dir ? 1 : 0; while (*p) { parent = *p; tmp_dp = rb_entry(parent, o2fsck_dir_parent, dp_node); if (dp->dp_ino < tmp_dp->dp_ino) p = &(*p)->rb_left; else if (dp->dp_ino > tmp_dp->dp_ino) p = &(*p)->rb_right; else { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } } rb_link_node(&dp->dp_node, parent, p); rb_insert_color(&dp->dp_node, root); out: if (ret && dp) free(dp); return ret; } o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root, uint64_t ino) { struct rb_node *node = root->rb_node; o2fsck_dir_parent *dp; while (node) { dp = rb_entry(node, o2fsck_dir_parent, dp_node); if (ino < dp->dp_ino) node = node->rb_left; else if (ino > dp->dp_ino) node = node->rb_right; else return dp; } return NULL; } o2fsck_dir_parent *o2fsck_dir_parent_first(struct rb_root *root) { struct rb_node *node = rb_first(root); o2fsck_dir_parent *dp = NULL; if (node) dp = rb_entry(node, o2fsck_dir_parent, dp_node); return dp; } o2fsck_dir_parent *o2fsck_dir_parent_next(o2fsck_dir_parent *from) { struct rb_node *node = rb_next(&from->dp_node); o2fsck_dir_parent *dp = NULL; if (node) dp = rb_entry(node, o2fsck_dir_parent, dp_node); return dp; } void ocfsck_remove_dir_parent(struct rb_root *root, uint64_t ino) { o2fsck_dir_parent *dp = NULL; struct rb_node *p = root->rb_node; while (p) { dp = rb_entry(p, o2fsck_dir_parent, dp_node); if (dp->dp_ino > ino) p = p->rb_left; else if (dp->dp_ino < ino) p = p->rb_right; else break; } if(!p) goto out; rb_erase(&dp->dp_node, root); free(dp); out: return; } ./ocfs2-tools-1.6.4/fsck.ocfs2/extent.c0000644000176100017610000003055411453177334014411 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * o2fsck_check_extents(), the only function this file exports, is called * by pass 0 to verify the extent trees that hang off of inodes. * * XXX * test reasonable/dup block references * fix up the i_ fields that depend on the extent trees * * this could be much more clever when it finds an extent block that is * self-consistent but in a crazy part of the file system that would lead * us to not trust it. it should first try and follow the suballoc bits * back to a possibly orphaned desc. failing that it should record the * reference/block and continue on. once it has parsed the rest of eb and * fleshed out the bits of the extent block allocators it could go back * and allocate a new block and copy the orphan into it. */ #include #include #include "ocfs2/ocfs2.h" #include "extent.h" #include "fsck.h" #include "problem.h" #include "util.h" #include "refcount.h" static const char *whoami = "extent.c"; static errcode_t check_eb(o2fsck_state *ost, struct extent_info *ei, uint64_t owner, uint64_t blkno, int *is_valid) { int changed = 0; char *buf = NULL; struct ocfs2_extent_block *eb; errcode_t ret; /* XXX test that the block isn't already used */ /* we only consider an extent block invalid if we were able to read * it and it didn't have a extent block signature */ *is_valid = 1; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating a block-sized buffer " "for an extent block"); goto out; } ret = ocfs2_read_extent_block_nocheck(ost->ost_fs, blkno, buf); if (ret) { com_err(whoami, ret, "reading extent block at %"PRIu64" in " "owner %"PRIu64" for verification", blkno, owner); if (ret == OCFS2_ET_BAD_EXTENT_BLOCK_MAGIC) *is_valid = 0; goto out; } eb = (struct ocfs2_extent_block *)buf; if (eb->h_blkno != blkno && prompt(ost, PY, PR_EB_BLKNO, "An extent block at %"PRIu64" in owner %"PRIu64" " "claims to be located at block %"PRIu64". Update the " "extent block's location?", blkno, owner, (uint64_t)eb->h_blkno)) { eb->h_blkno = blkno; changed = 1; } if (eb->h_fs_generation != ost->ost_fs_generation) { if (prompt(ost, PY, PR_EB_GEN, "An extent block at %"PRIu64" in owner " "%"PRIu64" has a generation of %x which doesn't " "match the volume's generation of %x. Consider " "this extent block invalid?", blkno, owner, eb->h_fs_generation, ost->ost_fs_generation)) { *is_valid = 0; goto out; } if (prompt(ost, PY, PR_EB_GEN_FIX, "Update the extent block's generation to match the " "volume?")) { eb->h_fs_generation = ost->ost_fs_generation; changed = 1; } } /* XXX worry about suballoc node/bit */ /* XXX worry about next_leaf_blk */ check_el(ost, ei, owner, &eb->h_list, ocfs2_extent_recs_per_eb(ost->ost_fs->fs_blocksize), &changed); if (changed) { ret = ocfs2_write_extent_block(ost->ost_fs, blkno, buf); if (ret) { com_err(whoami, ret, "while writing an updated extent " "block at %"PRIu64" for owner %"PRIu64, blkno, owner); goto out; } } out: if (buf) ocfs2_free(&buf); return 0; } /* the caller will check if er->e_blkno is out of range to determine if it * should try removing the record */ static errcode_t check_er(o2fsck_state *ost, struct extent_info *ei, uint64_t owner, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *er, int *changed) { errcode_t ret = 0; uint32_t clusters; clusters = ocfs2_rec_clusters(el->l_tree_depth, er); verbosef("cpos %u clusters %u blkno %"PRIu64"\n", er->e_cpos, clusters, (uint64_t)er->e_blkno); if (ocfs2_block_out_of_range(ost->ost_fs, er->e_blkno)) goto out; if (el->l_tree_depth) { int is_valid = 0; /* we only expect a given depth when we descend to extent blocks * from a previous depth. these start at 0 when the inode * is checked */ ei->ei_expect_depth = 1; ei->ei_expected_depth = el->l_tree_depth - 1; check_eb(ost, ei, owner, er->e_blkno, &is_valid); if (!is_valid && prompt(ost, PY, PR_EXTENT_EB_INVALID, "The extent record for cluster offset " "%"PRIu32" in owner %"PRIu64" refers to an invalid " "extent block at %"PRIu64". Clear the reference " "to this invalid block?", er->e_cpos, owner, (uint64_t)er->e_blkno)) { er->e_blkno = 0; *changed = 1; } ret = 0; goto out; } if (ei->chk_rec_func) ret = ei->chk_rec_func(ost, owner, el, er, changed, ei->para); /* XXX offer to remove leaf records with er_clusters set to 0? */ /* XXX check that the blocks that are referenced aren't already * used */ out: return ret; } errcode_t check_el(o2fsck_state *ost, struct extent_info *ei, uint64_t owner, struct ocfs2_extent_list *el, uint16_t max_recs, int *changed) { int trust_next_free = 1; struct ocfs2_extent_rec *er; uint64_t max_size; uint16_t i; uint32_t clusters; size_t cpy; verbosef("depth %u count %u next_free %u\n", el->l_tree_depth, el->l_count, el->l_next_free_rec); if (ei->ei_expect_depth && el->l_tree_depth != ei->ei_expected_depth && prompt(ost, PY, PR_EXTENT_LIST_DEPTH, "Extent list in owner %"PRIu64" is recorded as " "being at depth %u but we expect it to be at depth %u. " "update the list?", owner, el->l_tree_depth, ei->ei_expected_depth)) { el->l_tree_depth = ei->ei_expected_depth; *changed = 1; } if (el->l_count > max_recs && prompt(ost, PY, PR_EXTENT_LIST_COUNT, "Extent list in owner %"PRIu64" claims to have %u " "records, but the maximum is %u. Fix the list's count?", owner, el->l_count, max_recs)) { el->l_count = max_recs; *changed = 1; } if (max_recs > el->l_count) max_recs = el->l_count; if (el->l_next_free_rec > max_recs) { if (prompt(ost, PY, PR_EXTENT_LIST_FREE, "Extent list in owner %"PRIu64" claims %u " "as the next free chain record, but fsck believes " "the largest valid value is %u. Clamp the next " "record value?", owner, el->l_next_free_rec, max_recs)) { el->l_next_free_rec = el->l_count; *changed = 1; } else { trust_next_free = 0; } } if (trust_next_free) max_recs = el->l_next_free_rec; for (i = 0; i < max_recs; i++) { er = &el->l_recs[i]; clusters = ocfs2_rec_clusters(el->l_tree_depth, er); /* * For a sparse file, we may find an empty record * in the left most record. Just skip it. */ if ((OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) && el->l_tree_depth && !i && !clusters) continue; /* returns immediately if blkno is out of range. * descends into eb. checks that data er doesn't * reference past the volume or anything crazy. */ check_er(ost, ei, owner, el, er, changed); /* offer to remove records that point to nowhere */ if (ocfs2_block_out_of_range(ost->ost_fs, er->e_blkno) && prompt(ost, PY, PR_EXTENT_BLKNO_RANGE, "Extent record %u in owner %"PRIu64" " "refers to a block that is out of range. Remove " "this record from the extent list?", i, owner)) { if (!trust_next_free) { printf("Can't remove the record becuase " "next_free_rec hasn't been fixed\n"); continue; } cpy = (max_recs - i - 1) * sizeof(*er); /* shift the remaining recs into this ones place */ if (cpy != 0) { memcpy(er, er + 1, cpy); memset(&el->l_recs[max_recs - 1], 0, sizeof(*er)); i--; } el->l_next_free_rec--; max_recs--; *changed = 1; continue; } /* we've already accounted for the extent block as part of * the extent block chain groups */ if (el->l_tree_depth) continue; /* mark the data clusters as used */ if (ei->mark_rec_alloc_func) ei->mark_rec_alloc_func(ost, er, clusters, ei->para); ei->ei_clusters += clusters; max_size = (er->e_cpos + clusters) << OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_clustersize_bits; if (max_size > ei->ei_max_size) ei->ei_max_size = max_size; } return 0; } errcode_t o2fsck_check_extent_rec(o2fsck_state *ost, uint64_t owner, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *er, int *changed, void *para) { uint32_t clusters, last_cluster; uint64_t first_block; struct ocfs2_super_block *sb = OCFS2_RAW_SB(ost->ost_fs->fs_super); struct ocfs2_dinode *di = para; clusters = ocfs2_rec_clusters(el->l_tree_depth, er); first_block = ocfs2_blocks_to_clusters(ost->ost_fs, er->e_blkno); first_block = ocfs2_clusters_to_blocks(ost->ost_fs, first_block); if (first_block != er->e_blkno && prompt(ost, PY, PR_EXTENT_BLKNO_UNALIGNED, "The extent record for cluster offset %"PRIu32" " "in owner %"PRIu64" refers to block %"PRIu64" which isn't " "aligned with the start of a cluster. Point the extent " "record at block %"PRIu64" which starts this cluster?", er->e_cpos, owner, (uint64_t)er->e_blkno, first_block)) { er->e_blkno = first_block; *changed = 1; } /* imagine blkno 0, 1 er_clusters. last_cluster is 1 and * fs_clusters is 1, which is ok.. */ last_cluster = ocfs2_blocks_to_clusters(ost->ost_fs, er->e_blkno) + clusters; if (last_cluster > ost->ost_fs->fs_clusters && prompt(ost, PY, PR_EXTENT_CLUSTERS_OVERRUN, "The extent record for cluster offset %"PRIu32" " "in inode %"PRIu64" refers to an extent that goes beyond " "the end of the volume. Truncate the extent by %"PRIu32" " "clusters to fit it in the volume?", er->e_cpos, owner, last_cluster - ost->ost_fs->fs_clusters)) { clusters -= last_cluster - ost->ost_fs->fs_clusters; ocfs2_set_rec_clusters(el->l_tree_depth, er, clusters); *changed = 1; } if (!ocfs2_writes_unwritten_extents(sb) && (er->e_flags & OCFS2_EXT_UNWRITTEN) && prompt(ost, PY, PR_EXTENT_MARKED_UNWRITTEN, "The extent record for cluster offset %"PRIu32" " "in owner %"PRIu64" has the UNWRITTEN flag set, but " "this filesystem does not support unwritten extents. " "Clear the UNWRITTEN flag?", er->e_cpos, (uint64_t)di->i_blkno)) { er->e_flags &= ~OCFS2_EXT_UNWRITTEN; *changed = 1; } if (((!ocfs2_refcount_tree(sb)) || !(di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)) && (er->e_flags & OCFS2_EXT_REFCOUNTED) && prompt(ost, PY, PR_EXTENT_MARKED_REFCOUNTED, "The extent record for cluster offset %"PRIu32" at block " "%"PRIu64" in inode %"PRIu64" has the REFCOUNTED flag set, " "while it shouldn't have that flag. " "Clear the REFCOUNTED flag?", er->e_cpos, er->e_blkno, (uint64_t)di->i_blkno)) { er->e_flags &= ~OCFS2_EXT_REFCOUNTED; *changed = 1; } return 0; } errcode_t o2fsck_mark_tree_clusters_allocated(o2fsck_state *ost, struct ocfs2_extent_rec *rec, uint32_t clusters, void *para) { struct ocfs2_dinode *di = para; errcode_t ret = 0; if (rec->e_flags & OCFS2_EXT_REFCOUNTED) ret = o2fsck_mark_clusters_refcounted(ost, di->i_refcount_loc, di->i_blkno, ocfs2_blocks_to_clusters(ost->ost_fs, rec->e_blkno), clusters, rec->e_cpos); else o2fsck_mark_clusters_allocated(ost, ocfs2_blocks_to_clusters(ost->ost_fs, rec->e_blkno), clusters); return ret; } errcode_t o2fsck_check_extents(o2fsck_state *ost, struct ocfs2_dinode *di) { errcode_t ret; struct extent_info ei = {0, }; int changed = 0; ei.chk_rec_func = o2fsck_check_extent_rec; ei.mark_rec_alloc_func = o2fsck_mark_tree_clusters_allocated; ei.para = di; ret = check_el(ost, &ei, di->i_blkno, &di->id2.i_list, ocfs2_extent_recs_per_inode(ost->ost_fs->fs_blocksize), &changed); if (changed) o2fsck_write_inode(ost, di->i_blkno, di); return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/icount.c0000644000176100017610000001272011341355437014374 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * A trivial rbtree that stores a u16 icount indexed by an inode's block * number. */ #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "fsck.h" #include "icount.h" #include "util.h" typedef struct _icount_node { struct rb_node in_node; uint64_t in_blkno; uint16_t in_icount; } icount_node; /* XXX this is currently fragile in that it requires that the caller make * sure that the node doesn't already exist in the tree. */ static void icount_insert(o2fsck_icount *icount, icount_node *in) { struct rb_node ** p = &icount->ic_multiple_tree.rb_node; struct rb_node * parent = NULL; icount_node *tmp_in; while (*p) { parent = *p; tmp_in = rb_entry(parent, icount_node, in_node); if (in->in_blkno < tmp_in->in_blkno) p = &(*p)->rb_left; else if (in->in_blkno > tmp_in->in_blkno) p = &(*p)->rb_right; } rb_link_node(&in->in_node, parent, p); rb_insert_color(&in->in_node, &icount->ic_multiple_tree); } static icount_node *icount_search(o2fsck_icount *icount, uint64_t blkno, icount_node **next) { struct rb_node *node = icount->ic_multiple_tree.rb_node; icount_node *in, *last_left = NULL; while (node) { in = rb_entry(node, icount_node, in_node); if (blkno < in->in_blkno) { last_left = in; node = node->rb_left; } else if (blkno > in->in_blkno) node = node->rb_right; else return in; } if (next && last_left) *next = last_left; return NULL; } /* keep it simple for now by always updating both data structures */ errcode_t o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno, uint16_t count) { icount_node *in; errcode_t ret = 0; if (count == 1) o2fsck_bitmap_set(icount->ic_single_bm, blkno, NULL); else o2fsck_bitmap_clear(icount->ic_single_bm, blkno, NULL); in = icount_search(icount, blkno, NULL); if (in) { if (count < 2) { rb_erase(&in->in_node, &icount->ic_multiple_tree); free(in); } else { in->in_icount = count; } } else if (count > 1) { in = calloc(1, sizeof(*in)); if (in == NULL) { ret = OCFS2_ET_NO_MEMORY; goto out; } in->in_blkno = blkno; in->in_icount = count; icount_insert(icount, in); } out: return ret; } uint16_t o2fsck_icount_get(o2fsck_icount *icount, uint64_t blkno) { icount_node *in; int was_set; uint16_t ret = 0; ocfs2_bitmap_test(icount->ic_single_bm, blkno, &was_set); if (was_set) { ret = 1; goto out; } in = icount_search(icount, blkno, NULL); if (in) ret = in->in_icount; out: return ret; } /* again, simple before efficient. We just find the old value and * use _set to make sure that the new value updates both the bitmap * and the tree */ void o2fsck_icount_delta(o2fsck_icount *icount, uint64_t blkno, int delta) { int was_set; uint16_t prev_count; icount_node *in; if (delta == 0) return; ocfs2_bitmap_test(icount->ic_single_bm, blkno, &was_set); if (was_set) { prev_count = 1; } else { in = icount_search(icount, blkno, NULL); if (in == NULL) prev_count = 0; else prev_count = in->in_icount; } if (prev_count + delta < 0) com_err(__FUNCTION__, OCFS2_ET_INTERNAL_FAILURE, "while droping icount from %"PRIu16" bt %d for " "inode %"PRIu64, prev_count, delta, blkno); o2fsck_icount_set(icount, blkno, prev_count + delta); } errcode_t o2fsck_icount_new(ocfs2_filesys *fs, o2fsck_icount **ret) { o2fsck_icount *icount; errcode_t err; icount = calloc(1, sizeof(*icount)); if (icount == NULL) return OCFS2_ET_NO_MEMORY; err = ocfs2_block_bitmap_new(fs, "inodes with single link_count", &icount->ic_single_bm); if (err) { free(icount); com_err("icount", err, "while allocating single link_count bm"); return err; } icount->ic_multiple_tree = RB_ROOT; *ret = icount; return 0; } errcode_t o2fsck_icount_next_blkno(o2fsck_icount *icount, uint64_t start, uint64_t *found) { uint64_t next_bit; errcode_t ret; icount_node *in, *next = NULL; ret = ocfs2_bitmap_find_next_set(icount->ic_single_bm, start, &next_bit); in = icount_search(icount, start, &next); if (in == NULL) in = next; if (in) { if (ret == OCFS2_ET_BIT_NOT_FOUND) *found = in->in_blkno; else *found = next_bit < in->in_blkno ? next_bit : in->in_blkno; ret = 0; } else { if (ret != OCFS2_ET_BIT_NOT_FOUND) *found = next_bit; } return ret; } void o2fsck_icount_free(o2fsck_icount *icount) { struct rb_node *node; icount_node *in; ocfs2_bitmap_free(icount->ic_single_bm); while((node = rb_first(&icount->ic_multiple_tree)) != NULL) { in = rb_entry(node, icount_node, in_node); rb_erase(node, &icount->ic_multiple_tree); free(in); } free(icount); } ./ocfs2-tools-1.6.4/fsck.ocfs2/journal.c0000644000176100017610000006501611341355437014553 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2000 Andreas Dilger * Copyright (C) 2000 Theodore Ts'o * Copyright (C) 2004,2008 Oracle. All rights reserved. * * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie * Copyright (C) 1999 Red Hat Software * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. * * -- * This replays the jbd2 journals for each slot. First all the journals are * walked to detect inconsistencies. Only journals with no problems will be * replayed. IO errors during replay will just result in partial journal * replay, just like jbd2 does in the kernel. Journals that don't pass * consistency checks, like having overlapping blocks or strange fields, are * ignored and left for later passes to clean up. * XXX * future passes need to guarantee journals exist and are the same size * pass fsck trigger back up, write dirty fs, always zap/write * revocation code is totally untested * some setup errors, like finding the dlm system inode, are fatal */ #include #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include "fsck.h" #include "journal.h" #include "pass1.h" #include "problem.h" #include "util.h" static const char *whoami = "journal recovery"; struct journal_info { int ji_slot; unsigned ji_replay:1; uint64_t ji_ino; struct rb_root ji_revoke; journal_superblock_t *ji_jsb; uint64_t ji_jsb_block; ocfs2_cached_inode *ji_cinode; unsigned ji_set_final_seq:1; uint32_t ji_final_seq; /* we keep our own bitmap for detecting overlapping journal blocks */ ocfs2_bitmap *ji_used_blocks; }; struct revoke_entry { struct rb_node r_node; uint64_t r_block; uint32_t r_seq; }; static int seq_gt(uint32_t x, uint32_t y) { int32_t diff = x - y; return diff > 0; } static int seq_geq(uint32_t x, uint32_t y) { int32_t diff = x - y; return diff >= 0; } static errcode_t revoke_insert(struct rb_root *root, uint64_t block, uint32_t seq) { struct rb_node ** p = &root->rb_node; struct rb_node * parent = NULL; struct revoke_entry *re; while (*p) { parent = *p; re = rb_entry(parent, struct revoke_entry, r_node); if (block < re->r_block) p = &(*p)->rb_left; else if (block > re->r_block) p = &(*p)->rb_right; else { if (seq_gt(seq, re->r_seq)) re->r_seq = seq; return 0; } } re = malloc(sizeof(struct revoke_entry)); if (re == NULL) return OCFS2_ET_NO_MEMORY; re->r_block = block; re->r_seq = seq; rb_link_node(&re->r_node, parent, p); rb_insert_color(&re->r_node, root); return 0; } static int revoke_this_block(struct rb_root *root, uint64_t block, uint32_t seq) { struct rb_node *node = root->rb_node; struct revoke_entry *re; while (node) { re = rb_entry(node, struct revoke_entry, r_node); if (block < re->r_block) node = node->rb_left; else if (block > re->r_block) node = node->rb_right; else { /* only revoke if we've recorded a revoke entry for * this block that is <= the seq that we're interested * in */ if (re && !seq_gt(seq, re->r_seq)) { verbosef("%"PRIu64" is revoked\n", block); return 1; } } } return 0; } static void revoke_free_all(struct rb_root *root) { struct revoke_entry *re; struct rb_node *node; while((node = rb_first(root)) != NULL) { re = rb_entry(node, struct revoke_entry, r_node); rb_erase(node, root); free(re); } } static errcode_t add_revoke_records(struct journal_info *ji, char *buf, size_t max, uint32_t seq) { journal_revoke_header_t jr; uint32_t *blkno; /* XXX 640k ought to be enough for everybody */ size_t i, num; errcode_t err = 0; memcpy(&jr, buf, sizeof(jr)); jr.r_count = be32_to_cpu(jr.r_count); if (jr.r_count < sizeof(jr) || jr.r_count > max) { verbosef("corrupt r_count: %X", jr.r_count); return OCFS2_ET_BAD_JOURNAL_REVOKE; } num = (jr.r_count - sizeof(jr)) / sizeof(blkno); blkno = (uint32_t *)(buf + sizeof(jr)); for (i = 0; i < num; i++, blkno++) { err = revoke_insert(&ji->ji_revoke, be32_to_cpu(*blkno), seq); if (err) break; } return err; } static uint64_t jwrap(journal_superblock_t *jsb, uint64_t block) { uint64_t diff = jsb->s_maxlen - jsb->s_first; if (diff == 0) /* ugh */ return 0; while (block >= jsb->s_maxlen) block -= diff; return block; } static errcode_t count_tags(ocfs2_filesys *fs, journal_superblock_t *jsb, char *buf, uint64_t *nr_ret) { char *tagp, *last; journal_block_tag_t *tag; int tag_bytes = ocfs2_journal_tag_bytes(jsb); uint64_t nr = 0; if (jsb->s_blocksize < sizeof(journal_header_t) + tag_bytes) return OCFS2_ET_BAD_JOURNAL_TAG; tagp = &buf[sizeof(journal_header_t)]; last = &buf[jsb->s_blocksize - tag_bytes]; for(; tagp <= last; tagp += tag_bytes) { tag = (journal_block_tag_t *)tagp; nr++; if (ocfs2_block_out_of_range(fs, ocfs2_journal_tag_block(tag, tag_bytes))) return OCFS2_ET_BAD_JOURNAL_TAG; if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG)) break; if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID))) tagp += 16; } *nr_ret = nr; return 0; } static errcode_t lookup_journal_block(ocfs2_filesys *fs, struct journal_info *ji, uint64_t blkoff, uint64_t *blkno, int check_dup) { errcode_t ret; uint64_t contig; int was_set; ret = ocfs2_extent_map_get_blocks(ji->ji_cinode, blkoff, 1, blkno, &contig, NULL); if (ret) { com_err(whoami, ret, "while looking up logical block " "%"PRIu64" in slot %d's journal", blkoff, ji->ji_slot); goto out; } if (check_dup) { o2fsck_bitmap_set(ji->ji_used_blocks, *blkno, &was_set); if (was_set) { printf("Logical block %"PRIu64" in slot %d's journal " "maps to block %"PRIu64" which has already " "been used in another journal.\n", blkoff, ji->ji_slot, *blkno); ret = OCFS2_ET_DUPLICATE_BLOCK; } } out: return ret; } static errcode_t read_journal_block(ocfs2_filesys *fs, struct journal_info *ji, uint64_t blkoff, char *buf, int check_dup) { errcode_t err; uint64_t blkno; err = lookup_journal_block(fs, ji, blkoff, &blkno, check_dup); if (err) return err; err = ocfs2_read_blocks(fs, blkno, 1, buf); if (err) com_err(whoami, err, "while reading block %"PRIu64" of slot " "%d's journal", blkno, ji->ji_slot); return err; } static errcode_t replay_blocks(ocfs2_filesys *fs, struct journal_info *ji, char *buf, uint64_t seq, uint64_t *next_block) { char *tagp; journal_block_tag_t *tag; size_t i, num; char *io_buf = NULL; errcode_t err, ret = 0; int tag_bytes = ocfs2_journal_tag_bytes(ji->ji_jsb); uint32_t t_flags; uint64_t block64; tagp = buf + sizeof(journal_header_t); num = (ji->ji_jsb->s_blocksize - sizeof(journal_header_t)) / tag_bytes; ret = ocfs2_malloc_blocks(fs->fs_io, 1, &io_buf); if (ret) { com_err(whoami, ret, "while allocating a block buffer"); goto out; } for(i = 0; i < num; i++, tagp += tag_bytes, (*next_block)++) { tag = (journal_block_tag_t *)tagp; t_flags = be32_to_cpu(tag->t_flags); block64 = ocfs2_journal_tag_block(tag, tag_bytes); *next_block = jwrap(ji->ji_jsb, *next_block); verbosef("recovering journal block %"PRIu64" to disk block " "%"PRIu64"\n", *next_block, block64); if (revoke_this_block(&ji->ji_revoke, block64, seq)) goto skip_io; err = read_journal_block(fs, ji, *next_block, io_buf, 1); if (err) { ret = err; goto skip_io; } if (t_flags & JBD2_FLAG_ESCAPE) { uint32_t magic = cpu_to_be32(JBD2_MAGIC_NUMBER); memcpy(io_buf, &magic, sizeof(magic)); } err = io_write_block(fs->fs_io, block64, 1, io_buf); if (err) ret = err; skip_io: if (t_flags & JBD2_FLAG_LAST_TAG) i = num; /* be sure to increment next_block */ if (!(t_flags & JBD2_FLAG_SAME_UUID)) tagp += 16; } out: if (io_buf) ocfs2_free(&io_buf); return ret; } static errcode_t walk_journal(ocfs2_filesys *fs, int slot, struct journal_info *ji, char *buf, int recover) { errcode_t err, ret = 0; uint32_t next_seq; uint64_t next_block, nr; journal_superblock_t *jsb = ji->ji_jsb; journal_header_t jh; next_seq = jsb->s_sequence; next_block = jsb->s_start; /* s_start == 0 when we have nothing to do */ if (next_block == 0) return 0; /* ret is set when bad tags are seen in the first scan and when there * are io errors in the recovery scan. Only stop walking the journal * when bad tags are seen in the first scan. */ while(recover || !ret) { verbosef("next_seq %"PRIu32" final_seq %"PRIu32" next_block " "%"PRIu64"\n", next_seq, ji->ji_final_seq, next_block); if (recover && seq_geq(next_seq, ji->ji_final_seq)) break; /* only mark the blocks used on the first pass */ err = read_journal_block(fs, ji, next_block, buf, !recover); if (err) { ret = err; break; } next_block = jwrap(jsb, next_block + 1); memcpy(&jh, buf, sizeof(jh)); jh.h_magic = be32_to_cpu(jh.h_magic); jh.h_blocktype = be32_to_cpu(jh.h_blocktype); jh.h_sequence = be32_to_cpu(jh.h_sequence); verbosef("jh magic %x\n", jh.h_magic); if (jh.h_magic != JBD2_MAGIC_NUMBER) break; verbosef("jh block %x\n", jh.h_blocktype); verbosef("jh seq %"PRIu32"\n", jh.h_sequence); if (jh.h_sequence != next_seq) break; switch(jh.h_blocktype) { case JBD2_DESCRIPTOR_BLOCK: verbosef("found a desc type %x\n", jh.h_blocktype); /* replay the blocks described in the desc block */ if (recover) { err = replay_blocks(fs, ji, buf, next_seq, &next_block); if (err) ret = err; continue; } /* just record the blocks as used and carry on */ err = count_tags(fs, jsb, buf, &nr); if (err) ret = err; else next_block = jwrap(jsb, next_block + nr); break; case JBD2_COMMIT_BLOCK: verbosef("found a commit type %x\n", jh.h_blocktype); next_seq++; break; case JBD2_REVOKE_BLOCK: verbosef("found a revoke type %x\n", jh.h_blocktype); add_revoke_records(ji, buf, jsb->s_blocksize, next_seq); break; default: verbosef("unknown type %x\n", jh.h_blocktype); break; } } verbosef("done scanning with seq %"PRIu32"\n", next_seq); if (!recover) { ji->ji_set_final_seq = 1; ji->ji_final_seq = next_seq; } else if (ji->ji_final_seq != next_seq) { printf("Replaying slot %d's journal stopped at seq %"PRIu32" " "but an initial scan indicated that it should have " "stopped at seq %"PRIu32"\n", ji->ji_slot, next_seq, ji->ji_final_seq); if (ret == 0) err = OCFS2_ET_IO; } return ret; } static errcode_t prep_journal_info(ocfs2_filesys *fs, int slot, struct journal_info *ji) { errcode_t err; err = ocfs2_malloc_blocks(fs->fs_io, 1, &ji->ji_jsb); if (err) com_err(whoami, err, "while allocating space for slot %d's " "journal superblock", slot); err = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, slot, &ji->ji_ino); if (err) { com_err(whoami, err, "while looking up the journal inode for " "slot %d", slot); goto out; } err = ocfs2_read_cached_inode(fs, ji->ji_ino, &ji->ji_cinode); if (err) { com_err(whoami, err, "while reading cached inode %"PRIu64" " "for slot %d's journal", ji->ji_ino, slot); goto out; } if (!(ji->ji_cinode->ci_inode->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL)) goto out; err = lookup_journal_block(fs, ji, 0, &ji->ji_jsb_block, 1); if (err) goto out; /* XXX be smarter about reading in the whole super block if it * spans multiple blocks */ err = ocfs2_read_journal_superblock(fs, ji->ji_jsb_block, (char *)ji->ji_jsb); if (err) { com_err(whoami, err, "while reading block %"PRIu64" as slot " "%d's journal super block", ji->ji_jsb_block, ji->ji_slot); goto out; } ji->ji_replay = 1; verbosef("slot: %d jsb start %u maxlen %u\n", slot, ji->ji_jsb->s_start, ji->ji_jsb->s_maxlen); out: return err; } /* * We only need to replay the journals if the inode's flag is set and s_start * indicates that there is actually pending data in the journals. * * In the simple case of an unclean shutdown we don't want to have to build up * enough state to be able to truncate the inodes waiting in the orphan dir. * ocfs2 in the kernel only fixes up the orphan dirs if the journal dirty flag * is set. So after replaying the journals we clear s_startin the journals to * stop a second journal replay but leave the dirty bit set so that the kernel * will truncate the orphaned inodes. */ errcode_t o2fsck_should_replay_journals(ocfs2_filesys *fs, int *should, int *has_dirty) { uint16_t i, max_slots; char *buf = NULL; uint64_t blkno; errcode_t ret; ocfs2_cached_inode *cinode = NULL; int is_dirty; uint64_t contig; journal_superblock_t *jsb; *should = 0; max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating room to read journal " "blocks"); goto out; } jsb = (journal_superblock_t *)buf; for (i = 0; i < max_slots; i++) { ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i, &blkno); if (ret) { com_err(whoami, ret, "while looking up the journal " "inode for slot %d", i); goto out; } if (cinode) { ocfs2_free_cached_inode(fs, cinode); cinode = NULL; } ret = ocfs2_read_cached_inode(fs, blkno, &cinode); if (ret) { com_err(whoami, ret, "while reading cached inode " "%"PRIu64" for slot %d's journal", blkno, i); goto out; } is_dirty = cinode->ci_inode->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL; verbosef("slot %d JOURNAL_DIRTY_FL: %d\n", i, is_dirty); if (!is_dirty) continue; else *has_dirty = 1; ret = ocfs2_extent_map_get_blocks(cinode, 0, 1, &blkno, &contig, NULL); if (ret) { com_err(whoami, ret, "while looking up the journal " "super block in slot %d's journal", i); goto out; } /* XXX be smarter about reading in the whole super block if it * spans multiple blocks */ ret = ocfs2_read_journal_superblock(fs, blkno, buf); if (ret) { com_err(whoami, ret, "while reading the journal " "super block in slot %d's journal", i); goto out; } if (jsb->s_start) *should = 1; } out: if (buf) ocfs2_free(&buf); if (cinode) ocfs2_free_cached_inode(fs, cinode); return ret; } /* Try and replay the slots journals if they're dirty. This only returns * a non-zero error if the caller should not continue. */ errcode_t o2fsck_replay_journals(ocfs2_filesys *fs, int *replayed) { errcode_t err = 0, ret = 0; struct journal_info *jis, *ji; journal_superblock_t *jsb; char *buf = NULL; int journal_trouble = 0; uint16_t i, max_slots; ocfs2_bitmap *used_blocks = NULL; max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ret = ocfs2_block_bitmap_new(fs, "journal blocks", &used_blocks); if (ret) { com_err(whoami, ret, "while allocating journal block bitmap"); goto out; } ret = ocfs2_malloc_blocks(fs->fs_io, 1, &buf); if (ret) { com_err(whoami, ret, "while allocating room to read journal " "blocks"); goto out; } ret = ocfs2_malloc0(sizeof(struct journal_info) * max_slots, &jis); if (ret) { com_err(whoami, ret, "while allocating an array of block " "numbers for journal replay"); goto out; } printf("Checking each slot's journal.\n"); for (i = 0, ji = jis; i < max_slots; i++, ji++) { ji->ji_used_blocks = used_blocks; ji->ji_revoke = RB_ROOT; ji->ji_slot = i; /* sets ji->ji_replay */ err = prep_journal_info(fs, i, ji); if (err) { printf("Slot %d seems to have a corrupt journal.\n", i); journal_trouble = 1; continue; } if (!ji->ji_replay) { verbosef("slot %d is clean\n", i); continue; } err = walk_journal(fs, i, ji, buf, 0); if (err) { printf("Slot %d's journal can not be replayed.\n", i); journal_trouble = 1; } } for (i = 0, ji = jis; i < max_slots; i++, ji++) { if (!ji->ji_replay) continue; printf("Replaying slot %d's journal.\n", i); err = walk_journal(fs, i, ji, buf, 1); if (err) { journal_trouble = 1; continue; } jsb = ji->ji_jsb; /* reset the journal */ jsb->s_start = 0; if (ji->ji_set_final_seq) jsb->s_sequence = ji->ji_final_seq + 1; /* we don't write back a clean 'mounted' bit here. That would * have to also include having recovered the orphan dir. we * updated s_start, though, so we won't replay the journal * again. */ err = ocfs2_write_journal_superblock(fs, ji->ji_jsb_block, (char *)ji->ji_jsb); if (err) { com_err(whoami, err, "while writing slot %d's journal " "super block", i); journal_trouble = 1; } else { printf("Slot %d's journal replayed successfully.\n", i); *replayed = 1; } } /* this is awkward, but we want fsck -n to tell us as much as it * can so we don't want to ask to proceed here. */ if (journal_trouble) printf("*** There were problems replaying journals. Be " "careful in telling fsck to make repairs to this " "filesystem.\n"); ret = 0; out: if (jis) { for (i = 0, ji = jis; i < max_slots; i++, ji++) { if (ji->ji_jsb) ocfs2_free(&ji->ji_jsb); if (ji->ji_cinode) ocfs2_free_cached_inode(fs, ji->ji_cinode); revoke_free_all(&ji->ji_revoke); } ocfs2_free(&jis); } if (buf) ocfs2_free(&buf); if (used_blocks) ocfs2_bitmap_free(used_blocks); return ret; } struct journal_check_info { errcode_t i_error; uint32_t i_clusters; ocfs2_fs_options i_features; }; struct journal_check_context { int jc_max_slots; int jc_this_slot; uint32_t jc_max_clusters; /* Size of the largest journal found */ ocfs2_fs_options jc_max_features; /* Union all features in good journals */ struct journal_check_info *jc_info; /* One per slot */ }; static errcode_t check_journals_func(o2fsck_state *ost, ocfs2_cached_inode *ci, struct journal_check_context *jc) { errcode_t err, ret; ocfs2_filesys *fs = ost->ost_fs; uint64_t contig; uint64_t blkno; char *buf = NULL; journal_superblock_t *jsb; struct journal_check_info *ji = &(jc->jc_info[jc->jc_this_slot]); ret = ocfs2_malloc_blocks(fs->fs_io, 1, &buf); if (ret) goto out; err = ocfs2_extent_map_get_blocks(ci, 0, 1, &blkno, &contig, NULL); if (err) { ji->i_error = err; goto out; } ji->i_clusters = ci->ci_inode->i_clusters; err = ocfs2_read_journal_superblock(fs, blkno, buf); if (err) { ji->i_error = err; goto out; } jsb = (journal_superblock_t *)buf; ji->i_features.opt_compat = jsb->s_feature_compat; ji->i_features.opt_ro_compat = jsb->s_feature_ro_compat; ji->i_features.opt_incompat = jsb->s_feature_incompat; if (!ji->i_clusters) { ji->i_error = OCFS2_ET_JOURNAL_TOO_SMALL; goto out; } jc->jc_max_clusters = ocfs2_max(jc->jc_max_clusters, ci->ci_inode->i_clusters); jc->jc_max_features.opt_compat |= jsb->s_feature_compat; jc->jc_max_features.opt_ro_compat |= jsb->s_feature_ro_compat; jc->jc_max_features.opt_incompat |= jsb->s_feature_incompat; ji->i_error = 0; out: if (buf) ocfs2_free(&buf); return ret; } static errcode_t fix_journals_func(o2fsck_state *ost, ocfs2_cached_inode *ci, struct journal_check_context *jc) { errcode_t err, ret = 0; ocfs2_filesys *fs = ost->ost_fs; char fname[OCFS2_MAX_FILENAME_LEN]; struct journal_check_info *ji = &(jc->jc_info[jc->jc_this_slot]); uint32_t min_clusters = ocfs2_clusters_in_bytes(fs, OCFS2_MIN_JOURNAL_SIZE); ocfs2_sprintf_system_inode_name(fname, OCFS2_MAX_FILENAME_LEN, JOURNAL_SYSTEM_INODE, jc->jc_this_slot); if (ji->i_error && (ji->i_error != OCFS2_ET_JOURNAL_TOO_SMALL) && (ji->i_error != OCFS2_ET_UNSUPP_FEATURE) && (ji->i_error != OCFS2_ET_RO_UNSUPP_FEATURE)) { if (prompt(ost, PY, PR_JOURNAL_FILE_INVALID, "journal file %s is invalid, regenerate it?", fname)) { err = ocfs2_make_journal(fs, ci->ci_blkno, jc->jc_max_clusters, &jc->jc_max_features); ji->i_error = err; } goto out; } if ((ji->i_error == OCFS2_ET_UNSUPP_FEATURE) || (ji->i_error == OCFS2_ET_RO_UNSUPP_FEATURE)) { if (prompt(ost, PN, PR_JOURNAL_UNKNOWN_FEATURE, "journal file %s has unknown features. " "However, other journals have only known " "features, so this is likely a corruption. " "If you think your filesystem may be newer " "than this version of fsck.ocfs2, say N here " "and grab the latest version of fsck.ocfs2. " "Reset the journal features to match other " "journals?", fname)) { err = ocfs2_make_journal(fs, ci->ci_blkno, ocfs2_max(ji->i_clusters, min_clusters), &jc->jc_max_features); if (!err) { ji->i_features.opt_compat = jc->jc_max_features.opt_compat; ji->i_features.opt_ro_compat = jc->jc_max_features.opt_ro_compat; ji->i_features.opt_incompat = jc->jc_max_features.opt_incompat; } ji->i_error = err; } } else if ((ji->i_features.opt_compat != jc->jc_max_features.opt_compat) || (ji->i_features.opt_ro_compat != jc->jc_max_features.opt_ro_compat) || (ji->i_features.opt_incompat != jc->jc_max_features.opt_incompat)) { if (prompt(ost, PY, PR_JOURNAL_MISSING_FEATURE, "journal file %s is missing features that " "are set on other journal files. Set these " "features?", fname)) { err = ocfs2_make_journal(fs, ci->ci_blkno, ocfs2_max(ji->i_clusters, min_clusters), &jc->jc_max_features); if (!err) { ji->i_features.opt_compat = jc->jc_max_features.opt_compat; ji->i_features.opt_ro_compat = jc->jc_max_features.opt_ro_compat; ji->i_features.opt_incompat = jc->jc_max_features.opt_incompat; } ji->i_error = err; } } if (ji->i_clusters != jc->jc_max_clusters) { if (prompt(ost, PY, PR_JOURNAL_TOO_SMALL, "journal file %s is too small, extend it?", fname)) { err = ocfs2_make_journal(fs, ci->ci_blkno, jc->jc_max_clusters, &ji->i_features); ji->i_error = err; } } out: return ret; } static errcode_t check_journal_walk(o2fsck_state *ost, errcode_t (*func)(o2fsck_state *ost, ocfs2_cached_inode *ci, struct journal_check_context *jc), struct journal_check_context *jc) { errcode_t ret = 0; uint64_t blkno; ocfs2_filesys *fs = ost->ost_fs; uint16_t i, max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ocfs2_cached_inode *ci = NULL; for (i = 0; i < max_slots; i++) { ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i, &blkno); if (ret) break; ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) break; jc->jc_this_slot = i; ret = func(ost, ci, jc); if (ret) break; } if (ci) ocfs2_free_cached_inode(fs, ci); return ret; } errcode_t o2fsck_check_journals(o2fsck_state *ost) { errcode_t ret; int i; ocfs2_filesys *fs = ost->ost_fs; int have_one_good_journal = 0, problem_is_consistent = 1; errcode_t known_problem = 0; struct journal_check_context jc = { .jc_max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots, }; struct journal_check_info *ji; ret = ocfs2_malloc0(sizeof(struct journal_check_info) * jc.jc_max_slots, &jc.jc_info); if (ret) { com_err(whoami, ret, "while checking journals"); goto out; } ret = check_journal_walk(ost, check_journals_func, &jc); if (ret) { com_err(whoami, ret, "while checking journals"); goto out; } /* * We now know the state of all our journals. If we have at least * one good journal, we have a sane state to fix the others from. * We require all our journals to have identical configuration. * Any inconsistencies (invalid size, bad feature flags) are * probably corruption or a failed tunefs. * * If we don't have a good journal, but all the journals have the * exact same problem, we may be able to handle it as well. We * currently know how to handle these problems: * * JOURNAL_TOO_SMALL * * We simply allocate a default journal size. * * UNSUPP_FEATURE & RO_UNSUPP_FEATURE * * If one journal has an unsupported feature bit set, it's probably * corruption. If all the journals have the exact same feature * bit set, it's certainly a feature we don't understand, and we * want the user to upgrade their fsck. */ for (i = 0; i < jc.jc_max_slots; i++) { ji = &jc.jc_info[i]; if (!ji->i_error) { have_one_good_journal = 1; continue; } if ((ji->i_error != OCFS2_ET_JOURNAL_TOO_SMALL) && (ji->i_error != OCFS2_ET_UNSUPP_FEATURE) && (ji->i_error != OCFS2_ET_RO_UNSUPP_FEATURE)) { problem_is_consistent = 0; continue; } if (known_problem) { if (known_problem != ji->i_error) problem_is_consistent = 0; continue; } known_problem = ji->i_error; } if (!have_one_good_journal) { if (!problem_is_consistent || !known_problem) { ret = jc.jc_info[0].i_error; com_err(whoami, ret, "while checking journals"); goto out; } if ((known_problem == OCFS2_ET_UNSUPP_FEATURE) || (known_problem == OCFS2_ET_RO_UNSUPP_FEATURE)) { com_err(whoami, known_problem, "on all journals. Please upgrade to the " "latest version of fsck.ocfs2"); ret = known_problem; goto out; } if (known_problem != OCFS2_ET_JOURNAL_TOO_SMALL) { ret = known_problem; com_err(whoami, ret, "for all journals"); goto out; } /* Force a valid cluster count for the journals */ jc.jc_max_clusters = ocfs2_clusters_in_bytes(fs, OCFS2_MIN_JOURNAL_SIZE); } ret = check_journal_walk(ost, fix_journals_func, &jc); out: if (jc.jc_info) ocfs2_free(&jc.jc_info); return ret; } static errcode_t ocfs2_clear_journal_flag(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot) { errcode_t ret = 0; if (!(di->i_flags & OCFS2_VALID_FL) || !(di->i_flags & OCFS2_SYSTEM_FL) || !(di->i_flags & OCFS2_JOURNAL_FL)) return OCFS2_ET_INVALID_ARGUMENT; if (!(di->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL)) goto bail; di->id1.journal1.ij_flags &= ~OCFS2_JOURNAL_DIRTY_FL; ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (!ret) printf("Slot %d's journal dirty flag removed\n", slot); bail: return ret; } errcode_t o2fsck_clear_journal_flags(o2fsck_state *ost) { if (!ost->ost_has_journal_dirty) return 0; return handle_slots_system_file(ost->ost_fs, JOURNAL_SYSTEM_INODE, ocfs2_clear_journal_flag); } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass0.c0000644000176100017610000012555411500500544014117 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * Pass 0 verifies that the basic linkage of the various chain allocators is * intact so that future passes can use them in place safely. The actual * bitmaps in the allocators aren't worried about here. Later passes will * clean them up by loading them in to memory, updating them, and writing them * back out. * * Pass 1, for example, wants to iterate over the inode blocks covered by the * inode chain allocators so it can verify them and update the allocation * bitmaps for inodes that are still in use. * * The cluster chain allocator is a special case because its group descriptors * are at regular predictable offsets throughout the volume. fsck forces these * block descriptors into service and removes and block descriptors in the * chain that aren't at these offsets. * * pass0 updates group descriptor chains on disk. * * XXX * track blocks and clusters we see here that iteration won't * verify more inode fields? * make sure blocks don't overlap as part of cluster tracking * make sure _bits is correct, pass in from callers * generalize the messages to chain allocators instead of inode allocators */ #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "dirblocks.h" #include "dirparents.h" #include "icount.h" #include "fsck.h" #include "pass0.h" #include "pass1.h" #include "problem.h" #include "util.h" static const char *whoami = "pass0"; struct chain_state { uint32_t cs_free_bits; uint32_t cs_total_bits; uint32_t cs_chain_no; uint16_t cs_cpg; }; static void find_max_free_bits(struct ocfs2_group_desc *gd, int *max_free_bits) { int end = 0; int start; int free_bits; *max_free_bits = 0; while (end < gd->bg_bits) { start = ocfs2_find_next_bit_clear(gd->bg_bitmap, gd->bg_bits, end); if (start >= gd->bg_bits) break; end = ocfs2_find_next_bit_set(gd->bg_bitmap, gd->bg_bits, start); free_bits = end - start; *max_free_bits += free_bits; } } /* check whether the group really exists in the specified chain of * the specified allocator file. */ static errcode_t check_group_parent(ocfs2_filesys *fs, uint64_t group, uint64_t ino, uint16_t chain,int *exist) { errcode_t ret; uint64_t gd_blkno; char *buf = NULL, *gd_buf = NULL; struct ocfs2_dinode *di = NULL; struct ocfs2_group_desc *gd = NULL; struct ocfs2_chain_rec *cr = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; ret = ocfs2_read_inode(fs, ino, buf); if (ret) { goto out; } di = (struct ocfs2_dinode *)buf; if (!(di->i_flags & OCFS2_VALID_FL) || !(di->i_flags & OCFS2_BITMAP_FL) || !(di->i_flags & OCFS2_CHAIN_FL)) goto out; if (di->id1.bitmap1.i_total == 0) goto out; if (di->id2.i_chain.cl_next_free_rec <= chain) goto out; cr = &di->id2.i_chain.cl_recs[chain]; ret = ocfs2_malloc_block(fs->fs_io, &gd_buf); if (ret) goto out; gd_blkno = cr->c_blkno; while (gd_blkno) { if (gd_blkno == group) { *exist = 1; break; } ret = ocfs2_read_group_desc(fs, gd_blkno, gd_buf); if (ret) goto out; gd = (struct ocfs2_group_desc *)gd_buf; gd_blkno = gd->bg_next_group; } out: if (gd_buf) ocfs2_free(&gd_buf); if (buf) ocfs2_free(&buf); return ret; } static void check_discontig_bg(o2fsck_state *ost, int cpg, struct ocfs2_group_desc *bg, int *changed, int *clear_ref) { uint64_t blkno = bg->bg_blkno; int next_free, i, total_clusters = 0; int fix_pos = -1; struct ocfs2_extent_rec *rec; if (bg->bg_list.l_tree_depth && prompt(ost, PY, PR_DISCONTIG_BG_DEPTH, "Discontiguous Group descriptor at block %"PRIu64" has " "a tree depth %u which is greater than 0. " "Change it to 0?", blkno, bg->bg_list.l_tree_depth)) { bg->bg_list.l_tree_depth = 0; *changed = 1; } if ((bg->bg_list.l_count > ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize)) && prompt(ost, PY, PR_DISCONTIG_BG_COUNT, "Discontigous group descriptor at block %"PRIu64" has " "an extent count of %u, but discontiguous groups can " "only hold %u records. Set it to %u?", blkno, bg->bg_list.l_count, ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize), ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize))) { bg->bg_list.l_count = ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize); *changed = 1; } if (bg->bg_list.l_next_free_rec > bg->bg_list.l_count) next_free = bg->bg_list.l_count; else next_free = bg->bg_list.l_next_free_rec; for (i = 0; i < next_free; i++) { rec = &bg->bg_list.l_recs[i]; /* * We treat e_blkno = 0 and e_leaf_cluster = 0 as the * end of the extent list so that we can find the proper * l_next_free_rec. */ if (!rec->e_blkno && !rec->e_leaf_clusters) break; if (ocfs2_block_out_of_range(ost->ost_fs, rec->e_blkno) || ocfs2_block_out_of_range(ost->ost_fs, rec->e_blkno + ocfs2_clusters_to_blocks(ost->ost_fs, rec->e_leaf_clusters) - 1)) { if (prompt(ost, PY, PR_DISCONTIG_BG_REC_RANGE, "Discontiguous block group %"PRIu64" in " "chain %d of inode %"PRIu64" claims " "clusters which is out of range. " "Drop this group?", blkno, bg->bg_chain, (uint64_t)bg->bg_parent_dinode)) *clear_ref = 1; goto out; } if (rec->e_leaf_clusters > cpg) { if (fix_pos >= 0) { if (prompt(ost, PY, PR_DISCONTIG_BG_CORRUPT_LEAVES, "Discontiguous block group %"PRIu64 " in chain %d of inode %"PRIu64" " "has errors in more than one extent " "record. Record %d claims %u " "clusters and record %d claims %u " "clusters, but a group does not " "contain more than %u clusters. " "Drop this group?", blkno, bg->bg_chain, (uint64_t)bg->bg_parent_dinode, fix_pos, bg->bg_list.l_recs[fix_pos].e_leaf_clusters, i, rec->e_leaf_clusters, cpg)) *clear_ref = 1; goto out; } fix_pos = i; continue; } if ((total_clusters + rec->e_leaf_clusters) > cpg) { if (total_clusters == cpg) { if (fix_pos >= 0) { /* * We have to drop the group here since * both l_next_free_rec and a extent * record have errors. */ if (prompt(ost, PY, PR_DISCONTIG_BG_LIST_CORRUPT, "Discontiguous group " "descriptor at block " "%"PRIu64" claims to use %u " "extents but only has %u " "filled in. The filled in " "records contain errors. " "Drop this group?", blkno, bg->bg_list.l_next_free_rec, i)) *clear_ref = 1; goto out; } /* * break out here so that we can fix the * l_next_free_rec. */ break; } else { if (prompt(ost, PY, PR_DISCONTIG_BG_CLUSTERS, "Discontiguous group descriptor at " "block %"PRIu64" claims to have %u " "clusters but a group does not " "contain more than %u clusters. " "Drop the group?", blkno, total_clusters + rec->e_leaf_clusters, cpg)) *clear_ref = 1; goto out; } } else total_clusters += rec->e_leaf_clusters; } if (bg->bg_list.l_next_free_rec != i) { /* Change l_next_free_rec since the extent list look sane. */ if (prompt(ost, PY, PR_DISCONTIG_BG_NEXT_FREE_REC, "Discontiguous group descriptor at " "block %"PRIu64" claims to use %u " "extents but only has %u filled in. " "The filled in records appear to " "be correct. Set the used extent " "count to the number filled in?", blkno, bg->bg_list.l_next_free_rec, i)) { bg->bg_list.l_next_free_rec = i; *changed = 1; } } if (fix_pos < 0 && total_clusters < cpg) { if (prompt(ost, PY, PR_DISCONTIG_BG_LESS_CLUSTERS, "Discontiguous group descriptor at " "block %"PRIu64" claims to have %u " "clusters but a group does not " "contain less than %u clusters. " "Drop the group?", blkno, total_clusters, cpg)) *clear_ref = 1; goto out; } if (fix_pos >= 0) { rec = &bg->bg_list.l_recs[fix_pos]; if (total_clusters == cpg) { if (prompt(ost, PY, PR_DISCONTIG_BG_REC_CORRUPT, "Extent record %d of discontiguous group " "descriptor at block %"PRIu64" claims %u " "clusters, but a group does not " "contain more than %u clusters. " "Drop the group?", fix_pos, blkno, rec->e_leaf_clusters, cpg)) *clear_ref = 1; goto out; } if (prompt(ost, PY, PR_DISCONTIG_BG_LEAF_CLUSTERS, "Extent record %d of discontiguous group " "descriptor %"PRIu64" claims %u clusters, " "but it should only have %u. Correct it?", fix_pos, blkno, rec->e_leaf_clusters, cpg - total_clusters)) { rec->e_leaf_clusters = cpg - total_clusters; *changed = 1; } } out: return; } static errcode_t repair_group_desc(o2fsck_state *ost, struct ocfs2_dinode *di, struct chain_state *cs, struct ocfs2_group_desc *bg, uint64_t blkno, int *clear_ref) { errcode_t ret = 0; int changed = 0; int max_free_bits = 0; verbosef("checking desc at %"PRIu64"; blkno %"PRIu64" size %u bits %u " "free_bits %u chain %u generation %u\n", blkno, (uint64_t)bg->bg_blkno, bg->bg_size, bg->bg_bits, bg->bg_free_bits_count, bg->bg_chain, bg->bg_generation); if (bg->bg_generation != ost->ost_fs_generation && prompt(ost, PY, PR_GROUP_GEN, "Group descriptor at block %"PRIu64" has " "a generation of %"PRIx32" which doesn't match the " "volume's generation of %"PRIx32". Change the generation " "in the descriptor to match the volume?", blkno, bg->bg_generation, ost->ost_fs_generation)) { bg->bg_generation = ost->ost_fs_generation; changed = 1; } /* XXX maybe for advanced pain we could check to see if these * kinds of descs have valid generations for the inodes they * reference */ if ((bg->bg_parent_dinode != di->i_blkno)) { int exist = 0; ret = check_group_parent(ost->ost_fs, bg->bg_blkno, bg->bg_parent_dinode, bg->bg_chain, &exist); /* If we finds that the group really exists in the specified * chain of the specified alloc inode, then this may be a * duplicated group and we may need to remove it from current * inode. */ if (!ret && exist && prompt(ost, PY, PR_GROUP_DUPLICATE, "Group descriptor at block %"PRIu64" is " "referenced by inode %"PRIu64" but thinks its parent inode " "is %"PRIu64" and we can also see it in that inode." " So it may be duplicated. Remove it from this inode?", blkno, (uint64_t)di->i_blkno, (uint64_t)bg->bg_parent_dinode)) { *clear_ref = 1; goto out; } if (prompt(ost, PY, PR_GROUP_PARENT, "Group descriptor at block %"PRIu64" is " "referenced by inode %"PRIu64" but thinks its parent inode " "is %"PRIu64". Fix the descriptor's parent inode?", blkno, (uint64_t)di->i_blkno, (uint64_t)bg->bg_parent_dinode)) { bg->bg_parent_dinode = di->i_blkno; changed = 1; } } if ((bg->bg_blkno != blkno) && prompt(ost, PY, PR_GROUP_BLKNO, "Group descriptor read from block %"PRIu64" " "claims to be located at block %"PRIu64". Update its " "recorded block location?", blkno, (uint64_t)di->i_blkno)) { bg->bg_blkno = blkno; changed = 1; } if ((bg->bg_chain != cs->cs_chain_no) && prompt(ost, PY, PR_GROUP_CHAIN, "Group descriptor at block %"PRIu64" was " "found in chain %u but it claims to be in chain %u. Update " "the descriptor's recorded chain?", blkno, cs->cs_chain_no, bg->bg_chain)) { bg->bg_chain = cs->cs_chain_no; changed = 1; } find_max_free_bits(bg, &max_free_bits); if ((bg->bg_free_bits_count > max_free_bits) && prompt(ost, PY, PR_GROUP_FREE_BITS, "Group descriptor at block %"PRIu64" claims to " "have %u free bits which is more than %u bits" " indicated by the bitmap. " "Drop its free bit count down to the total?", blkno, bg->bg_free_bits_count, max_free_bits)) { bg->bg_free_bits_count = max_free_bits; changed = 1; } if (ocfs2_gd_is_discontig(bg)) check_discontig_bg(ost, cs->cs_cpg, bg, &changed, clear_ref); if (*clear_ref) goto out; /* XXX check bg_bits vs cpg/bpc. */ if (changed) { ret = ocfs2_write_group_desc(ost->ost_fs, bg->bg_blkno, (char *)bg); if (ret) { com_err(whoami, ret, "while writing a group " "descriptor to block %"PRIu64" somewhere in " "chain %d in group allocator inode %"PRIu64, (uint64_t)bg->bg_blkno, cs->cs_chain_no, (uint64_t)di->i_blkno); ost->ost_saw_error = 1; } } cs->cs_total_bits += bg->bg_bits; cs->cs_free_bits += bg->bg_free_bits_count; out: return ret; } /* we do this here instead of check_chain so that we can have two relatively * digesitible routines instead of one enormous spaghetti-fed monster. we've * already had a chance to repair the chains so any remaining damage is * the fault of -n, etc, and can simply abort us */ static void unlink_group_desc(o2fsck_state *ost, struct ocfs2_dinode *di, struct ocfs2_group_desc *bg, uint64_t blkno) { struct ocfs2_chain_list *cl; struct ocfs2_chain_rec *cr; uint16_t i, max_count; struct ocfs2_group_desc *link; int unlink = 0; char *buf = NULL; uint64_t next_desc; errcode_t ret; cl = &di->id2.i_chain; max_count = ocfs2_min(cl->cl_next_free_rec, (__u16)ocfs2_chain_recs_per_inode(ost->ost_fs->fs_blocksize)); ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating block buffers"); goto out; } link = (struct ocfs2_group_desc *)buf; for (cr = cl->cl_recs, i = 0; i < max_count && cr->c_blkno; i++, cr++) { if (cr->c_blkno == blkno) { cr->c_blkno = bg->bg_next_group; unlink = 1; break; } next_desc = cr->c_blkno; while(next_desc) { ret = ocfs2_read_group_desc(ost->ost_fs, next_desc, (char *)link); if (ret) { com_err(whoami, ret, "while reading a " "group descriptor from block %"PRIu64, next_desc); goto out; } if (link->bg_next_group != blkno) { next_desc = link->bg_next_group; continue; } link->bg_next_group = bg->bg_next_group; ret = ocfs2_write_group_desc(ost->ost_fs, next_desc, (char *)link); if (ret) { com_err(whoami, ret, "while writing a group " "descriptor to block %"PRIu64" " "somewhere in chain %d in group " "allocator inode %"PRIu64, next_desc, i, (uint64_t)di->i_blkno); ost->ost_saw_error = 1; goto out; } /* we only try to remove it once.. to do more we'd * have to truncate chains at the offender rather than * just removing it as a link to avoid creating * chains that all reference the offender's children. * we'd also need to update the cr/inode counts * for each bg removed.. sounds weak. */ unlink = 1; break; } if (unlink) break; } if (!unlink) goto out; /* XXX this is kind of risky.. how can we trust next_free_rec? */ if (cl->cl_next_free_rec == i + 1 && cr->c_blkno == 0) cl->cl_next_free_rec--; cr->c_free -= bg->bg_free_bits_count; cr->c_total -= bg->bg_bits; di->id1.bitmap1.i_used -= bg->bg_bits - bg->bg_free_bits_count; di->id1.bitmap1.i_total -= bg->bg_bits; di->i_clusters -= (bg->bg_bits / cl->cl_bpc); di->i_size = (uint64_t)di->i_clusters * ost->ost_fs->fs_clustersize; ret = ocfs2_write_inode(ost->ost_fs, di->i_blkno, (char *)di); if (ret) { /* XXX ugh, undo the bitmap math? */ com_err(whoami, ret, "while writing inode alloc inode " "%"PRIu64, (uint64_t)di->i_blkno); ost->ost_saw_error = 1; goto out; } out: if (buf) ocfs2_free(&buf); } static void mark_group_used(o2fsck_state *ost, struct chain_state *cs, uint64_t blkno, int just_desc, struct ocfs2_group_desc *desc) { int i; uint16_t clusters = 0; if (just_desc) clusters = 1; else if (!desc || !ocfs2_gd_is_discontig(desc)) clusters = cs->cs_cpg; if (clusters) { o2fsck_mark_clusters_allocated(ost, ocfs2_blocks_to_clusters(ost->ost_fs, blkno), clusters); return; } /* Now check the discontiguous group case. */ for (i = 0; i < desc->bg_list.l_next_free_rec; i++) { struct ocfs2_extent_rec *rec = &desc->bg_list.l_recs[i]; o2fsck_mark_clusters_allocated(ost, ocfs2_blocks_to_clusters(ost->ost_fs, rec->e_blkno), rec->e_leaf_clusters); } } /* * Due to a glitch in old mkfs, cl->cl_cpg for the GLOBAL BITMAP could be * less than the max possible for volumes having just one cluster * group. Fix. */ static errcode_t maybe_fix_clusters_per_group(o2fsck_state *ost, struct ocfs2_dinode *di) { struct ocfs2_chain_list *cl; struct ocfs2_group_desc *gd; uint16_t new_cl_cpg = 0; uint64_t blkno; char *buf = NULL; int ret = 0; cl = &(di->id2.i_chain); if (cl->cl_next_free_rec > 1) goto out; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating block buffers " "to fix cl_cpg"); goto out; } gd = (struct ocfs2_group_desc *) buf; blkno = cl->cl_recs[0].c_blkno; ret = ocfs2_read_group_desc(ost->ost_fs, blkno, (char *)gd); if (ret) { com_err(whoami, ret, "while reading group descriptor " "at block %"PRIu64" to fix cl_cpg", blkno); goto out; } new_cl_cpg = 8 * gd->bg_size; if (cl->cl_cpg == new_cl_cpg) goto out; if (prompt(ost, PY, PR_CHAIN_CPG, "Global bitmap at block %"PRIu64" has clusters per group " "set to %u instead of %u. Fix?", (uint64_t)di->i_blkno, cl->cl_cpg, new_cl_cpg)) { cl->cl_cpg = new_cl_cpg; ret = ocfs2_write_inode(ost->ost_fs, di->i_blkno, (char *)di); if (ret) { com_err(whoami, ret, "while writing inode alloc inode " "%"PRIu64" to fix cl_cpg", (uint64_t)di->i_blkno); ost->ost_saw_error = 1; ret = 0; } } out: if (buf) ocfs2_free(&buf); return ret; } /* this takes a slightly ridiculous number of arguments :/ */ static errcode_t check_chain(o2fsck_state *ost, struct ocfs2_dinode *di, struct chain_state *cs, struct ocfs2_chain_rec *chain, char *buf1, char *buf2, char *pre_cache_buf, int *chain_changed, ocfs2_bitmap *allowed, ocfs2_bitmap *forbidden) { struct ocfs2_group_desc *bg1 = (struct ocfs2_group_desc *)buf1; struct ocfs2_group_desc *bg2 = (struct ocfs2_group_desc *)buf2; uint64_t blkno; errcode_t ret = 0; int depth = 0, clear_ref = 0; int blocks_per_group = ocfs2_clusters_to_blocks(ost->ost_fs, cs->cs_cpg); verbosef("free %u total %u blkno %"PRIu64"\n", chain->c_free, chain->c_total, (uint64_t)chain->c_blkno); while(1) { /* fetch the next reference */ if (depth == 0) blkno = chain->c_blkno; else { /* we only mark a group as used if it wasn't * contentious. if we weren't supposed to find it we * mark it for a future pass to consider. we do * this here just as we're about to take the reference * to the next group, implying that we've just * decided that bg1 is valid. */ blkno = bg1->bg_blkno; if (allowed) { int was_set; ocfs2_bitmap_test(allowed, blkno, &was_set); if (was_set) { o2fsck_bitmap_clear(allowed, blkno, &was_set); mark_group_used(ost, cs, bg1->bg_blkno, allowed != NULL, bg1); } else if (forbidden) o2fsck_bitmap_set(forbidden, blkno, &was_set); } else mark_group_used(ost, cs, bg1->bg_blkno, allowed != NULL, bg1); blkno = bg1->bg_next_group; } /* we're done */ if (blkno == 0) break; /* is it even feasible? */ if (ocfs2_block_out_of_range(ost->ost_fs, blkno)) { if (prompt(ost, PY, PR_CHAIN_LINK_RANGE, "Chain %d in allocator at inode " "%"PRIu64" contains a reference at depth " "%d to block %"PRIu64" which is out " "of range. Truncate this chain?", cs->cs_chain_no, (uint64_t)di->i_blkno, depth, blkno)) { clear_ref = 1; break; } /* this will just result in a bad blkno from * the read below.. */ } /* * Pre-cache the entire group. Don't care about failure. * If it works, the following ocfs2_read_group_desc() will * get the block out of the cache. */ if (pre_cache_buf) ocfs2_read_blocks(ost->ost_fs, blkno, blocks_per_group, pre_cache_buf); ret = ocfs2_read_group_desc(ost->ost_fs, blkno, (char *)bg2); if (ret == OCFS2_ET_BAD_GROUP_DESC_MAGIC) { if (prompt(ost, PY, PR_CHAIN_LINK_MAGIC, "Chain %d in allocator at inode " "%"PRIu64" contains a reference at depth " "%d to block %"PRIu64" which doesn't have " "a valid checksum. Truncate this chain?", cs->cs_chain_no, (uint64_t)di->i_blkno, depth, blkno)) { clear_ref = 1; break; } /* we're not interested in following a broken desc */ ret = 0; break; } if (ret) { com_err(whoami, ret, "while reading a group " "descriptor from block %"PRIu64" as pointed " "to by chain %d in allocator at inode " "%"PRIu64" at depth %d", blkno, cs->cs_chain_no, (uint64_t)di->i_blkno, depth); goto out; } if (bg2->bg_generation != ost->ost_fs_generation && prompt(ost, PY, PR_CHAIN_LINK_GEN, "Group descriptor at block %"PRIu64" " "has a generation of %"PRIx32" which doesn't match " "the volume's generation of %"PRIx32". Unlink " "this group descriptor?", blkno, bg2->bg_generation, ost->ost_fs_generation)) { clear_ref = 1; break; } ret = repair_group_desc(ost, di, cs, bg2, blkno, &clear_ref); if (ret) goto out; /* we found a duplicate chain, so we need to clear them from * current chain. * * Please note that all the groups below this group will also * be removed from this chain because this is the mechanism * of removing slots in tunefs.ocfs2. */ if (clear_ref) break; /* the loop will now start by reading bg1->next_group */ memcpy(buf1, buf2, ost->ost_fs->fs_blocksize); depth++; } /* we hit the premature end of a chain.. clear the last * ref we were working from */ if (clear_ref) { if (depth == 0) { chain->c_blkno = 0; *chain_changed = 1; } else { bg1->bg_next_group = 0; ret = ocfs2_write_group_desc(ost->ost_fs, bg1->bg_blkno, (char *)bg1); if (ret) { com_err(whoami, ret, "while writing a group " "descriptor at depth %d in chain %d " "in group allocator inode %"PRIu64" " "to block %"PRIu64, depth, cs->cs_chain_no, (uint64_t)di->i_blkno, (uint64_t)bg1->bg_blkno); ost->ost_saw_error = 1; } } } if (cs->cs_total_bits != chain->c_total || cs->cs_free_bits != chain->c_free) { if (prompt(ost, PY, PR_CHAIN_BITS, "Chain %d in allocator inode %"PRIu64" " "has %u bits marked free out of %d total bits " "but the block groups in the chain have %u " "free out of %u total. Fix this by updating " "the chain record?", cs->cs_chain_no, (uint64_t)di->i_blkno, chain->c_free, chain->c_total, cs->cs_free_bits, cs->cs_total_bits)) { chain->c_total = cs->cs_total_bits; chain->c_free = cs->cs_free_bits; *chain_changed = 1; } } out: return ret; } /* If this returns 0 then the inode allocator had better be amenable to * iteration. */ static errcode_t verify_chain_alloc(o2fsck_state *ost, struct ocfs2_dinode *di, char *buf1, char *buf2, char *pre_cache_buf, ocfs2_bitmap *allowed, ocfs2_bitmap *forbidden) { struct chain_state cs = {0, }; struct ocfs2_chain_list *cl; int i, max_count; struct ocfs2_chain_rec *cr; uint32_t free = 0, total = 0; int changed = 0, trust_next_free = 1; errcode_t ret = 0; uint64_t chain_bytes; if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) { printf("Allocator inode %"PRIu64" doesn't have an inode " "signature. fsck won't repair this.\n", (uint64_t)di->i_blkno); ret = OCFS2_ET_BAD_INODE_MAGIC; goto out; } if (!(di->i_flags & OCFS2_VALID_FL)) { printf("Allocator inode %"PRIu64" is not active. fsck won't " "repair this.\n", (uint64_t)di->i_blkno); ret = OCFS2_ET_INODE_NOT_VALID; goto out; } if (!(di->i_flags & OCFS2_CHAIN_FL)) { printf("Allocator inode %"PRIu64" doesn't have the CHAIN_FL " "flag set. fsck won't repair this.\n", (uint64_t)di->i_blkno); /* not _entirely_ accurate, but pretty close. */ ret = OCFS2_ET_INODE_NOT_VALID; goto out; } /* XXX should we check suballoc_node? */ cl = &di->id2.i_chain; verbosef("cl cpg %u bpc %u count %u next %u\n", cl->cl_cpg, cl->cl_bpc, cl->cl_count, cl->cl_next_free_rec); max_count = ocfs2_chain_recs_per_inode(ost->ost_fs->fs_blocksize); /* first, no rec should have a totally invalid blkno */ for (i = 0; i < max_count; i++) { cr = &cl->cl_recs[i]; if (cr->c_blkno != 0&& ocfs2_block_out_of_range(ost->ost_fs, cr->c_blkno) && prompt(ost, PY, PR_CHAIN_HEAD_LINK_RANGE, "Chain %d in allocator inode %"PRIu64" " "contains an initial block reference to %"PRIu64" " "which is out of range. Clear this reference?", i, (uint64_t)di->i_blkno, (uint64_t)cr->c_blkno)) { cr->c_blkno = 0; changed = 1; } } /* make sure cl_count is clamped to the size of the inode */ if (cl->cl_count > max_count && prompt(ost, PY, PR_CHAIN_COUNT, "Allocator inode %"PRIu64" claims to have %u " "chains, but the maximum is %u. Fix the inode's count?", (uint64_t)di->i_blkno, cl->cl_count, max_count)) { cl->cl_count = max_count; changed = 1; } if (max_count > cl->cl_count) max_count = cl->cl_count; if (cl->cl_next_free_rec > max_count) { if (prompt(ost, PY, PR_CHAIN_NEXT_FREE, "Allocator inode %"PRIu64" claims %u " "as the next free chain record, but fsck believes " "the largest valid value is %u. Clamp the next " "record value?", (uint64_t)di->i_blkno, cl->cl_next_free_rec, max_count)) { cl->cl_next_free_rec = cl->cl_count; changed = 1; } else { trust_next_free = 0; } } /* iterate over all chains if we don't trust next_free_rec to mark * the end of used chains */ if (trust_next_free) max_count = cl->cl_next_free_rec; /* * We walk the chains backwards for caching reasons. Basically, * at the end the last blocks we read will be the most recently * used in the cache. We want that to be the first chains, * especially for the inode scan, which will read forwards. */ for (i = max_count - 1; i >= 0; i--) { cr = &cl->cl_recs[i]; /* reset for each run */ cs = (struct chain_state) { .cs_chain_no = i, .cs_cpg = cl->cl_cpg, }; ret = check_chain(ost, di, &cs, cr, buf1, buf2, pre_cache_buf, &changed, allowed, forbidden); /* XXX what? not checking ret? */ if (cr->c_blkno != 0) { free += cs.cs_free_bits; total += cs.cs_total_bits; continue; } if (prompt(ost, PY, PR_CHAIN_EMPTY, "Chain %d in allocator inode %"PRIu64" " "is empty. Remove it from the chain record " "array in the inode and shift further chains " "into its place?", cs.cs_chain_no, (uint64_t)di->i_blkno)) { if (!trust_next_free) { printf("Can't remove the chain becuase " "next_free_rec hasn't been fixed\n"); continue; } /* when we move a chain to a different rec we have * to update bg_chain in all the descs in the chain. * we copy the last chain into the missing spot * instead of shifting everyone over a spot * to minimize the number of chains we have to * update. we then reset i so that we can go * over that chain and fix bg_chain */ if (i < (cl->cl_next_free_rec - 1)) { *cr = cl->cl_recs[cl->cl_next_free_rec - 1]; memset(&cl->cl_recs[cl->cl_next_free_rec - 1], 0, sizeof(struct ocfs2_chain_rec)); i++; } cl->cl_next_free_rec--; max_count--; changed = 1; continue; } } for (i = cl->cl_next_free_rec; i < cl->cl_count; i++) memset(&cl->cl_recs[i], 0, sizeof(struct ocfs2_chain_rec)); if (di->id1.bitmap1.i_total != total || (di->id1.bitmap1.i_used != total - free)) { if (prompt(ost, PY, PR_CHAIN_GROUP_BITS, "Allocator inode %"PRIu64" has %u bits " "marked used out of %d total bits but the chains " "have %u used out of %u total. Fix this by " "updating the inode counts?", (uint64_t)di->i_blkno, di->id1.bitmap1.i_used, di->id1.bitmap1.i_total, total - free, total)) { di->id1.bitmap1.i_used = total - free; di->id1.bitmap1.i_total = total; changed = 1; } } total /= cl->cl_bpc; if (di->i_clusters != total && prompt(ost, PY, PR_CHAIN_I_CLUSTERS, "Allocator inode %"PRIu64" has %"PRIu32" clusters " "represented in its allocator chains but has an " "i_clusters value of %"PRIu32". Fix this by updating " "i_clusters?", (uint64_t)di->i_blkno, total, di->i_clusters)) { di->i_clusters = total; changed = 1; } chain_bytes = (uint64_t)total * ost->ost_fs->fs_clustersize; if (di->i_size != chain_bytes && prompt(ost, PY, PR_CHAIN_I_SIZE, "Allocator inode %"PRIu64" has %"PRIu32" clusters " "represented in its allocator chain which accounts for " "%"PRIu64" total bytes, but its i_size is %"PRIu64". " "Fix this by updating i_size?", (uint64_t)di->i_blkno, di->id1.bitmap1.i_total, chain_bytes, (uint64_t)di->i_size)) { di->i_size = chain_bytes; changed = 1; } if (changed) { ret = ocfs2_write_inode(ost->ost_fs, di->i_blkno, (char *)di); if (ret) { com_err(whoami, ret, "while writing inode alloc inode " "%"PRIu64, (uint64_t)di->i_blkno); ost->ost_saw_error = 1; ret = 0; } } out: return ret; } /* we know that the bitmap descs are at predictable places in the fs. we * walk these locations and make sure there are valid group descs * there. We fill a bitmap with the valid ones so that when we later walk * the chains we can restrict it to the set of expected blocks and also * be sure to add blocks that aren't linked in */ static errcode_t verify_bitmap_descs(o2fsck_state *ost, struct ocfs2_dinode *di, char *buf1, char *buf2) { struct ocfs2_cluster_group_sizes cgs; uint16_t max_recs; uint16_t bits, chain; uint64_t blkno; struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *)buf1; errcode_t ret; struct chain_state cs; struct ocfs2_chain_rec *rec; ocfs2_bitmap *allowed = NULL, *forbidden = NULL; int was_set, i; /* XXX ugh, only used by mark_ */ cs.cs_cpg = di->id2.i_chain.cl_cpg; ret = ocfs2_block_bitmap_new(ost->ost_fs, "allowed group descriptors", &allowed); if (ret) { com_err(whoami, ret, "while allocating allowed bitmap descs " "bitmap"); goto out; } ret = ocfs2_block_bitmap_new(ost->ost_fs, "forbidden group " "descriptors", &forbidden); if (ret) { com_err(whoami, ret, "while allocating forbidden descs " "bitmap"); goto out; } ocfs2_calc_cluster_groups(ost->ost_fs->fs_clusters, ost->ost_fs->fs_blocksize, &cgs); max_recs = ocfs2_chain_recs_per_inode(ost->ost_fs->fs_blocksize); for (i = 0, blkno = ost->ost_fs->fs_first_cg_blkno; i < cgs.cgs_cluster_groups; i++, blkno = i * ocfs2_clusters_to_blocks(ost->ost_fs, cgs.cgs_cpg)) { o2fsck_bitmap_set(allowed, blkno, NULL); } ret = verify_chain_alloc(ost, di, buf1, buf2, NULL, allowed, forbidden); if (ret) { com_err(whoami, ret, "while looking up chain allocator inode " "%"PRIu64, (uint64_t)di->i_blkno); goto out; } /* remove descs that we found in the chain that we didn't expect */ for (blkno = ost->ost_fs->fs_first_cg_blkno; !ocfs2_bitmap_find_next_set(forbidden, blkno, &blkno); blkno++) { if (!prompt(ost, PY, PR_GROUP_UNEXPECTED_DESC, "Block %"PRIu64" is a group " "descriptor in the bitmap chain allocator but it " "isn't at one of the pre-determined locations and " "so shouldn't be in the allocator. Remove it " "from the chain?", blkno)) { mark_group_used(ost, &cs, blkno, 1, NULL); continue; } ret = ocfs2_read_group_desc(ost->ost_fs, blkno, (char *)bg); if (ret) { com_err(whoami, ret, "while reading a cluster bitmap " "group descriptor from block %"PRIu64, blkno); continue; } unlink_group_desc(ost, di, bg, blkno); } /* find the blocks that we think should have been in the chains * but which weren't found */ for (i = 0, blkno = ost->ost_fs->fs_first_cg_blkno; i < cgs.cgs_cluster_groups; i++, blkno = i * ocfs2_clusters_to_blocks(ost->ost_fs, cgs.cgs_cpg)) { if (ocfs2_bitmap_test(allowed, blkno, &was_set)) continue; if (!was_set) continue; if (!prompt(ost, PY, PR_GROUP_EXPECTED_DESC, "Block %"PRIu64" should be a group " "descriptor for the bitmap chain allocator but it " "wasn't found in any chains. Reinitialize it as " "a group desc and link it into the bitmap " "allocator?", blkno)) continue; /* some input that init_desc might need */ if (i == cgs.cgs_cluster_groups - 1) bits = cgs.cgs_tail_group_bits; else bits = cgs.cgs_cpg; chain = i % max_recs; /* we've been asked to link in this desc specifically. we're * using the predictability of the group descs to rebuild * its values.. we only preserve the bitmap if the signature * and generation match this volume */ ret = ocfs2_read_group_desc(ost->ost_fs, blkno, (char *)bg); if (ret == OCFS2_ET_BAD_GROUP_DESC_MAGIC || bg->bg_generation != ost->ost_fs_generation) { memset(bg, 0, ost->ost_fs->fs_blocksize); ocfs2_init_group_desc(ost->ost_fs, bg, blkno, ost->ost_fs_generation, di->i_blkno, bits, chain, 0); ret = 0; } if (ret) { com_err(whoami, ret, "while reading a cluster bitmap " "group descriptor from block %"PRIu64, blkno); continue; } /* first some easy fields */ bg->bg_size = ocfs2_group_bitmap_size( ost->ost_fs->fs_blocksize, 0, OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_feature_incompat); bg->bg_bits = bits; bg->bg_parent_dinode = di->i_blkno; bg->bg_blkno = blkno; ocfs2_set_bit(0, bg->bg_bitmap); bg->bg_free_bits_count = bg->bg_bits - o2fsck_bitcount(bg->bg_bitmap, (bg->bg_bits + 7)/ 8); /* we have to be kind of careful with the chain */ chain = ocfs2_min(chain, di->id2.i_chain.cl_next_free_rec); chain = ocfs2_min(chain, max_recs); bg->bg_chain = chain; /* now really link it in */ rec = &di->id2.i_chain.cl_recs[bg->bg_chain]; bg->bg_next_group = rec->c_blkno; ret = ocfs2_write_group_desc(ost->ost_fs, blkno, (char *)bg); if (ret) { com_err(whoami, ret, "while writing a cluster group " "descriptor at block %"PRIu64, blkno); ost->ost_saw_error = 1; continue; } /* and update the calling inode */ rec->c_free += bg->bg_free_bits_count; rec->c_total += bg->bg_bits; rec->c_blkno = blkno; /* ugh */ if (di->id2.i_chain.cl_next_free_rec == bg->bg_chain && di->id2.i_chain.cl_next_free_rec < max_recs) di->id2.i_chain.cl_next_free_rec++; di->id1.bitmap1.i_used += bg->bg_bits - bg->bg_free_bits_count; di->id1.bitmap1.i_total += bg->bg_bits; di->i_clusters += (bg->bg_bits / di->id2.i_chain.cl_bpc); di->i_size = (uint64_t)di->i_clusters * ost->ost_fs->fs_clustersize; ret = ocfs2_write_inode(ost->ost_fs, di->i_blkno, (char *)di); if (ret) { com_err(whoami, ret, "while writing inode alloc inode " "%"PRIu64, (uint64_t)di->i_blkno); ost->ost_saw_error = 1; goto out; } mark_group_used(ost, &cs, bg->bg_blkno, 1, bg); } out: if (allowed) ocfs2_bitmap_free(allowed); if (forbidden) ocfs2_bitmap_free(forbidden); return ret; } /* this returns an error if it didn't leave the allocators in a state that * the iterators will be able to work with. There is probably some room * for more resiliance here. */ errcode_t o2fsck_pass0(o2fsck_state *ost) { errcode_t ret; uint64_t blkno; uint32_t pre_repair_clusters; char *blocks = NULL; char *pre_cache_buf = NULL; struct ocfs2_dinode *di = NULL; ocfs2_filesys *fs = ost->ost_fs; ocfs2_cached_inode **ci; int max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; int i, type, bitmap_retried = 0; printf("Pass 0a: Checking cluster allocation chains\n"); /* * The I/O buffer is 3 blocks. We apportion our I/O buffer * thusly: * * blocks[0] is the allocator inode we're working on. * blocks[1] & blocks[2] are used to hold group descriptors * in functions below this one. */ ret = ocfs2_malloc_blocks(fs->fs_io, 3, &blocks); if (ret) { com_err(whoami, ret, "while allocating block buffers"); goto out; } di = (struct ocfs2_dinode *)blocks; /* * We also allocate a pre-cache buffer of 4MB for reading entire * suballocator groups. Some blocksizes have smaller groups, but * none have larger (see * libocfs2/alloc.c:ocfs2_clusters_per_group()). This allows * us to pre-fill the I/O cache; we're already reading the group * descriptor, so slurping the whole thing shouldn't hurt. * * If this allocation fails, we just ignore it. It's a cache. */ o2fsck_reset_blocks_cached(); if (o2fsck_worth_caching(1)) { ret = ocfs2_malloc_blocks(fs->fs_io, ocfs2_blocks_in_bytes(fs, 4 * 1024 * 1024), &pre_cache_buf); if (ret) verbosef("Unable to allocate group pre-cache " "buffer, %s\n", "ignoring"); } ret = ocfs2_malloc0(max_slots * sizeof(ocfs2_cached_inode *), &ost->ost_inode_allocs); if (ret) { com_err(whoami, ret, "while cached inodes for each node"); goto out; } ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &blkno); if (ret) { com_err(whoami, ret, "while looking up the global bitmap " "inode"); goto out; } ret = ocfs2_read_inode(ost->ost_fs, blkno, (char *)di); if (ret) { com_err(whoami, ret, "reading inode alloc inode " "%"PRIu64" for verification", blkno); goto out; } verbosef("found inode alloc %"PRIu64" at block %"PRIu64"\n", (uint64_t)di->i_blkno, blkno); ret = maybe_fix_clusters_per_group(ost, di); if (ret) goto out; /* * during resize, we may update the global bitmap but fails to * to update i_clusters in superblock, so ask the user which one * to use before checking. */ if (fs->fs_super->i_clusters != di->i_clusters) { if (prompt(ost, PY, PR_SUPERBLOCK_CLUSTERS, "Superblock has clusters set to %u instead of %u " "recorded in global_bitmap, it may be caused by an " "unsuccessful resize. Trust global_bitmap?", fs->fs_super->i_clusters, di->i_clusters)) { ost->ost_num_clusters = di->i_clusters; fs->fs_clusters = di->i_clusters; fs->fs_blocks = ocfs2_clusters_to_blocks(fs, fs->fs_clusters); ret = o2fsck_state_reinit(fs, ost); if (ret) { com_err(whoami, ret, "while reinit " "o2fsck_state."); goto out; } } } retry_bitmap: pre_repair_clusters = di->i_clusters; ret = verify_bitmap_descs(ost, di, blocks + ost->ost_fs->fs_blocksize, blocks + (ost->ost_fs->fs_blocksize * 2)); if (ret) goto out; if (pre_repair_clusters != di->i_clusters) { if (prompt(ost, PY, PR_FIXED_CHAIN_CLUSTERS, "Repair of global_bitmap changed the filesystem " "from %u clusters to %u clusters. Trust " "global_bitmap?", pre_repair_clusters, di->i_clusters)) { ost->ost_num_clusters = di->i_clusters; fs->fs_clusters = di->i_clusters; fs->fs_blocks = ocfs2_clusters_to_blocks(fs, fs->fs_clusters); ret = o2fsck_state_reinit(fs, ost); if (ret) { com_err(whoami, ret, "while reinit " "o2fsck_state."); goto out; } /* * The reinit clears the bits found during the * scan of the global bitmap. We need to go over * them again. They really should come out clean * this time. If they don't, we probably have * a serious problem. * * In an interactive run, the user can keep * retrying and abort when they give up. In a * non-interactive mode, we can't loop forever. */ if (ost->ost_ask || !bitmap_retried) { bitmap_retried = 1; verbosef("Restarting global_bitmap %s\n", "scan"); goto retry_bitmap; } } } printf("Pass 0b: Checking inode allocation chains\n"); /* first the global inode alloc and then each of the node's * inode allocators */ type = GLOBAL_INODE_ALLOC_SYSTEM_INODE; i = -1; for ( ; i < max_slots; i++, type = INODE_ALLOC_SYSTEM_INODE) { ret = ocfs2_lookup_system_inode(fs, type, i, &blkno); if (ret) { com_err(whoami, ret, "while looking up the inode " "allocator type %d for node %d\n", type, i); goto out; } ret = ocfs2_read_inode(ost->ost_fs, blkno, (char *)di); if (ret) { com_err(whoami, ret, "reading inode alloc inode " "%"PRIu64" for verification", blkno); goto out; } verbosef("found inode alloc %"PRIu64" at block %"PRIu64"\n", (uint64_t)di->i_blkno, blkno); ret = verify_chain_alloc(ost, di, blocks + ost->ost_fs->fs_blocksize, blocks + (ost->ost_fs->fs_blocksize * 2), pre_cache_buf, NULL, NULL); /* XXX maybe helped by the alternate super block */ if (ret) goto out; if (i == -1) ci = &ost->ost_global_inode_alloc; else ci = &ost->ost_inode_allocs[i]; ret = ocfs2_read_cached_inode(ost->ost_fs, blkno, ci); if (ret) { com_err(whoami, ret, "while reading node %d's inode " "allocator inode %"PRIu64, i, blkno); goto out; } ret = ocfs2_load_chain_allocator(ost->ost_fs, *ci); if (ret) { com_err(whoami, ret, "while loading inode %"PRIu64" " "as a chain allocator", blkno); ocfs2_free_cached_inode(ost->ost_fs, *ci); *ci = NULL; goto out; } } printf("Pass 0c: Checking extent block allocation chains\n"); for (i = 0; i < max_slots; i++) { ret = ocfs2_lookup_system_inode(fs, EXTENT_ALLOC_SYSTEM_INODE, i, &blkno); if (ret) { com_err(whoami, ret, "while looking up the extent " "allocator type %d for node %d\n", type, i); goto out; } ret = ocfs2_read_inode(ost->ost_fs, blkno, (char *)di); if (ret) { com_err(whoami, ret, "reading inode alloc inode " "%"PRIu64" for verification", blkno); goto out; } verbosef("found extent alloc %"PRIu64" at block %"PRIu64"\n", (uint64_t)di->i_blkno, blkno); ret = verify_chain_alloc(ost, di, blocks + ost->ost_fs->fs_blocksize, blocks + (ost->ost_fs->fs_blocksize * 2), pre_cache_buf, NULL, NULL); /* XXX maybe helped by the alternate super block */ if (ret) goto out; } out: if (pre_cache_buf) ocfs2_free(&pre_cache_buf); if (blocks) ocfs2_free(&blocks); if (ret) o2fsck_free_inode_allocs(ost); return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass1.c0000644000176100017610000012667511500500544014125 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * Pass 1 is arguably where the greatest concentration of special rules * in fsck live. It walks through all the inodes that it can get its hands * on and verifies them. For now it only walks the inode allocator groups * that pass 0 was able to verify. One can imagine it getting other potential * inodes from other places. * * The complexity comes in deciding that inodes are valid. There are different * critera for system inodes, allocator inodes, and the usual different * unix inode file types. * * Pass 1 build up in-memory copies of the inode allocators that are written * back as the real inode allocators if inconsistencies are found between * the bitmaps and the inodes. It also builds up many inode-dependent data * structures that are used by future passes: * - icount map of inodes to what their current on-disk i_link_count is * - bitmap of which inodes are directories or regular files * - directory blocks that it finds off of directory inodes * * Pass 1 also compiles a bitmap of all clusters used by the filesystem. * If any clusters are shared by more than one inode, a bitmap of * duplicate clusters is also created. * * The end of Pass 1 is when the found block bitmap should contain all the * blocks in the system that are in use. This is used to derive the set of * clusters that should be allocated. The cluster chain allocator is loaded * and synced up with this set and potentially written back. After that point * fsck can use libocfs2 to allocate and free clusters as usual. * * XXX * check many, many, more i_ fields for each inode type * make sure the inode's dtime/count/valid match in update_inode_alloc * more carefully track cluster use in conjunction with pass 0 * free an inodes chains and extents and such if we free it */ #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "dirblocks.h" #include "dirparents.h" #include "extent.h" #include "icount.h" #include "fsck.h" #include "pass1.h" #include "pass1b.h" #include "problem.h" #include "util.h" #include "xattr.h" #include "refcount.h" static const char *whoami = "pass1"; void o2fsck_free_inode_allocs(o2fsck_state *ost) { uint16_t i; ocfs2_free_cached_inode(ost->ost_fs, ost->ost_global_inode_alloc); for (i = 0; i < OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots; i++) ocfs2_free_cached_inode(ost->ost_fs, ost->ost_inode_allocs[i]); } /* update our in memory images of the inode chain alloc bitmaps. these * will be written out at the end of pass1 and the library will read * them off disk for use from then on. */ static void update_inode_alloc(o2fsck_state *ost, struct ocfs2_dinode *di, uint64_t blkno, int val) { int16_t slot; uint16_t max_slots, yn; errcode_t ret = OCFS2_ET_INTERNAL_FAILURE; ocfs2_cached_inode *cinode; int oldval; val = !!val; if (ost->ost_write_inode_alloc_asked && !ost->ost_write_inode_alloc) return; max_slots = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots; for (slot = OCFS2_INVALID_SLOT; slot != max_slots; slot++, ret = OCFS2_ET_INTERNAL_FAILURE) { if (slot == OCFS2_INVALID_SLOT) cinode = ost->ost_global_inode_alloc; else cinode = ost->ost_inode_allocs[slot]; /* we might have had trouble reading the chains in pass 0 */ if (cinode == NULL) continue; ret = ocfs2_chain_force_val(ost->ost_fs, cinode, blkno, val, &oldval); if (ret) { if (ret != OCFS2_ET_INVALID_BIT) com_err(whoami, ret, "while trying to set " "inode %"PRIu64"'s allocation to '%d' " "in slot %"PRId16"'s chain", blkno, val, slot); continue; } /* hmm, de hmm. it would be kind of nice if the bitmaps * didn't use 'int' but rather some real boolean construct */ oldval = !!oldval; /* this slot covers the inode. see if we've changed the * bitmap and if the user wants us to keep tracking it and * write back the new map */ if (oldval != val && !ost->ost_write_inode_alloc_asked) { yn = prompt(ost, PY, PR_INODE_ALLOC_REPAIR, "Inode %"PRIu64" is marked as %s but its " "position in the inode allocator is " "marked as %s. Fix the allocation of this " "and all future inodes?", blkno, val ? "valid" : "invalid", oldval ? "in use" : "free"); ost->ost_write_inode_alloc_asked = 1; ost->ost_write_inode_alloc = !!yn; if (!ost->ost_write_inode_alloc) o2fsck_free_inode_allocs(ost); } break; } if (ret) { com_err(whoami, ret, "while trying to set inode %"PRIu64"'s " "allocation to '%d'. None of the slots chain " "allocator's had a group covering the inode.", blkno, val); goto out; } verbosef("updated inode %"PRIu64" alloc to %d from %d in slot " "%"PRId16"\n", blkno, val, oldval, slot); /* make sure the inode's fields are consistent if it's allocated */ if (val == 1 && slot != (int16_t)di->i_suballoc_slot && prompt(ost, PY, PR_INODE_SUBALLOC, "Inode %"PRIu64" indicates that it was allocated " "from slot %"PRId16" but slot %"PRId16"'s chain allocator " "covers the inode. Fix the inode's record of where it is " "allocated?", blkno, di->i_suballoc_slot, slot)) { di->i_suballoc_slot = slot; o2fsck_write_inode(ost, di->i_blkno, di); } out: return; } static errcode_t verify_local_alloc(o2fsck_state *ost, struct ocfs2_dinode *di) { struct ocfs2_local_alloc *la = &di->id2.i_lab; uint32_t max; int broken = 0, changed = 0, clear = 0; errcode_t ret = 0; verbosef("la_bm_off %u size %u total %u used %u\n", la->la_bm_off, la->la_size, di->id1.bitmap1.i_total, di->id1.bitmap1.i_used); max = ocfs2_local_alloc_size(ost->ost_fs->fs_blocksize); if (la->la_size > max) { broken = 1; if (prompt(ost, PY, PR_LALLOC_SIZE, "Local alloc inode %"PRIu64" claims to " "have %u bytes of bitmap data but %u bytes is the " "maximum allowed. Set the inode's count to the " "maximum?", (uint64_t)di->i_blkno, la->la_size, max)) { la->la_size = max; changed = 1; } } if (di->id1.bitmap1.i_total == 0) { /* ok, it's not used. we don't mark these errors as * 'broken' as the kernel shouldn't care.. right? */ if (di->id1.bitmap1.i_used != 0) { if (prompt(ost, PY, PR_LALLOC_NZ_USED, "Local alloc inode %"PRIu64" " "isn't in use bit its i_used isn't 0. Set it to " "0?", (uint64_t)di->i_blkno)) { di->id1.bitmap1.i_used = 0; changed = 1; } } if (la->la_bm_off != 0) { if (prompt(ost, PY, PR_LALLOC_NZ_BM, "Local alloc inode %"PRIu64" " "isn't in use bit its i_bm_off isn't 0. Set it " "to 0?", (uint64_t)di->i_blkno)) { la->la_bm_off = 0; changed = 1; } } goto out; } if (la->la_bm_off >= ost->ost_fs->fs_clusters) { broken = 1; if (prompt(ost, PY, PR_LALLOC_BM_OVERRUN, "Local alloc inode %"PRIu64" claims to " "contain a bitmap that starts at cluster %u but " "the volume contains %u clusters. Mark the local " "alloc bitmap as unused?", (uint64_t)di->i_blkno, la->la_bm_off, ost->ost_fs->fs_clusters)) { clear = 1; } } if (di->id1.bitmap1.i_total > la->la_size * 8) { broken = 1; if (prompt(ost, PY, PR_LALLOC_BM_SIZE, "Local alloc inode %"PRIu64" claims to " "have a bitmap with %u bits but the inode can only " "fit %u bits. Clamp the bitmap size to this " "maxmum?", (uint64_t)di->i_blkno, di->id1.bitmap1.i_total, la->la_size * 8)) { di->id1.bitmap1.i_total = la->la_size * 8; changed = 1; } } if (la->la_bm_off + di->id1.bitmap1.i_total > ost->ost_fs->fs_clusters) { broken = 1; if (prompt(ost, PY, PR_LALLOC_BM_STRADDLE, "Local alloc inode %"PRIu64" claims to " "have a bitmap that covers clusters numbered %u " "through %u but %u is the last valid cluster. " "Mark the local bitmap as unused?", (uint64_t)di->i_blkno, la->la_bm_off, la->la_bm_off + di->id1.bitmap1.i_total - 1, ost->ost_fs->fs_clusters - 1)) { clear = 1; } /* we can't possibly check _used if bm/off and total are * so busted */ goto out; } if (di->id1.bitmap1.i_used > di->id1.bitmap1.i_total) { broken = 1; if (prompt(ost, PY, PR_LALLOC_USED_OVERRUN, "Local alloc inode %"PRIu64" claims to " "contain a bitmap with %u bits and %u used. Set " "i_used down to %u?", (uint64_t)di->i_blkno, di->id1.bitmap1.i_total, di->id1.bitmap1.i_used, di->id1.bitmap1.i_total)) { di->id1.bitmap1.i_used = di->id1.bitmap1.i_total; changed = 1; } } out: if (broken && !clear && prompt(ost, PY, PR_LALLOC_CLEAR, "Local alloc inode %"PRIu64" contained errors. " "Mark it as unused instead of trying to correct its " "bitmap?", (uint64_t)di->i_blkno)) { clear = 1; } if (clear) { di->id1.bitmap1.i_total = 0; di->id1.bitmap1.i_used = 0; la->la_bm_off = 0; memset(la->la_bitmap, 0, ocfs2_local_alloc_size(ost->ost_fs->fs_blocksize)); changed = 1; } if (changed) { ret = ocfs2_write_inode(ost->ost_fs, di->i_blkno, (char *)di); if (ret) { com_err(whoami, ret, "while writing local alloc inode " "%"PRIu64, (uint64_t)di->i_blkno); ost->ost_write_error = 1; ret = 0; } } return ret; } /* this just makes sure the truncate log contains consistent data, it doesn't * do anything with it yet */ static errcode_t verify_truncate_log(o2fsck_state *ost, struct ocfs2_dinode *di) { struct ocfs2_truncate_log *tl = &di->id2.i_dealloc; uint16_t max, i; int changed = 0; errcode_t ret = 0; verbosef("tl_count %u tl_used %u (tl_reserved1 %u)\n", tl->tl_count, tl->tl_used, tl->tl_reserved1); max = ocfs2_truncate_recs_per_inode(ost->ost_fs->fs_blocksize); if (tl->tl_count > max && prompt(ost, PY, PR_DEALLOC_COUNT, "Truncate log inode %"PRIu64" claims space for %u records but only %u " "records are possible. Set the inode's count to the maximum?", (uint64_t)di->i_blkno, tl->tl_count, max)) { tl->tl_count = max; changed = 1; } if (tl->tl_used > tl->tl_count && prompt(ost, PY, PR_DEALLOC_USED, "Truncate log inode %"PRIu64" claims to be using %u records but the " "inode can only hold %u records. Change the number used to reflect " "the maximum possible in the inode?", (uint64_t)di->i_blkno, tl->tl_used, tl->tl_count)) { tl->tl_used = tl->tl_count; changed = 1; } for (i = 0; i < ocfs2_min(max, tl->tl_used); i++) { struct ocfs2_truncate_rec *tr = &tl->tl_recs[i]; int zero = 0; verbosef("t_start %u t_clusters %u\n", tr->t_start, tr->t_clusters); if (tr->t_start == 0) continue; if (tr->t_start >= ost->ost_fs->fs_clusters && prompt(ost, PY, PR_TRUNCATE_REC_START_RANGE, "Truncate record at offset %u in truncate log " "inode %"PRIu64" starts at cluster %u but there " "are %u clusters in the volume. Remove this record " "from the log?", i, (uint64_t)di->i_blkno, tr->t_start, ost->ost_fs->fs_clusters)) { zero = 1; } if (tr->t_start + tr->t_clusters < tr->t_start && prompt(ost, PY, PR_TRUNCATE_REC_WRAP, "Truncate record at offset %u in truncate log " "inode %"PRIu64" starts at cluster %u and contains " "%u clusters. It can't have this many clusters " "as that overflows the number of possible clusters " "in a volume. Remove this record from the log?", i, (uint64_t)di->i_blkno, tr->t_start, tr->t_clusters)) { zero = 1; } if (tr->t_start + tr->t_clusters > ost->ost_fs->fs_clusters && prompt(ost, PY, PR_TRUNCATE_REC_RANGE, "Truncate record at offset %u in truncate log " "inode %"PRIu64" starts at cluster %u and contains " "%u clusters. It can't have this many clusters " "as this volume only has %u clusters. Remove this " "record from the log?", i, (uint64_t)di->i_blkno, tr->t_start, tr->t_clusters, ost->ost_fs->fs_clusters)) { zero = 1; } if (zero) { tr->t_start = 0; tr->t_clusters = 0; changed = 1; } } if (changed) { ret = ocfs2_write_inode(ost->ost_fs, di->i_blkno, (char *)di); if (ret) { com_err(whoami, ret, "while writing truncate log inode " "%"PRIu64, (uint64_t)di->i_blkno); ost->ost_write_error = 1; ret = 0; } } return ret; } /* Check the basics of the ocfs2_dinode itself. If we find problems * we clear the VALID flag and the caller will see that and update * inode allocations and write the inode to disk. * * XXX the o2fsck_write_inode helpers need to be fixed here*/ static void o2fsck_verify_inode_fields(ocfs2_filesys *fs, o2fsck_state *ost, uint64_t blkno, struct ocfs2_dinode *di) { int clear = 0; verbosef("checking inode %"PRIu64"'s fields\n", blkno); if (di->i_fs_generation != ost->ost_fs_generation) { if (prompt(ost, PY, PR_INODE_GEN, "Inode read from block %"PRIu64" looks " "like it is valid but it has a generation of %x " "that doesn't match the current volume's " "generation of %x. This is probably a harmless " "old inode. Mark it deleted?", blkno, di->i_fs_generation, ost->ost_fs_generation)) { clear = 1; goto out; } if (prompt(ost, PY, PR_INODE_GEN_FIX, "Update the inode's generation to match " "the volume?")) { di->i_fs_generation = ost->ost_fs_generation; o2fsck_write_inode(ost, blkno, di); } } /* do we want to detect and delete corrupt system dir/files here * so we can recreate them later ? */ /* also make sure the journal inode is ok? */ /* clamp inodes to > OCFS2_SUPER_BLOCK_BLKNO && < fs->fs_blocks? */ /* XXX need to compare the lifetime of inodes (uninitialized? * in use? orphaned? deleted? garbage?) to understand what * fsck can do to fix it up */ if (di->i_blkno != blkno && prompt(ost, PY, PR_INODE_BLKNO, "Inode read from block %"PRIu64" has i_blkno set " "to %"PRIu64". Set the inode's i_blkno value to reflect " "its location on disk?", blkno, (uint64_t)di->i_blkno)) { di->i_blkno = blkno; o2fsck_write_inode(ost, blkno, di); } /* offer to clear a non-directory root inode so that * pass3:check_root() can re-create it */ if ((di->i_blkno == fs->fs_root_blkno) && !S_ISDIR(di->i_mode) && prompt(ost, PY, PR_ROOT_NOTDIR, "Root inode isn't a directory. Clear it in " "preparation for fixing it?")) { clear = 1; goto out; } if (di->i_dtime && prompt(ost, PY, PR_INODE_NZ_DTIME, "Inode %"PRIu64" is in use but has a non-zero dtime. Reset " "the dtime to 0?", (uint64_t)di->i_blkno)) { di->i_dtime = 0ULL; o2fsck_write_inode(ost, blkno, di); } if ((di->i_dyn_features & OCFS2_INLINE_DATA_FL) && !ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) && prompt(ost, PY, PR_INLINE_DATA_FLAG_INVALID, "Inode %"PRIu64" has inline flag set but the volume " "doesn't support it. Clear it?", (uint64_t)di->i_blkno)) { di->i_dyn_features &= ~OCFS2_INLINE_DATA_FL; o2fsck_write_inode(ost, blkno, di); } if ((di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL) && !ocfs2_refcount_tree(OCFS2_RAW_SB(fs->fs_super)) && prompt(ost, PY, PR_REFCOUNT_FLAG_INVALID, "Inode %"PRIu64" has refcount flag set but the volume " "doesn't support it. Clear it?", (uint64_t)di->i_blkno)) { di->i_dyn_features &= ~OCFS2_HAS_REFCOUNT_FL; o2fsck_write_inode(ost, blkno, di); } if (ocfs2_refcount_tree(OCFS2_RAW_SB(fs->fs_super)) && (!(di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL) && di->i_refcount_loc) && prompt(ost, PY, PR_REFCOUNT_LOC_INVALID, "Inode %"PRIu64" doesn't have refcount flag set but have " "refcount loc set. Clear it?", (uint64_t)di->i_blkno)) { di->i_refcount_loc = 0; o2fsck_write_inode(ost, blkno, di); } if (S_ISDIR(di->i_mode)) { o2fsck_bitmap_set(ost->ost_dir_inodes, blkno, NULL); o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 0, 0, di->i_flags & OCFS2_ORPHANED_FL); } else if (S_ISREG(di->i_mode)) { o2fsck_bitmap_set(ost->ost_reg_inodes, blkno, NULL); } else if (S_ISLNK(di->i_mode)) { /* we only make sure a link's i_size matches * the link names length in the file data later when * we walk the inode's blocks */ } else { if (!S_ISCHR(di->i_mode) && !S_ISBLK(di->i_mode) && !S_ISFIFO(di->i_mode) && !S_ISSOCK(di->i_mode)) { clear = 1; goto out; } /* i_size? what other sanity testing for devices? */ } /* put this after all opportunities to clear so we don't have to * unwind it */ if (di->i_links_count) o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno, di->i_links_count); /* orphan inodes are a special case. if -n is given pass4 will try * and assert that their links_count should include the dirent * reference from the orphan dir. */ if (di->i_flags & OCFS2_ORPHANED_FL && di->i_links_count == 0) o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno, 1); if (di->i_flags & OCFS2_LOCAL_ALLOC_FL) verify_local_alloc(ost, di); else if (di->i_flags & OCFS2_DEALLOC_FL) verify_truncate_log(ost, di); out: /* XXX when we clear we need to also free whatever blocks may have * hung off this inode that haven't already been reserved. we want * to do this on the transition from valid to invalid, not just * any time we see an invalid inode (somewhat obviously). */ if (clear) { di->i_flags &= ~OCFS2_VALID_FL; o2fsck_write_inode(ost, blkno, di); /* if we cleared the inode then we're going to be * forbidding directory entries from referencing it.. we * should back-out the inode count we found in the inode * so that we're not surprised when there aren't any * references to it in pass 4 */ o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno, 0); } } struct verifying_blocks { unsigned vb_clear:1, vb_saw_link_null:1; uint64_t vb_link_len; uint64_t vb_num_blocks; uint64_t vb_last_block; o2fsck_state *vb_ost; struct ocfs2_dinode *vb_di; errcode_t vb_ret; }; /* last_block and num_blocks would be different in a sparse file */ static void vb_saw_block(struct verifying_blocks *vb, uint64_t bcount) { vb->vb_num_blocks++; if (bcount > vb->vb_last_block) vb->vb_last_block = bcount; } static errcode_t process_link_block(struct verifying_blocks *vb, uint64_t blkno) { char *buf = NULL, *null; errcode_t ret = 0; unsigned int blocksize = vb->vb_ost->ost_fs->fs_blocksize; if (vb->vb_saw_link_null) goto out; ret = ocfs2_malloc_blocks(vb->vb_ost->ost_fs->fs_io, 1, &buf); if (ret) { com_err(whoami, ret, "while allocating room to read a block " "of link data"); goto out; } ret = ocfs2_read_blocks(vb->vb_ost->ost_fs, blkno, 1, buf); if (ret) goto out; null = memchr(buf, 0, blocksize); if (null != NULL) { vb->vb_link_len += null - buf; vb->vb_saw_link_null = 1; } else { vb->vb_link_len += blocksize; } out: if (buf) ocfs2_free(&buf); return ret; } static void check_link_data(struct verifying_blocks *vb) { struct ocfs2_dinode *di = vb->vb_di; o2fsck_state *ost = vb->vb_ost; uint64_t expected, link_max; char *null; verbosef("found a link: num %"PRIu64" last %"PRIu64" len " "%"PRIu64" null %d\n", (uint64_t)vb->vb_num_blocks, (uint64_t)vb->vb_last_block, (uint64_t)vb->vb_link_len, vb->vb_saw_link_null); if (di->i_clusters == 0 && vb->vb_num_blocks > 0 && prompt(ost, PY, PR_LINK_FAST_DATA, "Symlink inode %"PRIu64" claims to be a fast symlink " "but has file data. Clear the inode?", (uint64_t)di->i_blkno)) { vb->vb_clear = 1; return; } /* if we're a fast link we doctor the verifying_blocks book-keeping * to satisfy the following checks */ if (di->i_clusters == 0) { link_max = ost->ost_fs->fs_blocksize - offsetof(typeof(*di), id2.i_symlink); null = memchr(di->id2.i_symlink, 0, link_max); if (null != NULL) { vb->vb_saw_link_null = 1; vb->vb_link_len = (char *)null - (char *)di->id2.i_symlink; } else vb->vb_link_len = link_max; expected = 0; } else expected = ocfs2_blocks_in_bytes(ost->ost_fs, vb->vb_link_len + 1); /* XXX this could offer to null terminate */ if (!vb->vb_saw_link_null) { if (prompt(ost, PY, PR_LINK_NULLTERM, "The target of symlink inode %"PRIu64" " "isn't null terminated. Clear the inode?", (uint64_t)di->i_blkno)) { vb->vb_clear = 1; return; } } if (di->i_size != vb->vb_link_len) { if (prompt(ost, PY, PR_LINK_SIZE, "The target of symlink inode %"PRIu64" " "is %"PRIu64" bytes long on disk, but i_size is " "%"PRIu64" bytes long. Update i_size to reflect " "the length on disk?", (uint64_t)di->i_blkno, vb->vb_link_len, (uint64_t)di->i_size)) { di->i_size = vb->vb_link_len; o2fsck_write_inode(ost, di->i_blkno, di); return; } } /* maybe we don't shrink link target allocations, I don't know, * someone will holler if this is wrong :) */ if (vb->vb_num_blocks < expected) { if (prompt(ost, PN, PR_LINK_BLOCKS, "The target of symlink inode %"PRIu64" " "fits in %"PRIu64" blocks but the inode has " "%"PRIu64" allocated. Clear the inode?", (uint64_t)di->i_blkno, expected, vb->vb_num_blocks)) { vb->vb_clear = 1; return; } } } static int verify_block(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data) { struct verifying_blocks *vb = priv_data; struct ocfs2_dinode *di = vb->vb_di; o2fsck_state *ost = vb->vb_ost; errcode_t ret = 0; /* someday we may want to worry about holes in files here */ if (S_ISDIR(di->i_mode)) { verbosef("adding dir block %"PRIu64"\n", blkno); ret = o2fsck_add_dir_block(&ost->ost_dirblocks, (uint64_t)di->i_blkno, blkno, bcount); if (ret) { com_err(whoami, ret, "while trying to track block in " "directory inode %"PRIu64, (uint64_t)di->i_blkno); } } else if (S_ISLNK(di->i_mode)) ret = process_link_block(vb, blkno); if (ret) { vb->vb_ret = ret; return OCFS2_BLOCK_ABORT; } vb_saw_block(vb, bcount); return 0; } /* This may be accessed many times for the same cluster. * currently I haven't find a good way to avoid this since * we use ocfs2_block_iterate_inode to clear the clusters. * Anyway, it works well in clearing clusters. */ static int clear_block(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data) { struct verifying_blocks *vb = priv_data; o2fsck_state *ost = vb->vb_ost; uint32_t clusters = ocfs2_blocks_to_clusters(ost->ost_fs, blkno); o2fsck_mark_cluster_unallocated(ost, clusters); return 0; } static errcode_t o2fsck_check_dx_dir(o2fsck_state *ost, struct ocfs2_dinode *di) { errcode_t ret = 0; char *buf = NULL; struct ocfs2_dx_root_block *dx_root; ocfs2_filesys *fs = ost->ost_fs; struct extent_info ei = {0,}; int changed = 0; if (!ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super))) goto out; if (!ocfs2_dir_indexed(di)) goto out; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, (uint64_t)di->i_dx_root, buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)buf; if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) goto out; ei.chk_rec_func = o2fsck_check_extent_rec; ei.mark_rec_alloc_func = o2fsck_mark_tree_clusters_allocated; ei.para = di; ret = check_el(ost, &ei, di->i_blkno, &dx_root->dr_list, ocfs2_extent_recs_per_dx_root(fs->fs_blocksize), &changed); if (ret) goto out; if (changed) { ret = ocfs2_write_dx_root(fs, (uint64_t)di->i_dx_root, (char *)dx_root); if (ret) com_err(whoami, ret, "while writing an updated " "dx_root block at %"PRIu64" for inode %"PRIu64, (uint64_t)di->i_dx_root, (uint64_t)di->i_blkno); } out: if (buf) ocfs2_free(&buf); return ret; } /* * this verifies i_size and i_clusters for inodes that use i_list to * reference extents of data. */ static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost, uint64_t blkno, struct ocfs2_dinode *di) { uint64_t expected = 0, unexpected = 0; errcode_t ret = 0; struct verifying_blocks vb = { .vb_ost = ost, .vb_di = di, }; /* don't bother to verify for inodes that don't have i_list, * we have to trust i_mode/i_clusters to tell us that a symlink * has put target data in the union instead of i_list */ if ((di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_BITMAP_FL | OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL)) || (S_ISLNK(di->i_mode) && di->i_clusters == 0)) return 0; if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { /* * We add i_blkno as the dir block, so when the dir's * inode_no is the same as dir_block_no, we can tell * that this dir is inlinded and help us in the following * directory check. */ if (S_ISDIR(di->i_mode)) { ret = o2fsck_add_dir_block(&ost->ost_dirblocks, di->i_blkno, di->i_blkno, 0); if (ret) return ret; } goto size_cluster_check; } ret = o2fsck_check_extents(ost, di); if (ret == 0) ret = ocfs2_block_iterate_inode(fs, di, OCFS2_BLOCK_FLAG_APPEND, verify_block, &vb); if (vb.vb_ret) ret = vb.vb_ret; if (ret) { com_err(whoami, ret, "while iterating over the blocks for " "inode %"PRIu64, (uint64_t)di->i_blkno); goto out; } ret = o2fsck_check_dx_dir(ost, di); if (ret) { com_err(whoami, ret, "while iterating over the dir indexed " "tree for directory inode %"PRIu64, (uint64_t)di->i_blkno); goto out; } if (S_ISLNK(di->i_mode)) check_link_data(&vb); if (S_ISDIR(di->i_mode) && vb.vb_num_blocks == 0 && prompt(ost, PY, PR_DIR_ZERO, "Inode %"PRIu64" is a zero length directory, clear it?", (uint64_t)di->i_blkno)) { vb.vb_clear = 1; } /* * We have a helper function,clear_block, that clears an inode and * backs it out of any book-keeping that it might have been included * in, as though it was never seen. */ if (vb.vb_clear) { di->i_links_count = 0; o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno, di->i_links_count); di->i_dtime = time(NULL); /* clear valid flag and stuff. */ ret = ocfs2_block_iterate_inode(fs, di, OCFS2_BLOCK_FLAG_APPEND, clear_block, &vb); di->i_flags &= !OCFS2_VALID_FL; o2fsck_write_inode(ost, di->i_blkno, di); /* for a directory, we also need to clear it * from the dir_parent rb-tree. */ if (S_ISDIR(di->i_mode)) ocfsck_remove_dir_parent(&ost->ost_dir_parents, di->i_blkno); goto out; } size_cluster_check: /* * i_size and i_cluster mean quite different between a non-sparse * and sparse file system. * * For a non-sparse file system, the file size should be within the * clusters it is allocated, and the cluster size should be the same * as the number we calculate from extent iteration. * * For a sparse file, the file size can be greater than the real * last block offsets recorded in the extent list, but it shouldn't be * less than that cluster offset since we have already allocated some * blocks at that offset, so if the size is too small, fix it to the * end of the visible cluster end. It is also reasonable for a file * which has no allocated blocks but any number of byte sizes, * so we don't need to check its size either. * * In an inline file, i_clusters should be zero and i_size should be * less than the max inline data size. */ if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { uint16_t max_inline = ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di); /* id_count is check first. */ if (di->id2.i_data.id_count != max_inline && prompt(ost, PY, PR_INLINE_DATA_COUNT_INVALID, "Inode %"PRIu64" is inline file and its id_count " "is %u which should be %u. Correct this " "count?", (uint64_t)di->i_blkno, di->id2.i_data.id_count, max_inline)) { di->id2.i_data.id_count = max_inline; o2fsck_write_inode(ost, blkno, di); } /* i_size is checked for symlinks elsewhere */ if (di->i_size > max_inline && prompt(ost, PY, PR_INODE_INLINE_SIZE, "Inode %"PRIu64 "has a size of %"PRIu64" which exceeds the max " "inline data size %u. " "Correct the file size?", (uint64_t)di->i_blkno, (uint64_t)di->i_size, max_inline)) { di->i_size = max_inline; o2fsck_write_inode(ost, blkno, di); } if (di->i_clusters > 0 && prompt(ost, PY, PR_INODE_INLINE_CLUSTERS, "Inode %"PRIu64" has %"PRIu32" clusters but it has " "inline data flag set. " "Correct the number of clusters?", (uint64_t)di->i_blkno, di->i_clusters)) { di->i_clusters = 0; o2fsck_write_inode(ost, blkno, di); } } else if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) { if (vb.vb_num_blocks > 0) { expected = ocfs2_blocks_to_clusters(fs, vb.vb_last_block + 1); expected *= fs->fs_clustersize; unexpected = expected - fs->fs_clustersize; /* * NOTE: * - i_size is checked for symlinks elsewhere * - We're not going to check this for dirs * since it would be legal for a dir inode * whose i_size(in clusters) was less than * i_clusters, even on a sparsed filesystem */ if (!S_ISLNK(di->i_mode) && !S_ISDIR(di->i_mode) && di->i_size <= unexpected && prompt(ost, PY, PR_INODE_SPARSE_SIZE, "Inode %"PRIu64 " has a size of %"PRIu64" but has %"PRIu64 " blocks of actual data. " "Correct the file size?", (uint64_t)di->i_blkno, (uint64_t)di->i_size, vb.vb_last_block + 1)) { di->i_size = expected; o2fsck_write_inode(ost, blkno, di); } } if (vb.vb_num_blocks > 0) expected = ocfs2_clusters_in_blocks(fs, vb.vb_num_blocks); if (di->i_clusters != expected && prompt(ost, PY, PR_INODE_SPARSE_CLUSTERS, "Inode %"PRIu64" has %"PRIu32" clusters but its " "blocks fit in %"PRIu64" clusters. " "Correct the number of clusters?", (uint64_t)di->i_blkno, di->i_clusters, expected)) { di->i_clusters = expected; o2fsck_write_inode(ost, blkno, di); } } else { if (vb.vb_num_blocks > 0) expected = (vb.vb_last_block + 1) * fs->fs_blocksize; /* i_size is checked for symlinks elsewhere */ if (!S_ISLNK(di->i_mode) && di->i_size > expected && prompt(ost, PY, PR_INODE_SIZE, "Inode %"PRIu64" has a size of " "%"PRIu64" but has %"PRIu64" bytes of actual data. " "Correct the file size?", (uint64_t)di->i_blkno, (uint64_t)di->i_size, expected)) { di->i_size = expected; o2fsck_write_inode(ost, blkno, di); } if (vb.vb_num_blocks > 0) expected = ocfs2_clusters_in_blocks(fs, vb.vb_last_block + 1); if (di->i_clusters != expected && prompt(ost, PY, PR_INODE_CLUSTERS, "Inode %"PRIu64" has %"PRIu32" clusters but its " "blocks fit in %"PRIu64" clusters. Correct the " "number of clusters?", (uint64_t)di->i_blkno, di->i_clusters, expected)) { di->i_clusters = expected; o2fsck_write_inode(ost, blkno, di); } } out: return ret; } /* * we just make sure that the bits that are clear in the local * alloc are still reserved in the global bitmap. We leave * cleaning of the local windows to recovery in the file system. */ static void mark_local_allocs(o2fsck_state *ost) { int16_t slot; uint16_t max_slots; char *buf = NULL; errcode_t ret; uint64_t blkno, start, end; struct ocfs2_dinode *di; struct ocfs2_local_alloc *la; int bit; max_slots = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating an inode buffer to " "use when verifying local alloc inode bitmaps."); goto out; } di = (struct ocfs2_dinode *)buf; for (slot = 0; slot < max_slots; slot++) { ret = ocfs2_lookup_system_inode(ost->ost_fs, LOCAL_ALLOC_SYSTEM_INODE, slot, &blkno); if (ret) { com_err(whoami, ret, "while looking up local alloc " "inode %"PRIu64" to verify its bitmap", blkno); goto out; } ret = ocfs2_read_inode(ost->ost_fs, blkno, buf); if (ret) { com_err(whoami, ret, "while reading local alloc " "inode %"PRIu64" to verify its bitmap", blkno); goto out; } la = &di->id2.i_lab; if (di->id1.bitmap1.i_total == 0) continue; /* make sure we don't try to work with a crazy bitmap. It * can only be this crazy if the user wouldn't let us fix * it up.. just ignore it */ if (la->la_size > ocfs2_local_alloc_size(ost->ost_fs->fs_blocksize) || di->id1.bitmap1.i_used > di->id1.bitmap1.i_total || di->id1.bitmap1.i_total > la->la_size * 8) continue; start = la->la_bm_off; end = la->la_bm_off + di->id1.bitmap1.i_total; if (start >= ost->ost_fs->fs_clusters || end < start || end > ost->ost_fs->fs_clusters) continue; /* bits that are clear in the local alloc haven't been * used by the slot yet, they must still be set in the * main bitmap. bits that are set might have been used * and already freed in the main bitmap. */ for(bit = 0; bit < di->id1.bitmap1.i_total; bit++) { bit = ocfs2_find_next_bit_clear(la->la_bitmap, di->id1.bitmap1.i_total, bit); if (bit < di->id1.bitmap1.i_total) { verbosef("bit %u is clear, reserving " "cluster %u\n", bit, bit + la->la_bm_off); o2fsck_mark_cluster_allocated(ost, bit + la->la_bm_off); } } } out: if (buf) ocfs2_free(&buf); return; } /* * Clusters that are in the truncate logs should still be allocated. We just * make sure our accounting realizes this and let the kernel replay the logs * and free them. This will change someday when fsck learns to fully practice * recovery isntead of just making sure that the system is in a coherent * recoverable state. */ static void mark_truncate_logs(o2fsck_state *ost) { int16_t slot; uint16_t max_slots, i, max; struct ocfs2_truncate_log *tl; uint64_t blkno; struct ocfs2_dinode *di; char *buf = NULL; errcode_t ret; max_slots = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots; max = ocfs2_truncate_recs_per_inode(ost->ost_fs->fs_blocksize); ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating an inode buffer to " "use accounting for records in truncate logs"); goto out; } di = (struct ocfs2_dinode *)buf; for (slot = 0; slot < max_slots; slot++) { ret = ocfs2_lookup_system_inode(ost->ost_fs, TRUNCATE_LOG_SYSTEM_INODE, slot, &blkno); if (ret) { com_err(whoami, ret, "while looking up truncate log " "inode %"PRIu64" to account for its records", blkno); goto out; } ret = ocfs2_read_inode(ost->ost_fs, blkno, buf); if (ret) { com_err(whoami, ret, "while reading truncate log " "inode %"PRIu64" to account for its records", blkno); goto out; } tl = &di->id2.i_dealloc; for (i = 0; i < ocfs2_min(tl->tl_used, max); i++) { struct ocfs2_truncate_rec *tr = &tl->tl_recs[i]; if (tr->t_start == 0) continue; verbosef("rec [%u, %u] at off %u\n", tr->t_start, tr->t_clusters, i); o2fsck_mark_clusters_allocated(ost, tr->t_start, tr->t_clusters); } } out: if (buf) ocfs2_free(&buf); return; } /* XXX we really need to get the latch stuff straight */ static errcode_t force_cluster_bit(o2fsck_state *ost, ocfs2_cached_inode *ci, uint64_t bit, int val) { errcode_t ret; char *reason; if (!val) { reason = "marked in the global cluster bitmap but it isn't in " "use. Clear its bit in the bitmap?"; } else { reason = "in use but isn't set in the global cluster bitmap. " "Set its bit in the bitmap?"; } if (!prompt(ost, PY, PR_CLUSTER_ALLOC_BIT, "Cluster %"PRIu64" is %s", bit, reason)) return 0; ret = ocfs2_chain_force_val(ost->ost_fs, ci, bit, !!val, NULL); if (ret) com_err(whoami, ret, "while trying to %s bit %"PRIu64" in the " "cluster bitmap", val ? "set" : "clear", bit); return ret; } static inline int bit_in_backup_super(uint64_t bit, uint32_t *clusters, int len) { int i; for (i = 0; i < len; i++) { if (bit == clusters[i]) return 1; } return 0; } /* once we've iterated all the inodes we should have the current working * set of which blocks we think are in use. we use this to derive the set * of clusters that should be allocated in the cluster chain allocators. we * don't iterate over all clusters like we do inodes.. */ static void write_cluster_alloc(o2fsck_state *ost) { ocfs2_cached_inode *ci = NULL; errcode_t ret; uint64_t blkno, last_cbit, cbit, cbit_found; struct ocfs2_cluster_group_sizes cgs; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; uint32_t clusters[OCFS2_MAX_BACKUP_SUPERBLOCKS]; int backup_super = 0, num = 0, i; ocfs2_calc_cluster_groups(ost->ost_fs->fs_clusters, ost->ost_fs->fs_blocksize, &cgs); /* first load the cluster chain alloc so we can compare */ ret = ocfs2_lookup_system_inode(ost->ost_fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &blkno); if (ret) { com_err(whoami, ret, "while looking up the cluster bitmap " "allocator inode"); goto out; } /* load in the cluster chain allocator */ ret = ocfs2_read_cached_inode(ost->ost_fs, blkno, &ci); if (ret) { com_err(whoami, ret, "while reading the cluster bitmap " "allocator inode from block %"PRIu64, blkno); goto out; } ret = ocfs2_load_chain_allocator(ost->ost_fs, ci); if (ret) { com_err(whoami, ret, "while loading the cluster bitmap " "allocator from block %"PRIu64, blkno); goto out; } /* handle the condition of backup superblock. */ memset(&blocks, 0, sizeof(blocks)); memset(&clusters, 0, sizeof(clusters)); if (OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(ost->ost_fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB)) { num = ocfs2_get_backup_super_offsets(ost->ost_fs, blocks, ARRAY_SIZE(blocks)); if (num) { backup_super = 1; for (i = 0; i < num; i++) clusters[i] = ocfs2_blocks_to_clusters(ost->ost_fs, blocks[i]); } } /* we walk our found blocks bitmap to find clusters that we think * are in use. each time we find a block in a cluster we skip ahead * to the first block of the next cluster when looking for the next. * * once we have a cluster we think is allocated we walk the cluster * chain alloc bitmaps from the last cluster we thought was allocated * to make sure that all the bits are cleared on the way. * * we special case the number of clusters as the cluster offset which * indicates that the rest of the bits to the end of the bitmap * should be clear. * * we should take backup superblock as a special case since it doesn't * belong to any inode. So it shouldn't be exist in * ost->ost_allocated_clusters. */ for (last_cbit = 0, cbit = 0; cbit < ost->ost_fs->fs_clusters; cbit++, last_cbit = cbit) { ret = ocfs2_bitmap_find_next_set(ost->ost_allocated_clusters, cbit, &cbit); /* clear to the end */ if (ret == OCFS2_ET_BIT_NOT_FOUND) cbit = ost->ost_fs->fs_clusters; ret = ocfs2_bitmap_find_next_set(ci->ci_chains, last_cbit, &cbit_found); if (ret == OCFS2_ET_BIT_NOT_FOUND) cbit_found = ost->ost_fs->fs_clusters; verbosef("cbit %"PRIu64" last_cbit %"PRIu64" cbit_found " "%"PRIu64"\n", cbit, last_cbit, cbit_found); if (cbit_found == cbit) continue; /* clear set bits that should have been clear up to cbit */ while (cbit_found < cbit) { /* check whether the volume has backup blocks * and if yes, check whether the cluster contains * one of the backup blocks. */ if (!backup_super || !bit_in_backup_super(cbit_found, clusters, num)) force_cluster_bit(ost, ci, cbit_found, 0); cbit_found++; ret = ocfs2_bitmap_find_next_set(ci->ci_chains, cbit_found, &cbit_found); if (ret == OCFS2_ET_BIT_NOT_FOUND) cbit_found = ost->ost_fs->fs_clusters; } /* make sure cbit is set before moving on */ if (cbit_found != cbit && cbit != ost->ost_fs->fs_clusters) force_cluster_bit(ost, ci, cbit, 1); } ret = ocfs2_write_chain_allocator(ost->ost_fs, ci); if (ret) com_err(whoami, ret, "while trying to write back the cluster " "bitmap allocator"); out: if (ci) ocfs2_free_cached_inode(ost->ost_fs, ci); } static void write_inode_alloc(o2fsck_state *ost) { int max_slots = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots; ocfs2_cached_inode **ci; errcode_t ret; int i; if (!ost->ost_write_inode_alloc) return; for (i = -1; i < max_slots; i++) { if (i == OCFS2_INVALID_SLOT) ci = &ost->ost_global_inode_alloc; else ci = &ost->ost_inode_allocs[i]; if (*ci == NULL) continue; verbosef("writing slot %d's allocator\n", i); ret = ocfs2_write_chain_allocator(ost->ost_fs, *ci); if (ret) com_err(whoami, ret, "while trying to write back slot " "%d's inode allocator", i); } o2fsck_free_inode_allocs(ost); } errcode_t o2fsck_pass1(o2fsck_state *ost) { errcode_t ret; uint64_t blkno; char *buf; struct ocfs2_dinode *di; ocfs2_inode_scan *scan; ocfs2_filesys *fs = ost->ost_fs; int valid; printf("Pass 1: Checking inodes and blocks.\n"); ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating inode buffer"); goto out; } di = (struct ocfs2_dinode *)buf; ret = ocfs2_open_inode_scan(fs, &scan); if (ret) { com_err(whoami, ret, "while opening inode scan"); goto out_free; } for(;;) { ret = ocfs2_get_next_inode(scan, &blkno, buf); if (ret) { /* we don't deal with corrupt inode allocation * files yet. They won't be files for much longer. * In the future the intent is to clean up inode * allocation if scanning returns an error. */ com_err(whoami, ret, "while getting next inode"); goto out_close_scan; } if (blkno == 0) break; valid = 0; /* we never consider inodes who don't have a signature */ if (!memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) { ocfs2_swap_inode_to_cpu(fs, di); /* We only consider inodes whose generations don't * match if the user has asked us to */ if ((ost->ost_fix_fs_gen || (di->i_fs_generation == ost->ost_fs_generation))) { if (di->i_flags & OCFS2_VALID_FL) o2fsck_verify_inode_fields(fs, ost, blkno, di); if (di->i_flags & OCFS2_VALID_FL) { ret = o2fsck_check_refcount_tree(ost, di); if (ret) goto out; ret = o2fsck_check_blocks(fs, ost, blkno, di); if (ret) goto out; ret = o2fsck_check_xattr(ost, di); if (ret) goto out; } valid = di->i_flags & OCFS2_VALID_FL; } } update_inode_alloc(ost, di, blkno, valid); } mark_local_allocs(ost); mark_truncate_logs(ost); ret = o2fsck_check_mark_refcounted_clusters(ost); if (ret) com_err(whoami, ret, "while checking refcounted clusters"); write_cluster_alloc(ost); write_inode_alloc(ost); out_close_scan: ocfs2_close_inode_scan(scan); out_free: ocfs2_free(&buf); if (!ret && ost->ost_duplicate_clusters) ret = ocfs2_pass1_dups(ost); out: return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass1b.c0000644000176100017610000011422711500500544014255 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. * * The scheme of the passes is based on e2fsck pass1b.c, * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. * * -- * * Pass 1B-D are extra passes invoked only if Pass 1 discovered clusters * in use by more than one inode. They are very expensive, as they cannot * make easy use of the I/O cache. * * Pass 1 has already built us a bitmap of duplicated clusters. For * efficiency, it doesn't try to track who owns them. Now we need to know. * Because Pass 1 has already repaired and verified the allocators, we can * trust them to be consistent. * * Pass 1B rescans the inodes and builds two rbtrees. The first rbtree * maps a duplicate cluster to the inodes that share it. The second rbtree * keeps track of all inodes with duplicates. If an inode has more than * one duplicate cluster, it will get cloned or deleted when the first one * is evaluated in Pass 1D. The second rbtree prevents us from re-examining * this inode for each addition cluster it used to share. * * Pass 1C walks the directory tree and gives names to each inode. This * is so the user can see the name of the file they are fixing. The pass * does a depth-first traversal of the tree. For every inode in the * rbtree of duplicates it finds, it stores the path for it. It will * ignore errors in the directory tree, because we haven't fixed it yet. * When reporting to the user, inodes without names will just get their * inode number printed. * * Pass 1D does the actual fixing. Each inode with duplicate clusters can * cloned to an entirely new file or deleted. Regardless of the choice, * an inode that is fixed no longer has duplicate clusters. Cloning is * done by creating a new inode and copying the data to it. Then the * extent trees are swapped between the original and clone inode. This * leaves the original inode with a good extent tree. Finally, the clone * inode is removed and its extent tree released. If deletion is chosen * instead of cloning, the original inode is removed. Either way, we end * up over-freeing the clusters in the main bitmap. At the end, we run * the list of multi-claimed clusters again. If the cluster still has * claimers, it is forced on in the bitmap. If it does not, it is forced * clear in the bitmap. If we crash in the middle, we're still safe. A * re-run of fsck will determine whether the over-freed clusters are * actually in use. * * Once Pass1D is complete, the ost_duplicate_clusters bitmap can be * freed. */ #include #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "dirblocks.h" #include "dirparents.h" #include "extent.h" #include "icount.h" #include "fsck.h" #include "pass1.h" #include "pass1b.h" #include "problem.h" #include "util.h" #include "xattr.h" static const char *whoami = "UNSET!"; /* states for dup_inode.di_state */ #define DUP_INODE_CLONED 0x01 #define DUP_INODE_REMOVED 0x02 /* A simple test to see if we should care about this dup inode anymore */ #define DUP_INODE_HANDLED (DUP_INODE_CLONED | DUP_INODE_REMOVED) /* * Keep track of an inode that claims clusters shared by other objects. */ struct dup_inode { struct rb_node di_node; /* The block number of this inode */ uint64_t di_ino; /* The path to this inode */ char *di_path; /* * i_flags from the inode. We need to refuse deletion of * system files, and chain allocators are even worse. */ uint32_t di_flags; /* What we've done to it. */ unsigned int di_state; /* the refcount tree it has. */ uint64_t di_refcount_loc; }; /* * Keep track of clusters that are claimed by multiple objects. */ struct dup_cluster_owner { struct list_head dco_list; /* * The block number of the owning inode. This is the lookup key * for the dup inode rbtree. */ uint64_t dco_ino; /* * virtual offset in the extent tree. * Only valid for an extent tree, 0 for a chain file. */ uint32_t dco_cpos; }; struct dup_cluster { struct rb_node dc_node; /* The physical cluster that is multiply-claimed */ uint32_t dc_cluster; /* List of owning inodes */ struct list_head dc_owners; }; /* * Context for Passes 1B-D. */ struct dup_context { /* Tree of multiply-claimed clusters */ struct rb_root dup_clusters; /* Inodes that own them */ struct rb_root dup_inodes; /* How many there are */ uint64_t dup_inode_count; }; /* See if the cluster rbtree has the given cluster. */ static struct dup_cluster *dup_cluster_lookup(struct dup_context *dct, uint32_t cluster) { struct rb_node *p = dct->dup_clusters.rb_node; struct dup_cluster *dc; while (p) { dc = rb_entry(p, struct dup_cluster, dc_node); if (cluster < dc->dc_cluster) { p = p->rb_left; } else if (cluster > dc->dc_cluster) { p = p->rb_right; } else return dc; } return NULL; } static void dup_cluster_insert(struct dup_context *dct, struct dup_cluster *insert_dc) { struct rb_node **p = &dct->dup_clusters.rb_node; struct rb_node *parent = NULL; struct dup_cluster *dc = NULL; while (*p) { parent = *p; dc = rb_entry(parent, struct dup_cluster, dc_node); if (insert_dc->dc_cluster < dc->dc_cluster) { p = &(*p)->rb_left; dc = NULL; } else if (insert_dc->dc_cluster > dc->dc_cluster) { p = &(*p)->rb_right; dc = NULL; } else assert(0); /* Caller checked */ } rb_link_node(&insert_dc->dc_node, parent, p); rb_insert_color(&insert_dc->dc_node, &dct->dup_clusters); } /* See if the inode rbtree has the given cluster. */ static struct dup_inode *dup_inode_lookup(struct dup_context *dct, uint64_t ino) { struct rb_node *p = dct->dup_inodes.rb_node; struct dup_inode *di; while (p) { di = rb_entry(p, struct dup_inode, di_node); if (ino < di->di_ino) { p = p->rb_left; } else if (ino > di->di_ino) { p = p->rb_right; } else return di; } return NULL; } static void dup_inode_insert(struct dup_context *dct, struct dup_inode *insert_di) { struct rb_node **p = &dct->dup_inodes.rb_node; struct rb_node *parent = NULL; struct dup_inode *di = NULL; while (*p) { parent = *p; di = rb_entry(parent, struct dup_inode, di_node); if (insert_di->di_ino < di->di_ino) { p = &(*p)->rb_left; di = NULL; } else if (insert_di->di_ino > di->di_ino) { p = &(*p)->rb_right; di = NULL; } else assert(0); /* Caller checked */ } rb_link_node(&insert_di->di_node, parent, p); rb_insert_color(&insert_di->di_node, &dct->dup_inodes); dct->dup_inode_count++; } /* * Given a (cluster,inode) tuple, insert the appropriate metadata * into the context. */ static errcode_t dup_insert(struct dup_context *dct, uint32_t cluster, struct ocfs2_dinode *dinode, uint32_t v_cpos) { errcode_t ret; struct list_head *p; struct dup_cluster *dc, *new_dc = NULL; struct dup_inode *di, *new_di = NULL; struct dup_cluster_owner *dco, *new_dco = NULL; ret = ocfs2_malloc0(sizeof(struct dup_cluster), &new_dc); if (ret) { com_err(whoami, ret, "while allocating duplicate cluster tracking " "structures"); goto out; } INIT_LIST_HEAD(&new_dc->dc_owners); new_dc->dc_cluster = cluster; ret = ocfs2_malloc0(sizeof(struct dup_inode), &new_di); if (ret) { com_err(whoami, ret, "while allocating duplicate cluster tracking " "structures"); goto out; } new_di->di_ino = dinode->i_blkno; new_di->di_flags = dinode->i_flags; new_di->di_refcount_loc = dinode->i_refcount_loc; ret = ocfs2_malloc0(sizeof(struct dup_cluster_owner), &new_dco); if (ret) { com_err(whoami, ret, "while allocating duplicate cluster tracking " "structures"); goto out; } new_dco->dco_ino = dinode->i_blkno; new_dco->dco_cpos = v_cpos; dc = dup_cluster_lookup(dct, cluster); if (!dc) { dup_cluster_insert(dct, new_dc); dc = new_dc; new_dc = NULL; } di = dup_inode_lookup(dct, dinode->i_blkno); if (!di) { dup_inode_insert(dct, new_di); di = new_di; new_di = NULL; } dco = NULL; list_for_each(p, &dc->dc_owners) { dco = list_entry(p, struct dup_cluster_owner, dco_list); if (dco->dco_ino == dinode->i_blkno) break; dco = NULL; } if (!dco) { list_add_tail(&new_dco->dco_list, &dc->dc_owners); dco = new_dco; new_dco = NULL; } out: if (new_dc) ocfs2_free(&new_dc); if (new_di) ocfs2_free(&new_di); if (new_dco) ocfs2_free(&new_dco); return ret; } static void o2fsck_empty_dup_context(struct dup_context *dct) { struct dup_cluster *dc; struct dup_inode *di; struct dup_cluster_owner *dco; struct rb_node *node; struct list_head *p, *next; while ((node = rb_first(&dct->dup_clusters)) != NULL) { dc = rb_entry(node, struct dup_cluster, dc_node); list_for_each_safe(p, next, &dc->dc_owners) { dco = list_entry(p, struct dup_cluster_owner, dco_list); list_del(&dco->dco_list); ocfs2_free(&dco); } rb_erase(&dc->dc_node, &dct->dup_clusters); ocfs2_free(&dc); } while ((node = rb_first(&dct->dup_inodes)) != NULL) { di = rb_entry(node, struct dup_inode, di_node); rb_erase(&di->di_node, &dct->dup_inodes); ocfs2_free(&di); } } /* * Pass 1B */ struct process_extents_context { o2fsck_state *ost; struct dup_context *dct; struct ocfs2_dinode *di; errcode_t ret; uint64_t global_bitmap_blkno; char *extra_buf; }; static errcode_t process_dup_clusters(struct process_extents_context *pc, uint32_t p_cpos, uint32_t clusters, uint32_t v_cpos) { int was_set; errcode_t ret = 0; while (clusters) { ret = ocfs2_bitmap_test(pc->ost->ost_duplicate_clusters, p_cpos, &was_set); if (ret) { com_err(whoami, ret, "while testing cluster %"PRIu32" of inode " "%"PRIu64" in the duplicate cluster map", p_cpos, pc->di->i_blkno); break; } if (was_set) { verbosef("Marking multiply-claimed cluster %"PRIu32 " as claimed by inode %"PRIu64"\n", p_cpos, pc->di->i_blkno); ret = dup_insert(pc->dct, p_cpos, pc->di, v_cpos); if (ret) { com_err(whoami, ret, "while marking duplicate cluster " "%"PRIu32" as owned by inode " "%"PRIu64, p_cpos, pc->di->i_blkno); break; } } p_cpos++; v_cpos++; clusters--; } return ret; } static int process_inode_chains(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data) { struct process_extents_context *pc = priv_data; uint32_t clusters = pc->di->id2.i_chain.cl_cpg; struct ocfs2_group_desc *gd; int i; if (pc->di->i_blkno == pc->global_bitmap_blkno) clusters = 1; if (!ocfs2_supports_discontig_bg(OCFS2_RAW_SB(fs->fs_super)) || (pc->di->i_blkno == pc->global_bitmap_blkno)) { pc->ret = process_dup_clusters(pc, ocfs2_blocks_to_clusters(fs, gd_blkno), clusters, 0); goto out; } pc->ret = ocfs2_read_group_desc(fs, gd_blkno, pc->extra_buf); if (pc->ret) goto out; gd = (struct ocfs2_group_desc *)pc->extra_buf; if (!ocfs2_gd_is_discontig(gd)) { pc->ret = process_dup_clusters(pc, ocfs2_blocks_to_clusters(fs, gd_blkno), clusters, 0); goto out; } /* Now check the discontiguous group case. */ for (i = 0; i < gd->bg_list.l_next_free_rec; i++) { struct ocfs2_extent_rec *rec = &gd->bg_list.l_recs[i]; pc->ret = process_dup_clusters(pc, ocfs2_blocks_to_clusters(fs, rec->e_blkno), rec->e_leaf_clusters, rec->e_cpos); } out: return pc->ret ? OCFS2_CHAIN_ERROR | OCFS2_CHAIN_ABORT : 0; } static int process_inode_extents(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { struct process_extents_context *pc = priv_data; assert(!tree_depth); pc->ret = process_dup_clusters(pc, ocfs2_blocks_to_clusters(fs, rec->e_blkno), rec->e_leaf_clusters, rec->e_cpos); return pc->ret ? OCFS2_EXTENT_ERROR | OCFS2_EXTENT_ABORT : 0; } static errcode_t process_xattr_header(struct process_extents_context *pc, struct ocfs2_xattr_header *xh) { int i; errcode_t ret = 0; struct ocfs2_xattr_entry *xe; struct ocfs2_xattr_value_root *xv; for (i = 0 ; i < xh->xh_count; i++) { xe = &xh->xh_entries[i]; if (ocfs2_xattr_is_local(xe)) continue; xv = (struct ocfs2_xattr_value_root *) ((void *)xh + xe->xe_name_offset + OCFS2_XATTR_SIZE(xe->xe_name_len)); ret = ocfs2_extent_iterate_xattr(pc->ost->ost_fs, &xv->xr_list, xv->xr_last_eb_blk, OCFS2_EXTENT_FLAG_DATA_ONLY, process_inode_extents, pc, NULL); if (ret) com_err(whoami, ret, "while processing xattrs on inode %"PRIu64, pc->di->i_blkno); if (!ret) ret = pc->ret; if (ret) break; } return ret; } static errcode_t process_one_bucket_list(struct process_extents_context *pc, struct ocfs2_extent_rec *rec) { int i; errcode_t ret; char *bucket; struct ocfs2_xattr_header *xh; uint64_t blkno = ocfs2_clusters_to_blocks(pc->ost->ost_fs, rec->e_cpos); int bucket_count = rec->e_leaf_clusters * ocfs2_xattr_buckets_per_cluster(pc->ost->ost_fs); ret = ocfs2_malloc_blocks(pc->ost->ost_fs->fs_io, ocfs2_blocks_per_xattr_bucket(pc->ost->ost_fs), &bucket); if (ret) { com_err(whoami, ret, "while allocating an xattr bucket buffer"); return ret; } xh = (struct ocfs2_xattr_header *)bucket; for (i = 0; i < bucket_count; i++) { ret = ocfs2_read_xattr_bucket(pc->ost->ost_fs, blkno, bucket); if (ret) { com_err(whoami, ret, "while reading the xattr bucket at " "%"PRIu64" on inode %"PRIu64, blkno, pc->di->i_blkno); break; } if (!i) bucket_count = xh->xh_num_buckets; ret = process_xattr_header(pc, xh); if (ret) break; blkno += ocfs2_blocks_per_xattr_bucket(pc->ost->ost_fs); } ocfs2_free(&bucket); return ret; } static int process_xattr_buckets(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { errcode_t ret; struct process_extents_context *pc = priv_data; assert(!tree_depth); pc->ret = process_dup_clusters(pc, ocfs2_blocks_to_clusters(fs, rec->e_blkno), rec->e_leaf_clusters, rec->e_cpos); if (pc->ret) goto out; ret = process_one_bucket_list(pc, rec); out: if (!ret) ret = pc->ret; return pc->ret ? OCFS2_EXTENT_ERROR | OCFS2_EXTENT_ABORT : 0; } static errcode_t process_xattr_tree(struct process_extents_context *pc, struct ocfs2_xattr_block *xb) { errcode_t ret; ret = ocfs2_extent_iterate_xattr(pc->ost->ost_fs, &xb->xb_attrs.xb_root.xt_list, xb->xb_attrs.xb_root.xt_last_eb_blk, OCFS2_EXTENT_FLAG_DATA_ONLY, process_xattr_buckets, pc, NULL); if (ret) com_err(whoami, ret, "while processing xattrs on inode %"PRIu64, pc->di->i_blkno); if (!ret) ret = pc->ret; return ret; } static errcode_t process_xattr_block(struct process_extents_context *pc) { errcode_t ret; char *blk = NULL; struct ocfs2_xattr_block *xb; ret = ocfs2_malloc_block(pc->ost->ost_fs->fs_io, &blk); if (ret) { com_err(whoami, ret, "while allocating a buffer to read the xattr block " "on inode %"PRIu64, pc->di->i_xattr_loc); goto out; } ret = ocfs2_read_xattr_block(pc->ost->ost_fs, pc->di->i_xattr_loc, blk); if (ret) { com_err(whoami, ret, "while reading externel block of" " extended attributes "); goto out; } xb = (struct ocfs2_xattr_block *)blk; if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) ret = process_xattr_header(pc, &xb->xb_attrs.xb_header); else ret = process_xattr_tree(pc, xb); out: if (blk) ocfs2_free(&blk); return ret; } static errcode_t process_inode_xattrs(struct process_extents_context *pc) { errcode_t ret = 0; struct ocfs2_xattr_header *xh; if (pc->di->i_dyn_features & OCFS2_INLINE_XATTR_FL) { xh = (struct ocfs2_xattr_header *) ((void *)pc->di + pc->ost->ost_fs->fs_blocksize - pc->di->i_xattr_inline_size); ret = process_xattr_header(pc, xh); if (ret) goto out; } if (pc->di->i_xattr_loc) ret = process_xattr_block(pc); out: return ret; } static errcode_t pass1b_process_inode(o2fsck_state *ost, struct dup_context *dct, uint64_t ino, struct ocfs2_dinode *di, char *extra_buf) { errcode_t ret = 0; static uint64_t global_bitmap_blkno = 0; struct process_extents_context pc = { .ost = ost, .dct = dct, .di = di, .extra_buf = extra_buf, }; /* * The global bitmap needs magic in process_inode_chains. Let's * look it up here. It's static, so this only happens once. */ if (!global_bitmap_blkno) { ret = ocfs2_lookup_system_inode(ost->ost_fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &global_bitmap_blkno); if (ret) { com_err(whoami, ret, "while looking up the cluster bitmap " "allocator inode"); goto out; } } pc.global_bitmap_blkno = global_bitmap_blkno; /* * Skip extent processing for for inodes that don't have i_list or * i_chains. Like Pass 1, we have to trust i_mode/i_clusters to * tell us that a symlink has put target data in the union instead * of i_list */ if ((di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_DEALLOC_FL)) || (S_ISLNK(di->i_mode) && di->i_clusters == 0)) goto xattrs; if (di->i_flags & OCFS2_CHAIN_FL) ret = ocfs2_chain_iterate(ost->ost_fs, pc.di->i_blkno, process_inode_chains, &pc); else ret = ocfs2_extent_iterate_inode(ost->ost_fs, di, OCFS2_EXTENT_FLAG_DATA_ONLY, NULL, process_inode_extents, &pc); if (ret) com_err(whoami, ret, "while processing inode %"PRIu64, ino); else ret = pc.ret; if (ret) goto out; xattrs: if (di->i_dyn_features & OCFS2_HAS_XATTR_FL) ret = process_inode_xattrs(&pc); out: return ret; } static errcode_t o2fsck_pass1b(o2fsck_state *ost, struct dup_context *dct) { errcode_t ret; uint64_t blkno; char *buf = NULL, *extra_buf = NULL; struct ocfs2_dinode *di; ocfs2_inode_scan *scan; ocfs2_filesys *fs = ost->ost_fs; whoami = "pass1b"; printf("Running additional passes to resolve clusters claimed by " "more than one inode...\n" "Pass 1b: Determining ownership of multiply-claimed clusters\n"); ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating inode buffer"); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &extra_buf); if (ret) { com_err(whoami, ret, "while allocating extra buffer"); goto out; } di = (struct ocfs2_dinode *)buf; ret = ocfs2_open_inode_scan(fs, &scan); if (ret) { com_err(whoami, ret, "while opening inode scan"); goto out; } /* * The inode allocators should be good after Pass 1. * Valid inodes should really be valid. Errors are real errors. */ for(;;) { ret = ocfs2_get_next_inode(scan, &blkno, buf); if (ret) { com_err(whoami, ret, "while getting next inode"); break; } if (blkno == 0) break; if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) continue; ocfs2_swap_inode_to_cpu(fs, di); if (di->i_fs_generation != ost->ost_fs_generation) continue; if (!(di->i_flags & OCFS2_VALID_FL)) continue; ret = pass1b_process_inode(ost, dct, blkno, di, extra_buf); if (ret) break; } ocfs2_close_inode_scan(scan); out: if (buf) ocfs2_free(&buf); if (extra_buf) ocfs2_free(&extra_buf); return ret; } /* * Pass 1C */ struct dir_to_scan { struct list_head ts_list; uint64_t ts_ino; char *ts_path; }; struct dir_scan_context { o2fsck_state *ds_ost; struct dup_context *ds_dct; /* Inodes we still have to find */ int64_t ds_inodes_left; /* Subdirs that are pending */ struct list_head ds_paths; /* The cwd's path and ino */ uint64_t ds_ino; char *ds_cwd; int ds_cwdlen; }; static void pass1c_warn(errcode_t ret) { static int warned = 0; if (warned) return; warned = 1; com_err(whoami, ret, "while finding path names in Pass 1c. The pass will " "continue, but some inodes may be described by " "inode number instead of name."); } static char *de_to_path(struct dir_scan_context *scan, struct ocfs2_dir_entry *de) { /* The 2 is for the path separator and the null */ int copied, pathlen = scan->ds_cwdlen + de->name_len + 2; char *path = NULL; /* We start with an empty cwd as we add '/' or '//' */ const char *cwdstr = scan->ds_cwdlen ? scan->ds_cwd : ""; const char *sep = "/"; /* Don't repeat '/' */ if (scan->ds_cwdlen && (scan->ds_cwd[scan->ds_cwdlen - 1] == '/')) sep = ""; if (de->name_len && (de->name[0] == '/')) sep = ""; if (!ocfs2_malloc0(sizeof(char) * pathlen, &path)) { copied = snprintf(path, pathlen, "%s%s%.*s", cwdstr, sep, de->name_len, de->name); assert(copied < pathlen); } return path; } static void push_dir(struct dir_scan_context *scan, struct ocfs2_dir_entry *de) { errcode_t ret; struct dir_to_scan *ts = NULL; ret = ocfs2_malloc0(sizeof(struct dir_to_scan), &ts); if (ret) goto warn; ts->ts_ino = de->inode; ts->ts_path = de_to_path(scan, de); if (!ts->ts_path) { ret = OCFS2_ET_NO_MEMORY; goto warn; } list_add(&ts->ts_list, &scan->ds_paths); return; warn: if (ts) ocfs2_free(&ts); pass1c_warn(ret); } static void set_next_cwd(struct dir_scan_context *scan) { struct dir_to_scan *ts; if (scan->ds_cwd) ocfs2_free(&scan->ds_cwd); ts = list_entry(scan->ds_paths.next, struct dir_to_scan, ts_list); list_del(&ts->ts_list); /* Steal the string from ts */ scan->ds_cwd = ts->ts_path; scan->ds_cwdlen = strlen(scan->ds_cwd); scan->ds_ino = ts->ts_ino; ocfs2_free(&ts); } static void name_inode(struct dir_scan_context *scan, struct ocfs2_dir_entry *de) { struct dup_inode *di = dup_inode_lookup(scan->ds_dct, de->inode); if (!di || di->di_path) return; scan->ds_inodes_left--; di->di_path = de_to_path(scan, de); if (!di->di_path) pass1c_warn(OCFS2_ET_NO_MEMORY); } static int walk_iterate(struct ocfs2_dir_entry *de, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct dir_scan_context *scan = priv_data; /* Directories are checked when they're traversed */ if (de->file_type == OCFS2_FT_DIR) push_dir(scan, de); else name_inode(scan, de); return scan->ds_inodes_left ? 0 : OCFS2_DIRENT_ABORT; } static void walk_cwd(struct dir_scan_context *scan) { errcode_t ret; struct ocfs2_dir_entry de; memcpy(de.name, scan->ds_cwd, scan->ds_cwdlen); de.name_len = scan->ds_cwdlen; name_inode(scan, &de); ret = ocfs2_dir_iterate(scan->ds_ost->ost_fs, scan->ds_ino, OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL, walk_iterate, scan); if (ret) pass1c_warn(ret); } static void o2fsck_pass1c(o2fsck_state *ost, struct dup_context *dct) { struct dir_scan_context scan = { .ds_ost = ost, .ds_dct = dct, .ds_inodes_left = dct->dup_inode_count, }; whoami = "pass1c"; printf("Pass 1c: Determining the names of inodes owning " "multiply-claimed clusters\n"); INIT_LIST_HEAD(&scan.ds_paths); push_dir(&scan, &(struct ocfs2_dir_entry){ .name = "/", .name_len = 1, .file_type = OCFS2_FT_DIR, .inode = ost->ost_fs->fs_root_blkno, }); push_dir(&scan, &(struct ocfs2_dir_entry){ .name = "//", .name_len = 2, .file_type = OCFS2_FT_DIR, .inode = ost->ost_fs->fs_sysdir_blkno, }); while (scan.ds_inodes_left && !list_empty(&scan.ds_paths)) { set_next_cwd(&scan); walk_cwd(&scan); } } /* * Pass 1D */ static void print_inode_path(struct dup_inode *di) { if (di->di_path) fprintf(stdout, "%s\n", di->di_path); else fprintf(stdout, "<%"PRIu64">\n", di->di_ino); } /* * Walk the owning inodes of a dup_cluster, calling func(). func() may * return non-zero to abort the walk. */ static void for_each_owner(struct dup_context *dct, struct dup_cluster *dc, int (*func)(struct dup_cluster *dc, struct dup_inode *di, struct dup_cluster_owner *dco, void *priv_data), void *priv_data) { struct list_head *p, *next; struct dup_cluster_owner *dco; struct dup_inode *di; assert(!list_empty(&dc->dc_owners)); list_for_each_safe(p, next, &dc->dc_owners) { dco = list_entry(p, struct dup_cluster_owner, dco_list); di = dup_inode_lookup(dct, dco->dco_ino); assert(di); if (func(dc, di, dco, priv_data)) break; } } static int count_func(struct dup_cluster *dc, struct dup_inode *di, struct dup_cluster_owner *dco, void *priv_data) { uint64_t *count = priv_data; if (!(di->di_state & DUP_INODE_HANDLED)) (*count)++; return 0; } static int print_func(struct dup_cluster *dc, struct dup_inode *di, struct dup_cluster_owner *dco, void *priv_data) { printf(" "); print_inode_path(di); return 0; } /* * Check whether we can create refcount for the file. * So a file is valid only if: * 1. It isn't a system file. * 2. It has no refcount tree. * 3. It has the same tree as others. * Store refcount_loc if we find one. * * if there is other file that does't have the same tree, set refcount_loc * to UINT64_MAX and stop the search. */ static int find_refcount_func(struct dup_cluster *dc, struct dup_inode *di, struct dup_cluster_owner *dco, void *priv_data) { uint64_t *refcount_loc = priv_data; if (di->di_flags & OCFS2_SYSTEM_FL) { *refcount_loc = UINT64_MAX; return 1; } if (!di->di_refcount_loc) return 0; if (!*refcount_loc) { *refcount_loc = di->di_refcount_loc; return 0; } if (di->di_refcount_loc != *refcount_loc) { *refcount_loc = UINT64_MAX; return 1; } return 0; } /* Context for fix_dups_func() */ struct fix_dup_context { o2fsck_state *fd_ost; struct dup_context *fd_dct; errcode_t fd_err; }; static void print_chain_warning(void) { static int chain_warning = 0; if (chain_warning) return; printf("The filesystem is safe to read. You may wish to mount " "it read-only and copy data to a new filesystem.\n"); chain_warning = 1; } static errcode_t new_clone(ocfs2_filesys *fs, ocfs2_cached_inode *orig_ci, ocfs2_cached_inode **clone_ci) { errcode_t ret, ret2; uint64_t clone_blkno = 0; uint64_t bytes = orig_ci->ci_inode->i_size; uint32_t clusters = ocfs2_clusters_in_bytes(fs, bytes); ret = ocfs2_new_inode(fs, &clone_blkno, orig_ci->ci_inode->i_mode); if (ret) { com_err(whoami, ret, "while allocating a clone inode"); return ret; } /* * Let's get the clusters in the best way we can. We make sure * i_size is updated so that ocfs2_file_write() is happy. */ if (ocfs2_writes_unwritten_extents(OCFS2_RAW_SB(fs->fs_super)) && !(orig_ci->ci_inode->i_flags & OCFS2_SYSTEM_FL)) ret = ocfs2_allocate_unwritten_extents(fs, clone_blkno, 0, bytes); else { ret = ocfs2_extend_allocation(fs, clone_blkno, clusters); if (!ret) ret = ocfs2_extend_file(fs, clone_blkno, bytes); } if (ret) { com_err(whoami, ret, "while allocating data clusters for a clone inode"); goto out; } ret = ocfs2_read_cached_inode(fs, clone_blkno, clone_ci); if (ret) com_err(whoami, ret, "while reading temporary clone inode"); /* * It is so tempting to link the temporary clone inode into * the orphan directory here. But we can't, because later in * the clone process it will point to multiply-claimed clusters. * Orphan cleanup would free them, which is even worse than * leaving the temporary clone inode around. */ out: if (ret && clone_blkno) { ret2 = ocfs2_delete_inode(fs, clone_blkno); if (ret2) com_err(whoami, ret2, "while removing temporary clone inode"); } return ret; } static errcode_t copy_clone(ocfs2_filesys *fs, ocfs2_cached_inode *orig_ci, ocfs2_cached_inode *clone_ci) { char *buf; errcode_t ret; uint64_t offset = 0; uint64_t filesize = orig_ci->ci_inode->i_size; unsigned int iosize = 1024 * 1024; /* Let's read in 1MB hunks */ unsigned int got, wrote, write_len; ret = ocfs2_malloc_blocks(fs->fs_io, iosize / fs->fs_blocksize, &buf); if (ret) { com_err(whoami, ret, "while allocating clone buffer"); return ret; } while (offset < filesize) { ret = ocfs2_file_read(orig_ci, buf, iosize, offset, &got); if (ret) { com_err(whoami, ret, "while reading inode to clone"); break; } write_len = ocfs2_align_bytes_to_blocks(fs, got); ret = ocfs2_file_write(clone_ci, buf, write_len, offset, &wrote); if (ret) { com_err(whoami, ret, "while writing clone data"); break; } assert(got == wrote); offset += wrote; } ocfs2_free(&buf); return ret; } static errcode_t swap_clone(ocfs2_filesys *fs, ocfs2_cached_inode *orig_ci, ocfs2_cached_inode *clone_ci) { uint32_t clusters; errcode_t ret; struct ocfs2_extent_list *tmp_el = NULL; struct ocfs2_extent_list *orig_el = &orig_ci->ci_inode->id2.i_list; struct ocfs2_extent_list *clone_el = &clone_ci->ci_inode->id2.i_list; int el_size = offsetof(struct ocfs2_extent_list, l_recs) + sizeof(struct ocfs2_extent_rec) * orig_el->l_count; ret = ocfs2_malloc0(el_size, &tmp_el); if (ret) { com_err(whoami, ret, "while allocating temporary memory to swap a " "cloned inode"); goto out; } memcpy(tmp_el, orig_el, el_size); memcpy(orig_el, clone_el, el_size); memcpy(clone_el, tmp_el, el_size); /* * In new_clone, we allocate all the clusters disregard whether * there are holes. So here we need to update the i_clusters also. */ clusters = orig_ci->ci_inode->i_clusters; orig_ci->ci_inode->i_clusters = clone_ci->ci_inode->i_clusters; clone_ci->ci_inode->i_clusters = clusters; /* * We write the cloned inode with the original extent list first. * If we crash between writing the cloned inode and the original * one, the cloned inode will appear to share the same extents * as the original and the extents we just allocated to the clone * will look unused to a subsequent fsck run. They'll be reusable * for recovery. */ ret = ocfs2_write_cached_inode(fs, clone_ci); if (ret) { com_err(whoami, ret, "while writing out clone inode %"PRIu64, clone_ci->ci_blkno); goto out; } ret = ocfs2_write_cached_inode(fs, orig_ci); if (ret) com_err(whoami, ret, "while writing out inode %"PRIu64, orig_ci->ci_blkno); out: if (tmp_el) ocfs2_free(&tmp_el); return ret; } static int can_free(struct dup_context *dct, uint32_t cpos) { struct dup_cluster *dc; int unhandled = 0; dc = dup_cluster_lookup(dct, cpos); /* We don't call can_free unless it's in the dup bitmap */ assert(dc); /* * See how many inodes still point to it. It can't be zero, * because we're working on an inode that points to it RIGHT * NOW. */ for_each_owner(dct, dc, count_func, &unhandled); assert(unhandled > 0); if (unhandled > 1) return 0; return 1; } static errcode_t pass1d_free_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start, void *free_data) { errcode_t ret = 0; int was_set; struct fix_dup_context *fd = free_data; uint32_t p_cpos, p_start = ocfs2_blocks_to_clusters(fs, start); for (p_cpos = p_start; p_cpos < (p_start + len); p_cpos++) { verbosef("checking cpos %"PRIu32"\n", p_cpos); ret = ocfs2_bitmap_test(fd->fd_ost->ost_duplicate_clusters, p_cpos, &was_set); if (ret) { com_err(whoami, ret, "while testing cluster %"PRIu32" in " "the duplicate cluster map", p_cpos); break; } verbosef("cpos %"PRIu32" was_set == %d\n", p_cpos, was_set); if (was_set) { if (can_free(fd->fd_dct, p_cpos)) verbosef("Freeing multiply-claimed cluster " "%"PRIu32", as it is no longer used\n", p_cpos); else continue; } verbosef("Freeing cluster %"PRIu32"\n", p_cpos); ret = ocfs2_free_clusters(fd->fd_ost->ost_fs, 1, ocfs2_clusters_to_blocks(fs, p_cpos)); if (ret) { com_err(whoami, ret, "while freeing duplicate cluster " "%"PRIu32, p_cpos); break; } } return ret; } static int delete_one_inode(struct fix_dup_context *fd, uint64_t ino) { errcode_t ret; o2fsck_state *ost = fd->fd_ost; verbosef("Truncating inode %"PRIu64"\n", ino); ret = ocfs2_truncate_full(ost->ost_fs, ino, 0, pass1d_free_clusters, fd); if (ret) { com_err(whoami, ret, "while truncating inode %"PRIu64" to remove it", ino); goto out; } verbosef("Deleting inode %"PRIu64"\n", ino); ret = ocfs2_delete_inode(ost->ost_fs, ino); if (ret) com_err(whoami, ret, "while removing inode %"PRIu64, ino); else o2fsck_icount_set(ost->ost_icount_in_inodes, ino, 0); out: return ret ? 1 : 0; } static int clone_one_inode(struct fix_dup_context *fd, struct dup_inode *di) { errcode_t ret, tmpret; ocfs2_filesys *fs = fd->fd_ost->ost_fs; ocfs2_cached_inode *orig_ci = NULL, *clone_ci = NULL; ret = ocfs2_read_cached_inode(fs, di->di_ino, &orig_ci); if (ret) { com_err(whoami, ret, "while reading inode \"%s\" to clone it", di->di_path); goto out; } ret = new_clone(fs, orig_ci, &clone_ci); if (ret) goto out; verbosef("Copying inode \"%s\" to clone %"PRIu64"\n", di->di_path, clone_ci->ci_blkno); ret = copy_clone(fs, orig_ci, clone_ci); if (ret) goto out; ret = swap_clone(fs, orig_ci, clone_ci); out: if (orig_ci) ocfs2_free_cached_inode(fs, orig_ci); if (clone_ci) { tmpret = delete_one_inode(fd, clone_ci->ci_blkno); if (!ret) ret = tmpret; ocfs2_free_cached_inode(fs, clone_ci); } return ret ? 1 : 0; } static int fix_dups_func(struct dup_cluster *dc, struct dup_inode *di, struct dup_cluster_owner *dco, void *priv_data) { int ret = 0; struct fix_dup_context *fd = priv_data; if (di->di_flags & OCFS2_CHAIN_FL) { printf("Inode \"%s\" is a chain allocator and cannot " "be cloned or deleted.\n", di->di_path); print_chain_warning(); return 0; } if (di->di_flags & OCFS2_SYSTEM_FL) { if (prompt(fd->fd_ost, PY, PR_DUP_CLUSTERS_SYSFILE_CLONE, "Inode \"%s\" is a system file. It may be " "cloned but not deleted. Clone inode \"%s\" to " "break claims on clusters it shares with other " "inodes?", di->di_path, di->di_path)) { ret = clone_one_inode(fd, di); if (!ret) di->di_state |= DUP_INODE_CLONED; } } else { if (prompt(fd->fd_ost, PY, PR_DUP_CLUSTERS_CLONE, "Inode \"%s\" may be cloned or deleted to " "break the claim it has on its clusters. " "Clone inode \"%s\" to break claims on " "clusters it shares with other inodes?", di->di_path, di->di_path)) { ret = clone_one_inode(fd, di); if (!ret) di->di_state |= DUP_INODE_CLONED; } else if (prompt(fd->fd_ost, PN, PR_DUP_CLUSTERS_DELETE, "Delete inode \"%s\" to break claims on " "clusters it shares with other inodes?", di->di_path)) { ret = delete_one_inode(fd, di->di_ino); if (!ret) di->di_state |= DUP_INODE_REMOVED; } } return ret; } struct create_refcount { o2fsck_state *cr_ost; uint64_t cr_refcount_loc; errcode_t cr_err; }; static int create_refcount_func(struct dup_cluster *dc, struct dup_inode *di, struct dup_cluster_owner *dco, void *priv_data) { errcode_t ret; struct create_refcount *cr = priv_data; ocfs2_filesys *fs = cr->cr_ost->ost_fs; if (!di->di_refcount_loc) { ret = ocfs2_attach_refcount_tree(fs, di->di_ino, cr->cr_refcount_loc); if (ret) { com_err(whoami, ret, "while attaching file %"PRIu64" to" "refcount tree %"PRIu64, di->di_ino, cr->cr_refcount_loc); goto out; } di->di_refcount_loc = cr->cr_refcount_loc; } ret = ocfs2_change_refcount_flag(fs, di->di_ino, dco->dco_cpos, 1, dc->dc_cluster, OCFS2_EXT_REFCOUNTED, 0); if (ret) { com_err(whoami, ret, "while mark extent refcounted at %u in file %"PRIu64, dco->dco_cpos, di->di_ino); goto out; } ret = ocfs2_increase_refcount(fs, di->di_ino, dc->dc_cluster, 1); if (ret) com_err(whoami, ret, "while increasing refcount at %u for file %"PRIu64, dc->dc_cluster, di->di_ino); out: cr->cr_err = ret; return ret; } /* * Create refcount record for all the files sharing the same clusters. * Create a new refcount tree if all the files don't have it(refcount_loc = 0). * If a file don't have refcount tree, attach it to that tree. */ static errcode_t o2fsck_create_refcount(o2fsck_state *ost, struct dup_context *dct, struct dup_cluster *dc, uint64_t refcount_loc) { errcode_t ret = 0; struct create_refcount cr = { .cr_ost = ost, .cr_refcount_loc = refcount_loc, }; if (!refcount_loc) { ret = ocfs2_create_refcount_tree(ost->ost_fs, &refcount_loc); if (ret) { com_err(whoami, ret, "while allocating a new refcount block"); goto out; } cr.cr_refcount_loc = refcount_loc; } for_each_owner(dct, dc, create_refcount_func, &cr); ret = cr.cr_err; out: return ret; } static errcode_t o2fsck_pass1d(o2fsck_state *ost, struct dup_context *dct) { errcode_t ret = 0; struct dup_cluster *dc; struct rb_node *node = rb_first(&dct->dup_clusters); uint64_t dups, refcount_loc; struct fix_dup_context fd = { .fd_ost = ost, .fd_dct = dct, }; whoami = "pass1d"; printf("Pass 1d: Reconciling multiply-claimed clusters\n"); for (node = rb_first(&dct->dup_clusters); node; node = rb_next(node)) { dc = rb_entry(node, struct dup_cluster, dc_node); dups = 0; for_each_owner(dct, dc, count_func, &dups); if (dups < 2) continue; printf("Cluster %"PRIu32" is claimed by the following " "inodes:\n", dc->dc_cluster); for_each_owner(dct, dc, print_func, NULL); /* We try create refcount tree first. */ if (ocfs2_refcount_tree(OCFS2_RAW_SB(ost->ost_fs->fs_super))) { refcount_loc = 0; for_each_owner(dct, dc, find_refcount_func, &refcount_loc); if (refcount_loc != UINT64_MAX && prompt(ost, PY, PR_DUP_CLUSTERS_ADD_REFCOUNT, "Create refcount record for it?")) { ret = o2fsck_create_refcount(ost, dct, dc, refcount_loc); if (ret) break; continue; } } for_each_owner(dct, dc, fix_dups_func, &fd); if (fd.fd_err) { ret = fd.fd_err; break; } } return ret; } /* * Exported call */ errcode_t ocfs2_pass1_dups(o2fsck_state *ost) { errcode_t ret; struct dup_context dct = { .dup_clusters = RB_ROOT, .dup_inodes = RB_ROOT, }; ret = o2fsck_pass1b(ost, &dct); if (!ret) { o2fsck_pass1c(ost, &dct); ret = o2fsck_pass1d(ost, &dct); } o2fsck_empty_dup_context(&dct); return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass2.c0000644000176100017610000007260011500500544014112 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * Pass 2 iterates through the directory blocks that pass 1 found under * directory inodes. The basic dirent structures are made consistent * in each block. Directory entries much point to active inodes. "dot dot" * must be in the first blocks of the dir and nowhere else. Duplicate entries * are detected but little more. Slashes and nulls in names are replaced * with dots. The file type in the entry is synced with the type found in * the inode it points to. Throughout this invalid entries are cleared * by simply setting their inode field to 0 so that the fs will reuse them. * * Pass 2 builds up the parent dir linkage as it scans the directory entries * so that pass 3 can walk the directory trees to find disconnected inodes. */ #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/kernel-rbtree.h" #include "dirparents.h" #include "icount.h" #include "fsck.h" #include "pass2.h" #include "problem.h" #include "strings.h" #include "util.h" static const char *whoami = "pass2"; int o2fsck_test_inode_allocated(o2fsck_state *ost, uint64_t blkno) { errcode_t ret; int was_set; ret = ocfs2_test_inode_allocated(ost->ost_fs, blkno, &was_set); /* XXX this should stop fsck from marking the fs clean */ if (ret) { com_err(whoami, ret, "while testing if inode %"PRIu64" is " "allocated. Continuing as though it is.", blkno); was_set = 1; } return was_set; } struct dirblock_data { o2fsck_state *ost; ocfs2_filesys *fs; char *dirblock_buf; char *inoblock_buf; errcode_t ret; o2fsck_strings strings; uint64_t last_ino; struct rb_root re_idx_dirs; }; static int dirent_has_dots(struct ocfs2_dir_entry *dirent, int num_dots) { if (num_dots < 1 || num_dots > 2 || num_dots != dirent->name_len) return 0; if (num_dots == 2 && dirent->name[1] != '.') return 0; return dirent->name[0] == '.'; } static int expected_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, int offset) { int inline_off = offsetof(struct ocfs2_dinode, id2.i_data.id_data); if (dbe->e_blkcount == 0) { if (offset == 0 || (dbe->e_ino == dbe->e_blkno && offset == inline_off)) return 1; if (offset == OCFS2_DIR_REC_LEN(1) || (dbe->e_ino == dbe->e_blkno && offset == inline_off + OCFS2_DIR_REC_LEN(1))) return 2; } return 0; } static errcode_t fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_entry *dirent, int offset, int left, unsigned int *flags) { int expect_dots = expected_dots(ost, dbe, offset); int changed_len = 0; struct ocfs2_dir_entry *next; uint16_t new_len; errcode_t ret = 0; if (!expect_dots) { if (!dirent->inode || (!dirent_has_dots(dirent, 1) && !dirent_has_dots(dirent, 2))) goto out; if (prompt(ost, PY, PR_DIRENT_DOTTY_DUP, "Duplicate '%.*s' directory entry found, remove " "it?", dirent->name_len, dirent->name)) { dirent->inode = 0; *flags |= OCFS2_DIRENT_CHANGED; goto out; } } if (!dirent_has_dots(dirent, expect_dots) && prompt(ost, PY, PR_DIRENT_NOT_DOTTY, "The %s directory entry in directory inode " "%"PRIu64" is '%.*s' instead of '%.*s'. Clobber the " "current name with the expected dot name?", expect_dots == 1 ? "first" : "second", dbe->e_ino, dirent->name_len, dirent->name, expect_dots, "..")) { dirent->name_len = expect_dots; memset(dirent->name, '.', expect_dots); dirent->file_type = OCFS2_FT_DIR; changed_len = 1; *flags |= OCFS2_DIRENT_CHANGED; } /* we only record where .. points for now and that ends the * checks for .. */ if (expect_dots == 2) { o2fsck_dir_parent *dp; dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, dbe->e_ino); if (dp == NULL) { ret = OCFS2_ET_INTERNAL_FAILURE; com_err(whoami, ret, "no dir parents for '..' entry " "for inode %"PRIu64, dbe->e_ino); } else dp->dp_dot_dot = dirent->inode; goto out; } if ((dirent->inode != dbe->e_ino) && prompt(ost, PY, PR_DIRENT_DOT_INODE, "The '.' entry in directory inode %"PRIu64" " "points to inode %"PRIu64" instead of itself. Fix " "the '.' entry?", dbe->e_ino, (uint64_t)dirent->inode)) { dirent->inode = dbe->e_ino; *flags |= OCFS2_DIRENT_CHANGED; } /* * we might have slop at the end of this "." dirent. split * it into another seperate dirent if there is enough room and * we've just updated it's name_len or the user says we should. */ new_len = OCFS2_DIR_REC_LEN(dirent->name_len) - dirent->rec_len; if (new_len && (changed_len || prompt(ost, PY, PR_DIRENT_DOT_EXCESS, "The '.' entry in directory inode " "%"PRIu64" is too long. Try to create another " "directory entry from the excess?", dbe->e_ino))) { dirent->rec_len = OCFS2_DIR_REC_LEN(dirent->name_len); next = (struct ocfs2_dir_entry *)((char *)dirent + dirent->rec_len); next->inode = 0; next->name_len = 0; next->rec_len = OCFS2_DIR_REC_LEN(next->rec_len); *flags |= OCFS2_DIRENT_CHANGED; } out: return ret; } /* * The directory trailer has compatibility fields so it can be treated * as an empty (deleted) dirent. We need to make sure those are correct. */ static void fix_dir_trailer(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_block_trailer *trailer, unsigned int *flags) { if (trailer->db_compat_inode && prompt(ost, PY, PR_DIR_TRAILER_INODE, "Directory block trailer for logical block %"PRIu64" " "physcal block %"PRIu64" in directory inode %"PRIu64" " "has a non-zero inode number. Clear it?", dbe->e_blkcount, dbe->e_blkno, dbe->e_ino)) { trailer->db_compat_inode = 0; *flags |= OCFS2_DIRENT_CHANGED; } if (trailer->db_compat_name_len && prompt(ost, PY, PR_DIR_TRAILER_NAME_LEN, "Directory block trailer for logical block %"PRIu64" " "physcal block %"PRIu64" in directory inode %"PRIu64" " "has a non-zero name_len. Clear it?", dbe->e_blkcount, dbe->e_blkno, dbe->e_ino)) { trailer->db_compat_name_len = 0; *flags |= OCFS2_DIRENT_CHANGED; } if ((trailer->db_compat_rec_len != sizeof(struct ocfs2_dir_block_trailer)) && prompt(ost, PY, PR_DIR_TRAILER_REC_LEN, "Directory block trailer for logical block %"PRIu64" " "physcal block %"PRIu64" in directory inode %"PRIu64" " "has an invalid rec_len. Fix it?", dbe->e_blkcount, dbe->e_blkno, dbe->e_ino)) { trailer->db_compat_rec_len = sizeof(struct ocfs2_dir_block_trailer); *flags |= OCFS2_DIRENT_CHANGED; } if ((trailer->db_blkno != dbe->e_blkno) && prompt(ost, PY, PR_DIR_TRAILER_BLKNO, "Directory block trailer for logical block %"PRIu64" " "physcal block %"PRIu64" in directory inode %"PRIu64" " "has an invalid db_blkno of %"PRIu64". Fix it?", dbe->e_blkcount, dbe->e_blkno, dbe->e_ino, trailer->db_blkno)) { trailer->db_blkno = dbe->e_blkno; *flags |= OCFS2_DIRENT_CHANGED; } if ((trailer->db_parent_dinode != dbe->e_ino) && prompt(ost, PY, PR_DIR_TRAILER_PARENT_INODE, "Directory block trailer for logical block %"PRIu64" " "physcal block %"PRIu64" in directory inode %"PRIu64" " "claims it belongs to inoe %"PRIu64". Fix it?", dbe->e_blkcount, dbe->e_blkno, dbe->e_ino, trailer->db_parent_dinode)) { trailer->db_parent_dinode = dbe->e_ino; *flags |= OCFS2_DIRENT_CHANGED; } } static int dirent_leaves_partial(struct ocfs2_dir_entry *dirent, int left) { left -= dirent->rec_len; return (left > 0 && left < OCFS2_DIR_MEMBER_LEN); } /* * The caller has found that either of rec_len or name_len are garbage. The * caller trusts us to fix them up in place and will be checking them again * before proceeding. We have to update the lengths to make forward progress. * 'left' is the number of bytes from the start of this dirent struct that * remain in the block. * * We're called for invalid dirents, and having a dirent * that leaves a partial dirent at the end of the block is considered invalid, * and we pad out partials at the end of this call so we can't be called here * with left < OCFS2_DIR_MEMBER_LEN. * * we're pretty limited in the repairs we can make: * * - We can't just set name_len if rec_len looks valid, we might guess * name_len wrong and create a bogus file name. * - we can't just set rec_len based on name_len. rec_len could have * included an arbitrary part of the name from a previously freed dirent. */ static void fix_dirent_lengths(struct ocfs2_dir_entry *dirent, int left, struct ocfs2_dir_entry *prev, unsigned int *flags) { /* * as described above we can't reconstruct either value if it is * complete nonsense. We can only proceed if we can work off of * one that is kind of valid looking. * name_len could well be 0 from the dirent being cleared. */ if (dirent->rec_len < OCFS2_DIR_MEMBER_LEN || (dirent->rec_len > left || dirent->name_len > left)) goto wipe; /* if we see a dirent with no file name then we remove it by * shifting the remaining dirents forward */ if ((dirent->rec_len == OCFS2_DIR_MEMBER_LEN)) { char *cp = (char *)dirent; left -= dirent->rec_len; memmove(cp, cp + dirent->rec_len, left); memset(cp + left, 0, dirent->rec_len); goto out; } /* if rec_len just appears to be mis-rounded in a way that doesn't * affect following dirents then we can probably save this dirent */ if (OCFS2_DIR_REC_LEN(dirent->name_len) != dirent->rec_len && OCFS2_DIR_REC_LEN(dirent->name_len) == OCFS2_DIR_REC_LEN(dirent->rec_len)) { dirent->rec_len = OCFS2_DIR_REC_LEN(dirent->name_len); left -= dirent->rec_len; goto out; } /* if name_len is too far off, however, we're going to lose this * dirent.. we might be able to just lose this one dirent if rec_len * appears to be intact. */ if ((dirent->rec_len & OCFS2_DIR_ROUND) == 0 && !dirent_leaves_partial(dirent, left)) { left -= dirent->rec_len; dirent->name_len = 0; dirent->inode = 0; dirent->file_type = OCFS2_FT_UNKNOWN; goto out; } /* * if we can't trust rec_len, however, then we don't know where the * next dirent might begin. We've lost the trail of dirents created by * the file system and run the risk of parsing file names as dirents. * So we're forced to wipe the block and leave the rest to lost+found. */ wipe: dirent->rec_len = left; dirent->name_len = 0; dirent->inode = 0; dirent->file_type = OCFS2_FT_UNKNOWN; left = 0; out: /* * rec_len must be valid and left must reflect the space *after* the * current dirent by this point. if there isn't enough room for * another dirent after the one we've just repaired then we tack the * remaining space onto the current dirent. */ if (dirent_leaves_partial(dirent, left)) dirent->rec_len += left; *flags |= OCFS2_DIRENT_CHANGED; } static void fix_dirent_name(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_entry *dirent, int offset, unsigned int *flags) { char *chr = dirent->name; int len = dirent->name_len, fix = 0; if (len == 0) { if (prompt(ost, PY, PR_DIRENT_ZERO, "Directory entry has a zero-length name, " "clear it?")) { dirent->inode = 0; *flags |= OCFS2_DIRENT_CHANGED; } } for(; len-- > 0 && (*chr == '/' || *chr == '\0'); chr++) { /* XXX in %s parent name */ if (!fix) { fix = prompt(ost, PY, PR_DIRENT_NAME_CHARS, "Directory entry '%.*s' " "contains invalid characters, replace " "them with dots?", dirent->name_len, dirent->name); if (!fix) break; } *chr = '.'; *flags |= OCFS2_DIRENT_CHANGED; } } static void fix_dirent_inode(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_entry *dirent, int offset, unsigned int *flags) { if (ocfs2_block_out_of_range(ost->ost_fs, dirent->inode) && prompt(ost, PY, PR_DIRENT_INODE_RANGE, "Directory entry '%.*s' refers to inode " "number %"PRIu64" which is out of range, clear the entry?", dirent->name_len, dirent->name, (uint64_t)dirent->inode)) { dirent->inode = 0; *flags |= OCFS2_DIRENT_CHANGED; goto out; } if (!o2fsck_test_inode_allocated(ost, dirent->inode) && prompt(ost, PY, PR_DIRENT_INODE_FREE, "Directory entry '%.*s' refers to inode number " "%"PRIu64" which isn't allocated, clear the entry?", dirent->name_len, dirent->name, (uint64_t)dirent->inode)) { dirent->inode = 0; *flags |= OCFS2_DIRENT_CHANGED; } out: return; } #define type_entry(type) [type] = #type static char *file_types[] = { type_entry(OCFS2_FT_UNKNOWN), type_entry(OCFS2_FT_REG_FILE), type_entry(OCFS2_FT_DIR), type_entry(OCFS2_FT_CHRDEV), type_entry(OCFS2_FT_BLKDEV), type_entry(OCFS2_FT_FIFO), type_entry(OCFS2_FT_SOCK), type_entry(OCFS2_FT_SYMLINK), }; #undef type_entry static char *file_type_string(uint8_t type) { if (type >= OCFS2_FT_MAX) return "(unknown)"; return file_types[type]; } static errcode_t fix_dirent_filetype(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_entry *dirent, int offset, unsigned int *flags) { uint8_t expected_type; errcode_t ret; int was_set; ret = ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &was_set); if (ret) goto out; if (was_set) { expected_type = OCFS2_FT_DIR; goto check; } ret = ocfs2_bitmap_test(ost->ost_reg_inodes, dirent->inode, &was_set); if (ret) goto out; if (was_set) { expected_type = OCFS2_FT_REG_FILE; goto check; } ret = o2fsck_type_from_dinode(ost, dirent->inode, &expected_type); if (ret) goto out; check: if ((dirent->file_type != expected_type) && prompt(ost, PY, PR_DIRENT_TYPE, "Directory entry %.*s contains file type %s (%u) " "but its inode %"PRIu64" leads to type %s (%u). Reset the " "entry's type to match the inode's?", dirent->name_len, dirent->name, file_type_string(dirent->file_type), dirent->file_type, (uint64_t)dirent->inode, file_type_string(expected_type), expected_type)) { dirent->file_type = expected_type; *flags |= OCFS2_DIRENT_CHANGED; } out: if (ret) com_err(whoami, ret, "while trying to verify the file type " "of directory entry %.*s", dirent->name_len, dirent->name); return ret; } static errcode_t fix_dirent_linkage(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_entry *dirent, int offset, unsigned int *flags) { int expect_dots = expected_dots(ost, dbe, offset); o2fsck_dir_parent *dp; errcode_t ret = 0; int is_dir; /* we already took care of special-casing the dots */ if (expect_dots) goto out; /* we're only checking the linkage if we already found the dir * this inode claims to be pointing to */ ret = ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &is_dir); if (ret) com_err(whoami, ret, "while checking for inode %"PRIu64" in " "the dir bitmap", (uint64_t)dirent->inode); if (!is_dir) goto out; dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, dirent->inode); if (dp == NULL) { ret = OCFS2_ET_INTERNAL_FAILURE; com_err(whoami, ret, "no dir parents recorded for inode " "%"PRIu64, (uint64_t)dirent->inode); goto out; } /* if no dirents have pointed to this inode yet we record ours * as the first and move on */ if (dp->dp_dirent == 0) { dp->dp_dirent = dbe->e_ino; goto out; } if (prompt(ost, 0, PR_DIR_PARENT_DUP, "Directory inode %"PRIu64" is not the first to " "claim to be the parent of subdir '%.*s' (inode %"PRIu64"). " "Clear this directory entry and leave the previous parent of " "the subdir's inode intact?", dbe->e_ino, dirent->name_len, dirent->name, (uint64_t)dirent->inode)) { dirent->inode = 0; *flags |= OCFS2_DIRENT_CHANGED; } out: return ret; } /* detecting dups is irritating because of the storage requirements of * detecting duplicates. e2fsck avoids the storage burden for a regular fsck * pass by only detecting duplicate entries that occur in the same directory * block. its repair pass then suffers under enormous directories because it * reads the whole thing into memory to detect duplicates. * * we'll take a compromise which expands the reach of a regular fsck pass by * using a slightly larger block size but which repairs in place rather than * reading the dir into memory. * * if we ever truly care to invest in duplicate detection and repair we could * either explicitly use some external sort and merge algo or perhaps just * combine mmap and some internal sort that has strong enough locality of * reference to work well with the vm. */ static errcode_t fix_dirent_dups(o2fsck_state *ost, o2fsck_dirblock_entry *dbe, struct ocfs2_dir_entry *dirent, o2fsck_strings *strings, unsigned int *flags) { errcode_t ret = 0; char *new_name = NULL; int was_set, i; /* start over every N bytes of dirent */ if (o2fsck_strings_bytes_allocated(strings) > (4 * 1024 * 1024)) o2fsck_strings_free(strings); ret = o2fsck_strings_insert(strings, dirent->name, dirent->name_len, &was_set); if (ret) { com_err(whoami, ret, "while allocating space to find " "duplicate directory entries"); goto out; } if (!was_set) goto out; new_name = calloc(1, dirent->rec_len + 1); if (new_name == NULL) { ret = OCFS2_ET_NO_MEMORY; com_err(whoami, ret, "while trying to generate a new name " "for duplicate file name '%.*s' in dir inode " "%"PRIu64, dirent->name_len, dirent->name, dbe->e_ino); goto out; } /* just simple mangling for now */ memcpy(new_name, dirent->name, dirent->name_len); was_set = 1; /* append '_' to free space in the dirent until its unique */ for (i = dirent->name_len ; was_set && i < dirent->rec_len; i++){ new_name[i] = '_'; if (!o2fsck_strings_exists(strings, new_name, strlen(new_name))) was_set = 0; } /* rename characters at the end to '_' until its unique */ for (i = dirent->name_len - 1 ; was_set && i >= 0; i--) { new_name[i] = '_'; if (!o2fsck_strings_exists(strings, new_name, strlen(new_name))) was_set = 0; } if (was_set) { printf("Directory inode %"PRIu64" contains a duplicate " "occurance " "of the file name '%.*s' but fsck was " "unable to come up with a unique name so this duplicate " "name will not be dealt with.\n.", dbe->e_ino, dirent->name_len, dirent->name); goto out; } if (!prompt(ost, PY, PR_DIRENT_DUPLICATE, "Directory inode %"PRIu64" contains a duplicate occurance " "of the file name '%.*s'. Replace this duplicate name " "with '%s'?", dbe->e_ino, dirent->name_len, dirent->name, new_name)) { /* we don't really care that we leak new_name's recording * in strings, it'll be freed later */ goto out; } ret = o2fsck_strings_insert(strings, new_name, strlen(new_name), NULL); if (ret) { com_err(whoami, ret, "while allocating space to track " "duplicates of a newly renamed dirent"); goto out; } dirent->name_len = strlen(new_name); memcpy(dirent->name, new_name, dirent->name_len); *flags |= OCFS2_DIRENT_CHANGED; out: if (new_name != NULL) free(new_name); return ret; } static errcode_t fix_dirent_index(o2fsck_dirblock_entry *dbe, struct dirblock_data *dd, struct ocfs2_dir_entry *dirent, unsigned int *flags) { errcode_t ret = 0; struct ocfs2_dinode *di = (struct ocfs2_dinode *)dd->inoblock_buf; uint64_t ino; if (!ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(dd->fs->fs_super))) goto out; if (di->i_dyn_features & OCFS2_INDEXED_DIR_FL) { ret = ocfs2_lookup(dd->fs, dbe->e_ino, dirent->name, dirent->name_len, NULL, &ino); if (ret) { if (ret != OCFS2_ET_FILE_NOT_FOUND) goto out; ret = 0; if (prompt(dd->ost, PY, PR_DX_LOOKUP_FAILED, "Directory inode %"PRIu64" is missing " "an index entry for the file \"%.*s\"" " (inode # %"PRIu64")\n. Repair this by " "rebuilding the directory index?", dbe->e_ino, dirent->name_len, dirent->name, ino)) *flags |= OCFS2_DIRENT_CHANGED; goto out; } } out: return ret; } static int corrupt_dirent_lengths(struct ocfs2_dir_entry *dirent, int left) { if ((dirent->rec_len >= OCFS2_DIR_REC_LEN(1)) && ((dirent->rec_len & OCFS2_DIR_ROUND) == 0) && (dirent->rec_len <= left) && (OCFS2_DIR_REC_LEN(dirent->name_len) <= dirent->rec_len) && !dirent_leaves_partial(dirent, left)) return 0; verbosef("corrupt dirent: %"PRIu64" rec_len %u name_len %u\n", (uint64_t)dirent->inode, dirent->rec_len, dirent->name_len); return 1; } /* this could certainly be more clever to issue reads in groups */ static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe, void *priv_data) { struct dirblock_data *dd = priv_data; struct ocfs2_dir_entry *dirent, *prev = NULL; unsigned int offset = 0, ret_flags = 0, end = dd->fs->fs_blocksize; unsigned int write_off, saved_reclen; struct ocfs2_dinode *di = (struct ocfs2_dinode *)dd->inoblock_buf; errcode_t ret = 0; if (!o2fsck_test_inode_allocated(dd->ost, dbe->e_ino)) { printf("Directory block %"PRIu64" belongs to directory inode " "%"PRIu64" which isn't allocated. Ignoring this " "block.", dbe->e_blkno, dbe->e_ino); goto out; } if (dbe->e_ino != dd->last_ino) { o2fsck_strings_free(&dd->strings); dd->last_ino = dbe->e_ino; ret = ocfs2_read_inode(dd->ost->ost_fs, dbe->e_ino, dd->inoblock_buf); if (ret) { com_err(whoami, ret, "while reading dir inode %"PRIu64, dbe->e_ino); ret_flags |= OCFS2_DIRENT_ABORT; goto out; } verbosef("dir inode %"PRIu64" i_size %"PRIu64"\n", dbe->e_ino, (uint64_t)di->i_size); } verbosef("dir block %"PRIu64" block offs %"PRIu64" in ino\n", dbe->e_blkno, dbe->e_blkcount); if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { if (dbe->e_ino != dbe->e_blkno) goto out; memcpy(dd->dirblock_buf, dd->inoblock_buf, dd->fs->fs_blocksize); offset = offsetof(struct ocfs2_dinode, id2.i_data.id_data); } else { if (dbe->e_blkcount >= ocfs2_blocks_in_bytes(dd->fs, di->i_size)) goto out; ret = ocfs2_read_dir_block(dd->fs, di, dbe->e_blkno, dd->dirblock_buf); if (ret && ret != OCFS2_ET_DIR_CORRUPTED) { com_err(whoami, ret, "while reading dir block %"PRIu64, dbe->e_blkno); goto out; } if (ocfs2_dir_has_trailer(dd->fs, di)) end = ocfs2_dir_trailer_blk_off(dd->fs); } write_off = offset; while (offset < end) { dirent = (struct ocfs2_dir_entry *)(dd->dirblock_buf + offset); verbosef("checking dirent offset %d, rec_len %"PRIu16" " "name_len %"PRIu8" file_type %"PRIu8"\n", offset, dirent->rec_len, dirent->name_len, dirent->file_type); /* XXX I wonder if we should be checking that the padding * is 0 */ /* if we can't trust this dirent then fix it up or skip * the whole block */ if (corrupt_dirent_lengths(dirent, end - offset)) { if (!prompt(dd->ost, PY, PR_DIRENT_LENGTH, "Directory inode %"PRIu64" " "corrupted in logical block %"PRIu64" " "physical block %"PRIu64" offset %d. " "Attempt to repair this block's directory " "entries?", dbe->e_ino, dbe->e_blkcount, dbe->e_blkno, offset)) break; /* we edit the dirent in place so we try to parse * it again after fixing it */ fix_dirent_lengths(dirent, end - offset, prev, &ret_flags); continue; } /* * In general, these calls mark ->inode as 0 when they want it * to be seen as deleted; ignored by fsck and reclaimed by the * kernel. The dots are a special case, of course. This * pass makes sure that they are the first two entries in * the directory and pass3 fixes ".."'s ->inode. * * XXX should verify that ocfs2 reclaims entries like that. */ ret = fix_dirent_dots(dd->ost, dbe, dirent, offset, end - offset, &ret_flags); if (ret) goto out; if (dirent->inode == 0) goto next; fix_dirent_name(dd->ost, dbe, dirent, offset, &ret_flags); if (dirent->inode == 0) goto next; fix_dirent_inode(dd->ost, dbe, dirent, offset, &ret_flags); if (dirent->inode == 0) goto next; ret = fix_dirent_filetype(dd->ost, dbe, dirent, offset, &ret_flags); if (ret) goto out; if (dirent->inode == 0) goto next; ret = fix_dirent_linkage(dd->ost, dbe, dirent, offset, &ret_flags); if (ret) goto out; if (dirent->inode == 0) goto next; ret = fix_dirent_dups(dd->ost, dbe, dirent, &dd->strings, &ret_flags); if (ret) goto out; if (dirent->inode == 0) goto next; ret = fix_dirent_index(dbe, dd, dirent, &ret_flags); if (ret) goto out; verbosef("dirent %.*s refs ino %"PRIu64"\n", dirent->name_len, dirent->name, (uint64_t)dirent->inode); o2fsck_icount_delta(dd->ost->ost_icount_refs, dirent->inode, 1); next: saved_reclen = dirent->rec_len; if (dd->ost->ost_compress_dirs) { if (prev && prev->inode) { /*Bring previous rec_len to required space */ prev->rec_len = OCFS2_DIR_REC_LEN(prev->name_len); write_off += prev->rec_len; } if (write_off < offset) { verbosef("ino: %llu woff: %u off: %u\n", dirent->inode, write_off, offset); memmove(dd->dirblock_buf + write_off, dd->dirblock_buf + offset, OCFS2_DIR_REC_LEN(dirent->name_len)); dirent = (struct ocfs2_dir_entry *)(dd->dirblock_buf + write_off); /* Cover space from our new location to * the next dirent */ dirent->rec_len = saved_reclen + offset - write_off; ret_flags |= OCFS2_DIRENT_CHANGED; } } prev = dirent; offset += saved_reclen; } if (ocfs2_dir_has_trailer(dd->fs, di)) fix_dir_trailer(dd->ost, dbe, ocfs2_dir_trailer_from_block(dd->fs, dd->dirblock_buf), &ret_flags); if (ret_flags & OCFS2_DIRENT_CHANGED) { if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) { memcpy(dd->inoblock_buf, dd->dirblock_buf, dd->fs->fs_blocksize); ret = ocfs2_write_inode(dd->fs, dbe->e_ino, dd->dirblock_buf); } else ret = ocfs2_write_dir_block(dd->fs, di, dbe->e_blkno, dd->dirblock_buf); if (ret) { com_err(whoami, ret, "while writing dir block %"PRIu64, dbe->e_blkno); dd->ost->ost_write_error = 1; goto out; } if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(dd->fs->fs_super)) && !(di->i_dyn_features & OCFS2_INLINE_DATA_FL) && (di->i_dyn_features & OCFS2_INDEXED_DIR_FL)) { ret = o2fsck_try_add_reidx_dir(&dd->re_idx_dirs, dbe->e_ino); if (ret) { com_err(whoami, ret, "while adding block for " "directory inode %"PRIu64" to rebuild " "dir index", dbe->e_ino); goto out; } } } /* truncate invalid indexed tree */ if ((!ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(dd->fs->fs_super)))&& di->i_dyn_features & OCFS2_INDEXED_DIR_FL ) { /* ignore the return value */ if (prompt(dd->ost, PY, PR_IV_DX_TREE, "A directory index was " "found on inode %"PRIu64" but this filesystem does" "not support directory indexes. Truncate the invalid index?", dbe->e_ino)) ocfs2_dx_dir_truncate(dd->fs, dbe->e_ino); } out: if (ret) dd->ret = ret; return ret_flags; } static void release_re_idx_dirs_rbtree(struct rb_root * root) { struct rb_node *node; o2fsck_dirblock_entry *dp; while ((node = rb_first(root)) != NULL) { dp = rb_entry(node, o2fsck_dirblock_entry, e_node); rb_erase(&dp->e_node, root); ocfs2_free(&dp); } } errcode_t o2fsck_pass2(o2fsck_state *ost) { o2fsck_dir_parent *dp; errcode_t ret; struct dirblock_data dd = { .ost = ost, .fs = ost->ost_fs, .last_ino = 0, .re_idx_dirs = RB_ROOT, }; printf("Pass 2: Checking directory entries.\n"); o2fsck_strings_init(&dd.strings); ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &dd.dirblock_buf); if (ret) { com_err(whoami, ret, "while allocating a block buffer to " "store directory blocks."); goto out; } ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &dd.inoblock_buf); if (ret) { com_err(whoami, ret, "while allocating a block buffer to " "store a directory inode."); goto out; } /* * Mark the root directory's dirent parent as itself if we found the * inode during inode scanning. The dir will be created in pass3 * if it didn't exist already. XXX we should do this for all our other * magical directories. */ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, ost->ost_fs->fs_root_blkno); if (dp) dp->dp_dirent = ost->ost_fs->fs_root_blkno; dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, ost->ost_fs->fs_sysdir_blkno); if (dp) dp->dp_dirent = ost->ost_fs->fs_sysdir_blkno; o2fsck_dir_block_iterate(ost, pass2_dir_block_iterate, &dd); if (dd.re_idx_dirs.rb_node) { ret = o2fsck_rebuild_indexed_dirs(ost->ost_fs, &dd.re_idx_dirs); if (ret) com_err(whoami, ret, "while rebuild indexed dirs."); } release_re_idx_dirs_rbtree(&dd.re_idx_dirs); o2fsck_strings_free(&dd.strings); out: if (dd.dirblock_buf) ocfs2_free(&dd.dirblock_buf); if (dd.inoblock_buf) ocfs2_free(&dd.inoblock_buf); return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass3.c0000644000176100017610000003014111500500544014105 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * Pass 3 makes sure that all directories are connected to the file system * tree and that their are no cycles in the tree. It starts by marking * the root and system directories in the filesystem as connected. It then * iterates through the directories found in pass 1. For each directory * it ascends to the root of the file system via the chain of parent dir * entries as built up by pass 2. If a directory is found which doesn't have * a parent it is connected to lost+found. connect_directory() is careful * to stop before following a parent that it has already seen. This lets it * connect to lost+found instead and break cycles. */ #include #include #include #include "ocfs2/ocfs2.h" #include "dirparents.h" #include "fsck.h" #include "pass2.h" #include "pass3.h" #include "problem.h" #include "util.h" static const char *whoami = "pass3"; static void check_root(o2fsck_state *ost) { struct ocfs2_super_block *sb = OCFS2_RAW_SB(ost->ost_fs->fs_super); errcode_t ret; uint64_t blkno, old_root; int was_set; if (o2fsck_test_inode_allocated(ost, ost->ost_fs->fs_root_blkno)) { ocfs2_bitmap_test(ost->ost_dir_inodes, ost->ost_fs->fs_root_blkno, &was_set); if (!was_set) printf("The root inode exists but isn't a " "directory.\n"); return; } if (!prompt(ost, PY, PR_ROOT_DIR_MISSING, "The super block claims that inode %"PRIu64" is the root " "directory but it isn't allocated. Create a new root " "directory and update the super block?", ost->ost_fs->fs_root_blkno)) return; ret = ocfs2_new_inode(ost->ost_fs, &blkno, 0755 | S_IFDIR); if (ret) { com_err(whoami, ret, "while trying to allocate a new inode " "for the root directory\n"); return; } ret = ocfs2_init_dir(ost->ost_fs, blkno, blkno); if (ret) { com_err(whoami, ret, "while trying to expand a new root " "directory"); goto out; } o2fsck_icount_set(ost->ost_icount_in_inodes, blkno, 1); o2fsck_icount_set(ost->ost_icount_refs, blkno, 1); ret = o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, ost->ost_fs->fs_root_blkno, ost->ost_fs->fs_root_blkno, 0); if (ret) { com_err(whoami, ret, "while recording a new root directory"); goto out; } old_root = sb->s_root_blkno; ost->ost_fs->fs_root_blkno = blkno; sb->s_root_blkno = blkno; ret = ocfs2_write_primary_super(ost->ost_fs); if (ret) { com_err(whoami, ret, "while writing the super block with a " "new root directory inode"); ost->ost_fs->fs_root_blkno = old_root; sb->s_root_blkno = old_root; goto out; } blkno = 0; out: if (blkno) { ret = ocfs2_delete_inode(ost->ost_fs, blkno); if (ret) { com_err(whoami, ret, "while trying to clean up an " "an allocated inode after linking /lost+found " "failed"); } } } static void check_lostfound(o2fsck_state *ost) { char name[] = "lost+found"; int namelen = sizeof(name) - 1; uint64_t blkno; errcode_t ret; ret = ocfs2_lookup(ost->ost_fs, ost->ost_fs->fs_root_blkno, name, namelen, NULL, &ost->ost_lostfound_ino); if (ret == 0) return; if (!prompt(ost, PY, PR_LOSTFOUND_MISSING, "/lost+found does not exist. Create it so " "that we can possibly fill it with orphaned inodes?")) return; ret = ocfs2_new_inode(ost->ost_fs, &blkno, 0755 | S_IFDIR); if (ret) { com_err(whoami, ret, "while trying to allocate a new inode " "for /lost+found"); return; } ret = ocfs2_init_dir(ost->ost_fs, blkno, ost->ost_fs->fs_root_blkno); if (ret) { com_err(whoami, ret, "while trying to expand a new " "/lost+found directory"); goto out; } ret = ocfs2_link(ost->ost_fs, ost->ost_fs->fs_root_blkno, name, blkno, OCFS2_FT_DIR); if (ret) { com_err(whoami, ret, "while linking inode %"PRIu64" as " "/lost+found", blkno); goto out; } /* XXX maybe this should be a helper to clean up the dir tracking * for any new dir. "2" for both the l+f dirent pointing to the * inode and the "." dirent in its dirblock */ o2fsck_icount_set(ost->ost_icount_in_inodes, blkno, 2); o2fsck_icount_set(ost->ost_icount_refs, blkno, 2); ret = o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, ost->ost_fs->fs_root_blkno, ost->ost_fs->fs_root_blkno, 0); if (ret) { com_err(whoami, ret, "while recording a new /lost+found " "directory"); goto out; } /* we've already iterated through the dirblocks in pass2 so there * is no need to register l+f's new dir block */ ost->ost_lostfound_ino = blkno; blkno = 0; out: if (blkno) { ret = ocfs2_delete_inode(ost->ost_fs, blkno); if (ret) { com_err(whoami, ret, "while trying to clean up an " "an allocated inode after linking /lost+found " "failed"); } } } struct fix_dot_dot_args { o2fsck_state *ost; uint64_t parent; int fixed; }; static int fix_dot_dot_dirent(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct fix_dot_dot_args *args = priv_data; if (dirent->name_len != 2 || strncmp(dirent->name, "..", 2)) return 0; verbosef("fixing '..' entry to point to %"PRIu64"\n", args->parent); if (dirent->inode != 0) o2fsck_icount_delta(args->ost->ost_icount_refs, dirent->inode, -1); o2fsck_icount_delta(args->ost->ost_icount_refs, args->parent, 1); dirent->inode = args->parent; args->fixed = 1; return OCFS2_DIRENT_ABORT | OCFS2_DIRENT_CHANGED; } static void fix_dot_dot(o2fsck_state *ost, o2fsck_dir_parent *dir) { errcode_t ret; struct fix_dot_dot_args args = { .ost = ost, .parent = dir->dp_dirent, .fixed = 0, }; ret = ocfs2_dir_iterate(ost->ost_fs, dir->dp_ino, OCFS2_DIRENT_FLAG_INCLUDE_EMPTY, NULL, fix_dot_dot_dirent, &args); if (ret) { com_err("fix_dot_dot", ret, "while iterating through dir " "inode %"PRIu64"'s directory entries.", dir->dp_dirent); /* XXX mark fs invalid */ return; } if (!args.fixed) { fprintf(stderr, "Didn't find a '..' entry to fix.\n"); /* XXX mark fs invalid */ return; } dir->dp_dot_dot = dir->dp_dirent; } /* add a directory entry that points to a given inode in lost+found. */ void o2fsck_reconnect_file(o2fsck_state *ost, uint64_t inode) { static char iname[NAME_MAX + 1]; char name[] = "lost+found"; int namelen = sizeof(name) - 1; o2fsck_dir_parent *dp; errcode_t ret; uint8_t type; int len; if (ost->ost_lostfound_ino == 0) { ret = ocfs2_lookup(ost->ost_fs, ost->ost_fs->fs_root_blkno, name, namelen, NULL, &ost->ost_lostfound_ino); if (ret) { com_err(whoami, ret, "while trying to find the " "/lost+found directory so that inode " "%"PRIu64" could be moved there.", inode); goto out; } } len = snprintf(iname, sizeof(iname), "#%"PRIu64, inode); if (len <= 0) { ret = OCFS2_ET_NO_MEMORY; com_err(whoami, ret, "while trying to build a new file name " "for inode %"PRIu64" to use in /lost+found", inode); goto out; } ret = o2fsck_type_from_dinode(ost, inode, &type); if (ret) goto out; ret = ocfs2_link(ost->ost_fs, ost->ost_lostfound_ino, iname, inode, type); if (ret) { com_err(whoami, ret, "while trying to link inode %"PRIu64" " "into /lost+found", inode); goto out; } /* add another ref to account for this new dirent */ o2fsck_icount_delta(ost->ost_icount_refs, inode, 1); /* if we just added a directory to l+f we need to track that * the new dirent points to the dir. we leave the dot_dot tracking * intact because we didn't change that in the dirblock.. */ if (type == OCFS2_FT_DIR) { dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, inode); if (dp == NULL) { ret = OCFS2_ET_INTERNAL_FAILURE; com_err(whoami, ret, "while looking up the directory " "parent structure for inode %"PRIu64, inode); goto out; } dp->dp_dirent = ost->ost_lostfound_ino; } out: return; } static uint64_t loop_no = 0; static errcode_t connect_directory(o2fsck_state *ost, o2fsck_dir_parent *dir) { o2fsck_dir_parent *dp = dir, *par; errcode_t ret = 0; int fix; verbosef("checking dir inode %"PRIu64" parent %"PRIu64" dot_dot " "%"PRIu64"\n", dir->dp_ino, dp->dp_dirent, dp->dp_dot_dot); loop_no++; while(!dp->dp_connected) { /* we either will ascend to a parent that is connected or * we'll graft the subtree with this directory on to lost * and found. */ dp->dp_connected = 1; /* move on to the parent dir only if it exists and we haven't * already traversed it in this instance of parent walking */ if (dp->dp_dirent) { par = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, dp->dp_dirent); if (par == NULL) { ret = OCFS2_ET_INTERNAL_FAILURE; com_err(whoami, ret, "no dir info for parent " "%"PRIu64, dp->dp_dirent); goto out; } if (par->dp_loop_no != loop_no) { par->dp_loop_no = loop_no; dp = par; continue; } } /* ok, we hit an orphan subtree with no parent or are at * the dir in a subtree that is the first to try to reference * a dir in its children */ fix = prompt(ost, PY, PR_DIR_NOT_CONNECTED, "Directory inode %"PRIu64" isn't " "connected to the filesystem. Move it to " "lost+found?", dp->dp_ino); if (fix) o2fsck_reconnect_file(ost, dp->dp_ino); break; } /* * orphan dirs are a magically awesome special case. they have * their i_link_count increased when subdirs are added but * the subdirs '..' entry isn't updated to point to the orphan * dir. we alter our book-keeping to it look like the '..' * was reasonable on disk. */ if (dir->dp_in_orphan_dir) { /* previous '..' entry is garbage */ if (dir->dp_dot_dot) o2fsck_icount_delta(ost->ost_icount_refs, dir->dp_dot_dot, -1); /* pretend '..' pointed to the orphan dir */ dir->dp_dot_dot = dir->dp_dirent; o2fsck_icount_delta(ost->ost_icount_refs, dir->dp_dot_dot, 1); } if (dir->dp_dirent != dir->dp_dot_dot) { fix = prompt(ost, PY, PR_DIR_DOTDOT, "Directory inode %"PRIu64" is " "referenced by a dirent in directory %"PRIu64" " "but its '..' entry points to inode %"PRIu64". " "Fix the '..' entry to reference %"PRIu64"?", dir->dp_ino, dir->dp_dirent, dir->dp_dot_dot, dir->dp_dirent); if (fix) fix_dot_dot(ost, dir); } out: return ret; } errcode_t o2fsck_pass3(o2fsck_state *ost) { o2fsck_dir_parent *dp; errcode_t ret = 0; printf("Pass 3: Checking directory connectivity.\n"); /* these could probably share more code. We might need to treat the * other required directories like root here */ check_root(ost); check_lostfound(ost); dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, ost->ost_fs->fs_root_blkno); if (dp == NULL) { ret = OCFS2_ET_INTERNAL_FAILURE; com_err(whoami, ret, "root inode %"PRIu64" wasn't marked as " "a directory in pass1", ost->ost_fs->fs_root_blkno); goto out; } dp->dp_connected = 1; dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, ost->ost_fs->fs_sysdir_blkno); if (dp == NULL) { ret = OCFS2_ET_INTERNAL_FAILURE; com_err(whoami, ret, "system dir inode %"PRIu64" wasn't " "marked as a directory in pass1", ost->ost_fs->fs_sysdir_blkno); goto out; } dp->dp_connected = 1; for(dp = o2fsck_dir_parent_first(&ost->ost_dir_parents) ; dp; dp = o2fsck_dir_parent_next(dp)) { /* XXX hmm, make sure dir->ino is in the dir map? */ ret = connect_directory(ost, dp); if (ret) goto out; } out: return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass4.c0000644000176100017610000002240411500500544014111 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * Pass 4 walks all the active inodes and makes sure that they are reachable * via directory entries, just like pass 3 did for directories. It also * makes sure each inode's link_count reflects the number of entries that * refer to it. Inodes that aren't referred to by any entries are moved * to lost+found. */ #include #include #include "ocfs2/ocfs2.h" #include "fsck.h" #include "icount.h" #include "pass3.h" #include "pass4.h" #include "problem.h" #include "util.h" struct orphan_dir_ctxt { o2fsck_state *ost; uint64_t orphan_dir; }; static const char *whoami = "pass4"; static void check_link_counts(o2fsck_state *ost, struct ocfs2_dinode *di, uint64_t blkno) { uint16_t refs, in_inode; errcode_t ret; refs = o2fsck_icount_get(ost->ost_icount_refs, blkno); in_inode = o2fsck_icount_get(ost->ost_icount_in_inodes, blkno); verbosef("ino %"PRIu64", refs %u in %u\n", blkno, refs, in_inode); /* XXX offer to remove files/dirs with no data? */ if (refs == 0 && prompt(ost, PY, PR_INODE_NOT_CONNECTED, "Inode %"PRIu64" isn't referenced by any " "directory entries. Move it to lost+found?", blkno)) { o2fsck_reconnect_file(ost, blkno); refs = o2fsck_icount_get(ost->ost_icount_refs, blkno); } if (refs == in_inode) goto out; ret = ocfs2_read_inode(ost->ost_fs, blkno, (char *)di); if (ret) { com_err(whoami, ret, "reading inode %"PRIu64" to update its " "i_links_count. Could this be because a directory " "entry referenced an invalid inode but wasn't fixed?", blkno); goto out; } if (in_inode != di->i_links_count) com_err(whoami, OCFS2_ET_INTERNAL_FAILURE, "fsck's thinks " "inode %"PRIu64" has a link count of %"PRIu16" but on " "disk it is %"PRIu16, (uint64_t)di->i_blkno, in_inode, di->i_links_count); if (prompt(ost, PY, PR_INODE_COUNT, "Inode %"PRIu64" has a link count of %"PRIu16" on " "disk but directory entry references come to %"PRIu16". " "Update the count on disk to match?", (uint64_t)di->i_blkno, in_inode, refs)) { di->i_links_count = refs; o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno, refs); o2fsck_write_inode(ost, di->i_blkno, di); } out: return; } static int replay_orphan_iterate(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct orphan_dir_ctxt *ctxt = priv_data; o2fsck_state *ost = ctxt->ost; int ret_flags = 0; errcode_t ret = 0; if (!(ost->ost_fs->fs_flags & OCFS2_FLAG_RW)) { printf("** Skipping orphan dir replay because -n was " "given.\n"); ret_flags |= OCFS2_DIRENT_ABORT; goto out; } /* Only ask for confirmation in force check. */ if (ost->ost_force) { if (!prompt(ost, PY, PR_INODE_ORPHANED, "Inode %"PRIu64" was found in the orphan directory. " "Delete its contents and unlink it?", (uint64_t)dirent->inode)) goto out; } ret = ocfs2_truncate(ost->ost_fs, dirent->inode, 0); if (ret) { com_err(whoami, ret, "while truncating orphan inode %"PRIu64, (uint64_t)dirent->inode); ret_flags |= OCFS2_DIRENT_ABORT; goto out; } ret = ocfs2_delete_inode(ost->ost_fs, dirent->inode); if (ret) { com_err(whoami, ret, "while deleting orphan inode %"PRIu64 "after truncating it", (uint64_t)dirent->inode); ret_flags |= OCFS2_DIRENT_ABORT; goto out; } /* Only calculate icount in force check. */ if (ost->ost_force) { /* * this matches a special case in o2fsck_verify_inode_fields() * where orphan dir members are recorded as having 1 link count, * even though they have 0 on disk */ o2fsck_icount_delta(ost->ost_icount_in_inodes, dirent->inode, -1); /* * dirs have this dirent ref and their '.' dirent and we also * need to handle '..' dirent for their parents. */ if (dirent->file_type == OCFS2_FT_DIR) { o2fsck_icount_delta(ost->ost_icount_refs, dirent->inode, -2); o2fsck_icount_delta(ost->ost_icount_refs, ctxt->orphan_dir, -1); } else o2fsck_icount_delta(ost->ost_icount_refs, dirent->inode, -1); } dirent->inode = 0; ret_flags |= OCFS2_DIRENT_CHANGED; out: ost->ost_err = ret; return ret_flags; } static errcode_t create_orphan_dir(o2fsck_state *ost, char *fname) { errcode_t ret; uint64_t blkno; ocfs2_filesys *fs = ost->ost_fs; /* create inode for system file */ ret = ocfs2_new_system_inode(fs, &blkno, ocfs2_system_inodes[ORPHAN_DIR_SYSTEM_INODE].si_mode, ocfs2_system_inodes[ORPHAN_DIR_SYSTEM_INODE].si_iflags); if (ret) goto bail; ret = ocfs2_init_dir(fs, blkno, fs->fs_sysdir_blkno); if (ret) goto bail; /* Add the inode to the system dir */ ret = ocfs2_link(fs, fs->fs_sysdir_blkno, fname, blkno, OCFS2_FT_DIR); if (ret) goto bail; /* we have created an orphan dir under system dir and updated the disk, * so we have to update the refs in ost accordingly. */ o2fsck_icount_delta(ost->ost_icount_refs, fs->fs_sysdir_blkno, 1); o2fsck_icount_delta(ost->ost_icount_in_inodes, fs->fs_sysdir_blkno, 1); bail: return ret; } /* * replay_orphan_dir could happen in 2 places and we handle it diffrently. * 1. In slot recovery, we will return any error which lead to a force check. * 2. in o2fsck_pass4, all other errors should be fixed in pass0,1,2 and 3, so * we try to fix some errors by ourselves. */ errcode_t replay_orphan_dir(o2fsck_state *ost, int slot_recovery) { errcode_t ret = OCFS2_ET_CORRUPT_SUPERBLOCK; char name[PATH_MAX]; uint64_t ino; int bytes; int i; int num_slots = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots; struct orphan_dir_ctxt ctxt; ctxt.ost = ost; for (i = 0; i < num_slots; ++i) { bytes = ocfs2_sprintf_system_inode_name(name, PATH_MAX, ORPHAN_DIR_SYSTEM_INODE, i); if (bytes < 1) { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } ret = ocfs2_lookup(ost->ost_fs, ost->ost_fs->fs_sysdir_blkno, name, bytes, NULL, &ino); if (ret) { if (slot_recovery) goto out; if (ret != OCFS2_ET_FILE_NOT_FOUND) goto out; /* orphan dir is missing, it may be caused by an * unsuccessful removing slots in tunefs.ocfs2. * so create it. */ if (prompt(ost, PY, PR_ORPHAN_DIR_MISSING, "%s is missing in system directory. " "Create it?", name)) { ret = create_orphan_dir(ost, name); if (ret) { com_err(whoami, ret, "while creating" "orphan directory %s", name); continue; } } } ctxt.orphan_dir = ino; ost->ost_err = 0; ret = ocfs2_dir_iterate(ost->ost_fs, ino, OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL, replay_orphan_iterate, &ctxt); if (!ret) ret = ost->ost_err; if (ret && slot_recovery) break; } out: return ret; } /* return the next inode that has either directory entries pointing to it or * that was valid and had a non-zero i_links_count. OCFS2_ET_BIT_NOT_FOUND * will be bubbled up from the next_blkno() calls when there is no such next * inode. It is expected that sometimes these won't match. If a directory * has been lost there can be inodes with i_links_count and no directory * entries at all. If an inode was lost but the user chose not to erase * the directory entries then there may be references to inodes that * we never saw the i_links_count for */ static errcode_t next_inode_any_ref(o2fsck_state *ost, uint64_t start, uint64_t *blkno_ret) { errcode_t tmp, ret = OCFS2_ET_BIT_NOT_FOUND; uint64_t blkno; tmp = o2fsck_icount_next_blkno(ost->ost_icount_refs, start, &blkno); if (tmp == 0) { *blkno_ret = blkno; ret = 0; } tmp = o2fsck_icount_next_blkno(ost->ost_icount_in_inodes, start, &blkno); /* use this if we didn't have one yet or this one's lesser */ if (tmp == 0 && (ret != 0 || (blkno < *blkno_ret))) { ret = 0; *blkno_ret = blkno; } return ret; } errcode_t o2fsck_pass4(o2fsck_state *ost) { struct ocfs2_dinode *di; char *buf = NULL; errcode_t ret; uint64_t blkno = 0, start; printf("Pass 4a: checking for orphaned inodes\n"); ret = replay_orphan_dir(ost, 0); if (ret) { com_err(whoami, ret, "while trying to replay the orphan " "directory"); goto out; } printf("Pass 4b: Checking inodes link counts.\n"); ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating space to read inodes"); goto out; } di = (struct ocfs2_dinode *)buf; start = 0; while (next_inode_any_ref(ost, start, &blkno) == 0) { check_link_counts(ost, di, blkno); start = blkno + 1; } out: if (buf) ocfs2_free(&buf); return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/pass5.c0000644000176100017610000003567311453177334014144 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2009 Novell. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * Pass 5 tries to read as much data as possible from the global quota file. * (we are interested mainly in limits for users and groups). After that we * scan the filesystem and recompute quota usage for each user / group and * finally we dump all the information into freshly created quota files. * * At this pass, filesystem should be already sound, so we use libocfs2 * functions for low-level operations. * * FIXME: We could also check node-local quota files and use limits there. * For now we just discard them. */ #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "ocfs2/byteorder.h" #include "fsck.h" #include "pass5.h" #include "problem.h" #include "strings.h" #include "util.h" static const char *whoami = "pass5"; static char *qbmp[MAXQUOTAS]; static ocfs2_quota_hash *qhash[MAXQUOTAS]; static char *type2name(int type) { if (type == USRQUOTA) return "user"; return "group"; } static errcode_t o2fsck_release_dquot(ocfs2_cached_dquot *dquot, void *p) { ocfs2_quota_hash *hash = p; ocfs2_remove_quota_hash(hash, dquot); ocfs2_free(&dquot); return 0; } static int check_blkref(uint32_t block, uint32_t maxblocks) { if (block < QT_TREEOFF || block >= maxblocks) return 0; return 1; } static errcode_t o2fsck_validate_blk(ocfs2_filesys *fs, char *buf) { struct ocfs2_disk_dqtrailer *dqt = ocfs2_block_dqtrailer(fs->fs_blocksize, buf); return ocfs2_validate_meta_ecc(fs, buf, &dqt->dq_check); } static int o2fsck_valid_quota_info(ocfs2_filesys *fs, int type, struct ocfs2_disk_dqheader *header, struct ocfs2_global_disk_dqinfo *info) { uint32_t magics[MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS; int versions[MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS; if (header->dqh_magic != magics[type] || header->dqh_version > versions[type]) return 0; if (info->dqi_blocks != fs->qinfo[type].qi_inode->ci_inode->i_size / fs->fs_blocksize) return 0; if ((info->dqi_free_blk && !check_blkref(info->dqi_free_blk, info->dqi_blocks)) || (info->dqi_free_entry && !check_blkref(info->dqi_free_entry, info->dqi_blocks))) return 0; return 1; } static errcode_t o2fsck_read_blk(ocfs2_filesys *fs, int type, char *buf, uint32_t blk) { uint32_t got; errcode_t ret; ret = ocfs2_file_read(fs->qinfo[type].qi_inode, buf, fs->fs_blocksize, blk * fs->fs_blocksize, &got); if (ret) return ret; if (got != fs->fs_blocksize) return OCFS2_ET_SHORT_READ; return 0; } static errcode_t o2fsck_check_info(o2fsck_state *ost, int type) { errcode_t ret; ocfs2_filesys *fs = ost->ost_fs; char *buf; struct ocfs2_disk_dqheader *header; struct ocfs2_global_disk_dqinfo *info; uint64_t blocks; int checksum_valid; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating block buffer"); goto set_default; } ret = o2fsck_read_blk(fs, type, buf, 0); if (ret) { com_err(whoami, ret, "while reading global %s quota info " "block", type2name(type)); goto set_default; } checksum_valid = !o2fsck_validate_blk(fs, buf); header = (struct ocfs2_disk_dqheader *)buf; info = (struct ocfs2_global_disk_dqinfo *)(buf + OCFS2_GLOBAL_INFO_OFF); ocfs2_swap_quota_header(header); ocfs2_swap_quota_global_info(info); if ((!checksum_valid || !o2fsck_valid_quota_info(fs, type, header, info)) && !prompt(ost, PN, PR_QMAGIC_INVALID, "%s quota info looks corrupt." " Use its content:\nBlock grace time: %"PRIu32" sec\n" "Inode grace time: %"PRIu32" sec\n" "Cluster quota sync time: %"PRIu32" ms\n", type2name(type), info->dqi_bgrace, info->dqi_igrace, info->dqi_syncms)) { goto set_default; } fs->qinfo[type].qi_info.dqi_bgrace = info->dqi_bgrace; fs->qinfo[type].qi_info.dqi_igrace = info->dqi_igrace; fs->qinfo[type].qi_info.dqi_syncms = info->dqi_syncms; goto set_blocks; set_default: fs->qinfo[type].qi_info.dqi_bgrace = OCFS2_DEF_BLOCK_GRACE; fs->qinfo[type].qi_info.dqi_igrace = OCFS2_DEF_INODE_GRACE; fs->qinfo[type].qi_info.dqi_syncms = OCFS2_DEF_QUOTA_SYNC; set_blocks: blocks = fs->qinfo[type].qi_inode->ci_inode->i_size / fs->fs_blocksize; if (blocks > (1ULL << 32) - 1) fs->qinfo[type].qi_info.dqi_blocks = (1ULL << 32) - 1; else fs->qinfo[type].qi_info.dqi_blocks = blocks; return ret; } /* Check whether a reference to a tree block is sane */ static int o2fsck_check_tree_ref(o2fsck_state *ost, int type, uint32_t blk, int depth) { ocfs2_filesys *fs = ost->ost_fs; uint32_t blocks = fs->qinfo[type].qi_info.dqi_blocks; /* Bogus block number? */ if (!check_blkref(blk, blocks)) { verbosef("ignoring invalid %s quota block reference %"PRIu32, type2name(type), blk); return 0; } /* Already scanned block? */ if (depth < ocfs2_qtree_depth(fs->fs_blocksize) && ocfs2_test_bit(blk, qbmp[type])) { verbosef("ignoring duplicate %s quota block reference %"PRIu32, type2name(type), blk); return 0; } return 1; } /* Read the block, check dquot structures in it */ static errcode_t o2fsck_check_data_blk(o2fsck_state *ost, int type, uint32_t blk, char *buf) { ocfs2_filesys *fs = ost->ost_fs; errcode_t ret; struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int str_in_blk = ocfs2_global_dqstr_in_blk(fs->fs_blocksize); int i; struct ocfs2_global_disk_dqblk *ddquot; ocfs2_cached_dquot *dquot; uint32_t blocks = fs->qinfo[type].qi_info.dqi_blocks; int valid = 1; ocfs2_set_bit(blk, qbmp[type]); ret = o2fsck_read_blk(fs, type, buf, blk); if (ret) { com_err(whoami, ret, "while reading %s quota file block %"PRIu32, type2name(type), blk); return ret; } ret = o2fsck_validate_blk(fs, buf); if (ret) { verbosef("%s: invalid checksum in %s quota leaf block (block %" PRIu32")", error_message(ret), type2name(type), blk); valid = 0; } ocfs2_swap_quota_leaf_block_header(dh); if ((dh->dqdh_next_free && !check_blkref(dh->dqdh_next_free, blocks)) || (dh->dqdh_prev_free && !check_blkref(dh->dqdh_prev_free, blocks)) || dh->dqdh_entries > str_in_blk) { verbosef("corrupt %s quota leaf block header (block %"PRIu32")", type2name(type), blk); valid = 0; } ddquot = (struct ocfs2_global_disk_dqblk *)(buf + sizeof(struct qt_disk_dqdbheader)); for (i = 0; i < str_in_blk; i++, ddquot++) { if (ocfs2_qtree_entry_unused(ddquot)) continue; ocfs2_swap_quota_global_dqblk(ddquot); ret = ocfs2_find_quota_hash(qhash[type], ddquot->dqb_id, &dquot); if (ret) { com_err(whoami, ret, "while searching in %s quota hash", type2name(type)); return ret; } if (dquot && valid) { if (!prompt(ost, PY, PR_DUP_DQBLK_VALID, "Duplicate %s quota structure for id %" PRIu32":\nCurrent quota limits: Inode: %" PRIu64" %"PRIu64" Space: %"PRIu64" %" PRIu64"\nFound quota limits: Inode: %" PRIu64" %"PRIu64" Space: %"PRIu64" %" PRIu64"\nUse found limits?", type2name(type), ddquot->dqb_id, dquot->d_ddquot.dqb_isoftlimit, dquot->d_ddquot.dqb_ihardlimit, dquot->d_ddquot.dqb_bsoftlimit, dquot->d_ddquot.dqb_bhardlimit, ddquot->dqb_isoftlimit, ddquot->dqb_ihardlimit, ddquot->dqb_bsoftlimit, ddquot->dqb_bhardlimit)) continue; } else if (dquot && !valid) { if (!prompt(ost, PN, PR_DUP_DQBLK_INVALID, "Found %s quota structure for id %"PRIu32 " in a corrupted block and already have " "values for this id:\nCurrent quota " "limits: Inode: %"PRIu64" %"PRIu64" Space:" " %"PRIu64" %"PRIu64"\nFound quota limits:" " Inode: %"PRIu64" %"PRIu64" Space: %" PRIu64" %"PRIu64"\nUse found limits?", type2name(type), ddquot->dqb_id, dquot->d_ddquot.dqb_isoftlimit, dquot->d_ddquot.dqb_ihardlimit, dquot->d_ddquot.dqb_bsoftlimit, dquot->d_ddquot.dqb_bhardlimit, ddquot->dqb_isoftlimit, ddquot->dqb_ihardlimit, ddquot->dqb_bsoftlimit, ddquot->dqb_bhardlimit)) continue; } else if (!dquot && !valid) { if (!prompt(ost, PN, PR_DQBLK_INVALID, "Found corrupted %s quota structure for id" " %"PRIu32":\nFound quota limits: Inode: %" PRIu64" %"PRIu64" Space: %"PRIu64" %" PRIu64"\nUse found limits?", type2name(type), ddquot->dqb_id, ddquot->dqb_isoftlimit, ddquot->dqb_ihardlimit, ddquot->dqb_bsoftlimit, ddquot->dqb_bhardlimit)) continue; } if (!dquot) { ret = ocfs2_find_create_quota_hash(qhash[type], ddquot->dqb_id, &dquot); if (ret) { com_err(whoami, ret, "while inserting quota" " structure into hash"); return ret; } } memcpy(&dquot->d_ddquot, ddquot, sizeof(struct ocfs2_global_disk_dqblk)); dquot->d_ddquot.dqb_use_count = 0; dquot->d_ddquot.dqb_curinodes = 0; dquot->d_ddquot.dqb_curspace = 0; } return 0; } /* Read the block, check references in it */ static errcode_t o2fsck_check_tree_blk(o2fsck_state *ost, int type, uint32_t blk, int depth, char *buf) { ocfs2_filesys *fs = ost->ost_fs; errcode_t ret; int epb = (fs->fs_blocksize - OCFS2_QBLK_RESERVED_SPACE) >> 2; int tree_depth = ocfs2_qtree_depth(fs->fs_blocksize); int i; uint32_t *refs = (uint32_t *)buf, actref; ocfs2_set_bit(blk, qbmp[type]); ret = o2fsck_read_blk(fs, type, buf, blk); if (ret) { com_err(whoami, ret, "while reading %s quota file block %"PRIu32, type2name(type), blk); goto out; } ret = o2fsck_validate_blk(fs, buf); if (ret && !prompt(ost, PN, PR_QTREE_BLK_INVALID, "Corrupted %s quota tree " "block %"PRIu32" (checksum error: %s). Scan referenced " "blocks anyway?", type2name(type), blk, error_message(ret))) { goto out; } for (i = 0; i < epb; i++) { actref = le32_to_cpu(refs[i]); if (!actref) continue; /* Valid block reference? */ if (o2fsck_check_tree_ref(ost, type, actref, depth + 1)) { if (depth + 1 < tree_depth) { ret = o2fsck_check_tree_blk(ost, type, actref, depth + 1, buf + fs->fs_blocksize); } else if (!ocfs2_test_bit(actref, qbmp[type])) { ret = o2fsck_check_data_blk(ost, type, actref, buf + fs->fs_blocksize); } if (ret) goto out; } } out: return ret; } static errcode_t load_quota_file(o2fsck_state *ost, int type) { ocfs2_filesys *fs = ost->ost_fs; char *buf = NULL; errcode_t ret; ret = ocfs2_init_fs_quota_info(fs, type); if (ret) { com_err(whoami, ret, "while looking up global %s quota file", type2name(type)); goto out; } ret = o2fsck_check_info(ost, type); /* Some fatal error happened? */ if (ret) goto out; ret = ocfs2_malloc0((fs->qinfo[type].qi_info.dqi_blocks + 7) / 8, qbmp + type); if (ret) { com_err(whoami, ret, "while allocating %s quota file block " "bitmap", type2name(type)); goto out; } ret = ocfs2_malloc_blocks(fs->fs_io, ocfs2_qtree_depth(fs->fs_blocksize) + 1, &buf); if (ret) { com_err(whoami, ret, "while allocating buffer for quota blocks"); goto out; } if (!o2fsck_check_tree_ref(ost, type, QT_TREEOFF, 0)) goto out; ret = o2fsck_check_tree_blk(ost, type, QT_TREEOFF, 0, buf); out: if (qbmp[type]) ocfs2_free(qbmp + type); if (buf) ocfs2_free(&buf); return ret; } /* You have to write the inode yourself after calling this function! */ static errcode_t truncate_cached_inode(ocfs2_filesys *fs, ocfs2_cached_inode *ci) { uint32_t new_clusters; errcode_t ret; ret = ocfs2_zero_tail_and_truncate(fs, ci, 0, &new_clusters); if (ret) return ret; ci->ci_inode->i_clusters = new_clusters; if (new_clusters == 0) ci->ci_inode->id2.i_list.l_tree_depth = 0; ci->ci_inode->i_size = 0; return 0; } static errcode_t recreate_quota_files(ocfs2_filesys *fs, int type) { ocfs2_cached_inode *ci = fs->qinfo[type].qi_inode; errcode_t ret; ret = truncate_cached_inode(fs, ci); if (ret) { com_err(whoami, ret, "while truncating global %s quota file", type2name(type)); return ret; } ret = ocfs2_init_global_quota_file(fs, type); if (ret) { com_err(whoami, ret, "while reinitializing global %s quota file", type2name(type)); return ret; } ret = ocfs2_write_release_dquots(fs, type, qhash[type]); if (ret) { com_err(whoami, ret, "while writing %s quota usage", type2name(type)); return ret; } ret = ocfs2_init_local_quota_files(fs, type); if (ret) { com_err(whoami, ret, "while initializing local quota files"); return ret; } return 0; } errcode_t o2fsck_pass5(o2fsck_state *ost) { errcode_t ret; ocfs2_filesys *fs = ost->ost_fs; struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); int has_usrquota, has_grpquota; has_usrquota = OCFS2_HAS_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_USRQUOTA); has_grpquota = OCFS2_HAS_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA); /* Nothing to check? */ if (!has_usrquota && !has_grpquota) return 0; printf("Pass 5: Checking quota information.\n"); if (has_usrquota) { ret = ocfs2_new_quota_hash(qhash + USRQUOTA); if (ret) { com_err(whoami, ret, "while allocating user quota hash"); goto out; } ret = load_quota_file(ost, USRQUOTA); if (ret) goto out; } if (has_grpquota) { ret = ocfs2_new_quota_hash(qhash + GRPQUOTA); if (ret) { com_err(whoami, ret, "while allocating group quota hash"); goto out; } ret = load_quota_file(ost, GRPQUOTA); if (ret) goto out; } ret = ocfs2_compute_quota_usage(fs, qhash[USRQUOTA], qhash[GRPQUOTA]); if (ret) { com_err(whoami, ret, "while computing quota usage"); goto out; } if (has_usrquota) { ret = recreate_quota_files(fs, USRQUOTA); if (ret) goto out; ret = ocfs2_free_quota_hash(qhash[USRQUOTA]); if (ret) { com_err(whoami, ret, "while release user quota hash"); goto out; } } if (has_grpquota) { ret = recreate_quota_files(fs, GRPQUOTA); if (ret) goto out; ret = ocfs2_free_quota_hash(qhash[GRPQUOTA]); if (ret) { com_err(whoami, ret, "while release group quota hash"); goto out; } } return 0; out: if (qhash[USRQUOTA]) { ocfs2_iterate_quota_hash(qhash[USRQUOTA], o2fsck_release_dquot, qhash[USRQUOTA]); ocfs2_free_quota_hash(qhash[USRQUOTA]); } if (qhash[GRPQUOTA]) { ocfs2_iterate_quota_hash(qhash[GRPQUOTA], o2fsck_release_dquot, qhash[GRPQUOTA]); ocfs2_free_quota_hash(qhash[GRPQUOTA]); } return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/problem.c0000644000176100017610000000732111115551035014523 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 1993-2004 by Theodore Ts'o. * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * prompt() asks the user whether a given problem should be fixed or not. * "problem.c" is derived from the baroque e2fsck origins of this concept. * * XXX * The significant gap here is in persistent answers. Often one wants * to tell fsck to stop asking the same freaking question over and over * until a different question is asked. */ #include #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "problem.h" #include "util.h" /* XXX more of fsck will want this.. */ static sig_atomic_t interrupted = 0; static void handle_sigint(int sig) { interrupted = 1; } /* * when a caller cares why read() failed we can bother to communicate * the error. */ static int read_a_char(int fd) { struct termios orig, new; char c; ssize_t ret; struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handle_sigint; sa.sa_flags = SA_ONESHOT; /* !SA_RESTART */ sigaction(SIGINT, &sa, NULL); /* turn off buffering and echoing and encourage single character * reads */ tcgetattr(0, &orig); new = orig; new.c_lflag &= ~(ICANON | ECHO); new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; tcsetattr (0, TCSANOW, &new); ret = read(fd, &c, sizeof(c)); tcsetattr (0, TCSANOW, &orig); if (interrupted) return 3; if (ret != sizeof(c)) return EOF; return c; } /* * this checks the user's intent. someday soon it will check command line flags * and have a notion of grouping, as well. The caller is expected to provide * a fully formed question that isn't terminated with a newline. */ int prompt_input(o2fsck_state *ost, unsigned flags, struct prompt_code code, const char *fmt, ...) { va_list ap; int c, ans = 0; static char yes[] = " ", no[] = " "; /* paranoia for jokers that claim to default to both */ if((flags & PY) && (flags & PN)) flags &= ~PY; printf("[%s] ", code.str); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); if (!ost->ost_ask) { ans = ost->ost_answer ? 'y' : 'n'; } else { if (flags & PY) printf(yes); else if (flags & PN) printf(no); } fflush(stdout); /* no curses, no nothin. overly regressive? */ while (!ans && (c = read_a_char(fileno(stdin))) != EOF) { if (c == 3) { printf("ctl-c pressed, aborting.\n"); exit(FSCK_ERROR|FSCK_CANCELED); } if (c == 27) { printf("ESC pressed, aborting.\n"); exit(FSCK_ERROR|FSCK_CANCELED); } c = tolower(c); /* space or CR lead to applying the optional default */ if (c == ' ' || c == '\n') { if (flags & PY) c = 'y'; else if (flags & PN) c = 'n'; } if (c == 'y' || c == 'n') { ans = c; break; } /* otherwise keep asking */ } if (!ans) { printf("input failed, aborting.\n"); exit(FSCK_ERROR); } /* this is totally silly. */ if (!ost->ost_ask) printf(" %c\n", ans); else printf("%c\n", ans); return ans == 'y'; } ./ocfs2-tools-1.6.4/fsck.ocfs2/refcount.c0000644000176100017610000007002211453177334014721 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * refcount.c * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #include #include #include "ocfs2/kernel-rbtree.h" #include "ocfs2-kernel/kernel-list.h" #include "ocfs2/ocfs2.h" #include "problem.h" #include "fsck.h" #include "extent.h" #include "util.h" #include "refcount.h" static const char *whoami = "refcount.c"; struct check_refcount_rec { uint64_t root_blkno; uint64_t c_end; }; /* every REFCOUNTED ocfs2_extent_rec will become one. */ struct refcount_extent { struct rb_node ext_node; uint32_t v_cpos; uint32_t clusters; uint64_t p_cpos; }; struct refcount_file { struct list_head list; uint64_t i_blkno; struct rb_root ref_extents; /* store every refcounted extent rec * in this file. */ }; struct refcount_tree { struct rb_node ref_node; uint64_t rf_blkno; uint64_t rf_end; struct list_head files_list; int files_count; int is_valid; char *root_buf; char *leaf_buf; /* the cluster offset we have checked against this tree. */ uint64_t p_cend; }; static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno, uint64_t root_blkno, uint64_t *c_end, int *is_valid); static void check_rl(o2fsck_state *ost, uint64_t rb_blkno, uint64_t root_blkno, struct ocfs2_refcount_list *rl, uint64_t *c_end, int *changed) { struct ocfs2_refcount_rec *rec; uint16_t i; size_t cpy; int trust_used = 1; int max_recs = ocfs2_refcount_recs_per_rb(ost->ost_fs->fs_blocksize); verbosef("count %u used %u\n", rl->rl_count, rl->rl_used); if (rl->rl_count > max_recs && prompt(ost, PY, PR_REFCOUNT_LIST_COUNT, "Refcount list in refcount tree %"PRIu64" claims to have %u " "records, but the maximum is %u. Fix the list's count?", root_blkno, rl->rl_count, max_recs)) { rl->rl_count = max_recs; *changed = 1; } if (max_recs > rl->rl_count) max_recs = rl->rl_count; if (rl->rl_used > max_recs) { if (prompt(ost, PY, PR_REFCOUNT_LIST_USED, "Refcount list in refcount tree %"PRIu64" claims %u " "as the used record, but fsck believes " "the largest valid value is %u. Clamp the used " "record value?", root_blkno, rl->rl_used, max_recs)) { rl->rl_used = rl->rl_count; *changed = 1; } else trust_used = 0; } if (trust_used) max_recs = rl->rl_used; for (i = 0; i < max_recs; i++) { rec = &rl->rl_recs[i]; /* offer to remove records that point to nowhere */ if (ocfs2_block_out_of_range(ost->ost_fs, ocfs2_clusters_to_blocks(ost->ost_fs, rec->r_cpos + rec->r_clusters - 1)) && prompt(ost, PY, PR_REFCOUNT_CLUSTER_RANGE, "Refcount record %u in refcount block %"PRIu64" " "of refcount tree %"PRIu64" refers to a cluster " "that is out of range. Remove " "this record from the refcount list?", i, rb_blkno, root_blkno)) { if (!trust_used) { printf("Can't remove the record becuase " "rl_used hasn't been fixed\n"); continue; } goto remove_rec; } if (rec->r_cpos < *c_end && prompt(ost, PY, PR_REFCOUNT_CLUSTER_COLLISION, "Refcount record %u in refcount block %"PRIu64" " "of refcount tree %"PRIu64" refers to a cluster " "that is collided with the previous record. Remove " "this record from the refcount list?", i, rb_blkno, root_blkno)) { if (!trust_used) { printf("Can't remove the record becuase " "rl_used hasn't been fixed\n"); continue; } goto remove_rec; } *c_end = rec->r_cpos + rec->r_clusters; continue; remove_rec: cpy = (max_recs - i - 1) * sizeof(*rec); /* shift the remaining recs into this ones place */ if (cpy != 0) { memcpy(rec, rec + 1, cpy); memset(&rl->rl_recs[max_recs - 1], 0, sizeof(*rec)); i--; } rl->rl_used--; max_recs--; *changed = 1; continue; } } static errcode_t refcount_check_leaf_extent_rec(o2fsck_state *ost, uint64_t owner, struct ocfs2_extent_list *el, struct ocfs2_extent_rec *er, int *changed, void *para) { errcode_t ret; int is_valid = 1; struct check_refcount_rec *check = para; ret = check_rb(ost, er->e_blkno, check->root_blkno, &check->c_end, &is_valid); if (!is_valid && prompt(ost, PY, PR_REFCOUNT_BLOCK_INVALID, "Refcount block %"PRIu64 " for tree %"PRIu64" is invalid. " "Remove it from the tree?", (uint64_t)er->e_blkno, check->root_blkno)) { er->e_blkno = 0; *changed = 1; } return ret; } static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno, uint64_t root_blkno, uint64_t *c_end, int *is_valid) { int changed = 0; char *buf = NULL; struct ocfs2_refcount_block *rb; errcode_t ret; /* XXX test that the block isn't already used */ /* we only consider a refcount block invalid if we were able to read * it and it didn't have a refcount block signature */ *is_valid = 1; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating a block-sized buffer " "for a refcount block"); goto out; } ret = ocfs2_read_refcount_block_nocheck(ost->ost_fs, blkno, buf); if (ret) { com_err(whoami, ret, "reading refcount block at %"PRIu64" in " "refcount tree %"PRIu64" for verification", blkno, root_blkno); if (ret == OCFS2_ET_BAD_EXTENT_BLOCK_MAGIC) *is_valid = 0; goto out; } rb = (struct ocfs2_refcount_block *)buf; if (rb->rf_blkno != blkno && prompt(ost, PY, PR_RB_BLKNO, "A refcount block at %"PRIu64" in refcount tree %"PRIu64" " "claims to be located at block %"PRIu64". Update the " "refcount block's location?", blkno, root_blkno, (uint64_t)rb->rf_blkno)) { rb->rf_blkno = blkno; changed = 1; } if (rb->rf_fs_generation != ost->ost_fs_generation) { if (prompt(ost, PY, PR_RB_GEN, "A refcount block at %"PRIu64" in refcount tree " "%"PRIu64" has a generation of %x which doesn't " "match the volume's generation of %x. Consider " "this refcount block invalid?", blkno, root_blkno, rb->rf_fs_generation, ost->ost_fs_generation)) { *is_valid = 0; goto out; } if (prompt(ost, PY, PR_RB_GEN_FIX, "Update the refcount block's generation to match " "the volume?")) { rb->rf_fs_generation = ost->ost_fs_generation; changed = 1; } } if (rb->rf_blkno != root_blkno && rb->rf_parent != root_blkno && prompt(ost, PY, PR_RB_PARENT, "A refcount block at %"PRIu64" in refcount tree %"PRIu64" " "claims to belong to tree %"PRIu64". Update the " "parent's information?", blkno, root_blkno, (uint64_t)rb->rf_parent)) { rb->rf_parent = root_blkno; changed = 1; } /* XXX worry about suballoc node/bit */ if (rb->rf_flags & OCFS2_REFCOUNT_TREE_FL) { struct check_refcount_rec check = {root_blkno, *c_end}; struct extent_info ei = {0, }; uint16_t max_recs = ocfs2_extent_recs_per_rb(ost->ost_fs->fs_blocksize); ei.para = ✓ ei.chk_rec_func = refcount_check_leaf_extent_rec; /* * leaf extent rec for a refcount tree is allocated from * extent_alloc, so we don't need to set mark_rec_alloc_func * here. */ check_el(ost, &ei, rb->rf_blkno, &rb->rf_list, max_recs, &changed); *c_end = check.c_end; if (ei.ei_clusters != rb->rf_clusters && prompt(ost, PY, PR_REFCOUNT_CLUSTERS, "Refcount tree %"PRIu64" claims to have %u " "clusters, but we only found %u. " "Fix it?", root_blkno, rb->rf_clusters, (uint32_t)ei.ei_clusters)) { rb->rf_clusters = ei.ei_clusters; changed = 1; } } else { assert(c_end); check_rl(ost, root_blkno, blkno, &rb->rf_records, c_end, &changed); /* We allow the root block to be empty. */ if (root_blkno != blkno && !rb->rf_records.rl_used && prompt(ost, PY, PR_REFCOUNT_LIST_EMPTY, "Refcount block %"PRIu64" claims to have no " "refcount record in it. Consider it as invalid " "and Remove from tree?", (uint64_t)rb->rf_blkno)) { *is_valid = 0; changed = 1; } } if (changed) { ret = ocfs2_write_refcount_block(ost->ost_fs, blkno, buf); if (ret) { com_err(whoami, ret, "while writing an updated " "refcount block at %"PRIu64" for refcount " "tree %"PRIu64, blkno, root_blkno); goto out; } } out: if (buf) ocfs2_free(&buf); return 0; } /* See if the recount_tree rbtree has the given ref_blkno. */ static struct refcount_tree* refcount_tree_lookup(o2fsck_state *ost, uint64_t ref_blkno) { struct rb_node *p = ost->ost_refcount_trees.rb_node; struct refcount_tree *ref_tree; while (p) { ref_tree = rb_entry(p, struct refcount_tree, ref_node); if (ref_blkno < ref_tree->rf_blkno) p = p->rb_left; else if (ref_blkno > ref_tree->rf_blkno) p = p->rb_right; else return ref_tree; } return NULL; } static void refcount_tree_insert(o2fsck_state *ost, struct refcount_tree *insert_rb) { struct rb_node **p = &ost->ost_refcount_trees.rb_node; struct rb_node *parent = NULL; struct refcount_tree *ref_tree = NULL; while (*p) { parent = *p; ref_tree = rb_entry(parent, struct refcount_tree, ref_node); if (insert_rb->rf_blkno < ref_tree->rf_blkno) p = &(*p)->rb_left; else if (insert_rb->rf_blkno > ref_tree->rf_blkno) p = &(*p)->rb_right; else assert(0); /* Caller checked */ } rb_link_node(&insert_rb->ref_node, parent, p); rb_insert_color(&insert_rb->ref_node, &ost->ost_refcount_trees); } errcode_t o2fsck_check_refcount_tree(o2fsck_state *ost, struct ocfs2_dinode *di) { errcode_t ret = 0; uint64_t c_end = 0; int is_valid = 1; struct refcount_tree *tree; struct refcount_file *file; if (!(di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)) return 0; tree = refcount_tree_lookup(ost, di->i_refcount_loc); if (tree) goto check_valid; ret = ocfs2_malloc0(sizeof(struct refcount_tree), &tree); if (ret) return ret; ret = check_rb(ost, di->i_refcount_loc, di->i_refcount_loc, &c_end, &is_valid); /* * Add refcount tree to the rb-tree. * rf_end records the end of the refcount record we have. * It will be used later. */ tree->rf_blkno = di->i_refcount_loc; tree->is_valid = is_valid; tree->rf_end = c_end; INIT_LIST_HEAD(&tree->files_list); refcount_tree_insert(ost, tree); check_valid: if (!tree->is_valid && prompt(ost, PY, PR_REFCOUNT_ROOT_BLOCK_INVALID, "Refcount tree %"PRIu64 " for inode %"PRIu64" is invalid. " "Remove it and clear the flag for the inode?", (uint64_t)di->i_refcount_loc, (uint64_t)di->i_blkno)) { di->i_refcount_loc = 0; di->i_dyn_features &= ~OCFS2_HAS_REFCOUNT_FL; o2fsck_write_inode(ost, di->i_blkno, di); } else { ret = ocfs2_malloc0(sizeof(struct refcount_file), &file); if (!ret) { file->i_blkno = di->i_blkno; INIT_LIST_HEAD(&file->list); list_add_tail(&file->list, &tree->files_list); tree->files_count++; } } return ret; } static void refcount_extent_insert(struct refcount_file *file, struct refcount_extent *insert) { struct rb_node **p = &file->ref_extents.rb_node; struct rb_node *parent = NULL; struct refcount_extent *extent = NULL; while (*p) { parent = *p; extent = rb_entry(parent, struct refcount_extent, ext_node); if (insert->p_cpos < extent->p_cpos) p = &(*p)->rb_left; else if (insert->p_cpos > extent->p_cpos) p = &(*p)->rb_right; else assert(0); /* Caller checked */ } rb_link_node(&insert->ext_node, parent, p); rb_insert_color(&insert->ext_node, &file->ref_extents); } errcode_t o2fsck_mark_clusters_refcounted(o2fsck_state *ost, uint64_t rf_blkno, uint64_t i_blkno, uint64_t p_cpos, uint32_t clusters, uint32_t v_cpos) { errcode_t ret; struct refcount_tree *tree; struct refcount_file *file = ost->ost_latest_file; struct list_head *p, *next; struct refcount_extent *extent; if (file && file->i_blkno == i_blkno) goto add_clusters; tree = refcount_tree_lookup(ost, rf_blkno); /* We should already insert the tree during refcount tree check. */ assert(tree); list_for_each_safe(p, next, &tree->files_list) { file = list_entry(p, struct refcount_file, list); if (file->i_blkno == i_blkno) goto add_clusters; } /* We should already insert the file during refcount tree check. */ assert(0); add_clusters: ost->ost_latest_file = file; ret = ocfs2_malloc0(sizeof(struct refcount_extent), &extent); if (ret) return ret; extent->v_cpos = v_cpos; extent->clusters = clusters; extent->p_cpos = p_cpos; refcount_extent_insert(file, extent); return 0; } /* * Given a refcount tree, find the lowest p_cpos of all * the files sharing the tree. */ static int get_refcounted_extent(struct refcount_tree *tree, uint64_t *p_cpos, uint32_t *p_clusters, uint32_t *p_refcount) { struct refcount_extent *extent; struct refcount_file *file; struct list_head *p, *next; struct rb_node *node; uint64_t cpos = UINT64_MAX; uint32_t clusters = 0, refcount = 0; int found = 0; list_for_each_safe(p, next, &tree->files_list) { file = list_entry(p, struct refcount_file, list); node = rb_first(&file->ref_extents); /* * If the file has no extent, go to next file. * XXX: We can improve it here by removing the empty file. */ if (!node) continue; found = 1; extent = rb_entry(node, struct refcount_extent, ext_node); if (extent->p_cpos < cpos) { /* We meet with a new start. */ clusters = cpos - extent->p_cpos < extent->clusters ? cpos - extent->p_cpos : extent->clusters; cpos = extent->p_cpos; refcount = 1; } else if (extent->p_cpos == cpos) { clusters = clusters < extent->clusters ? clusters : extent->clusters; refcount++; } else if (extent->p_cpos < cpos + clusters) { /* * extent->p_cpos > cpos, change clusters accordingly. */ clusters = extent->p_cpos - cpos; } } if (!found) return 0; *p_cpos = cpos; *p_clusters = clusters; *p_refcount = refcount; return 1; } /* * Remove pair(cpos, clusters) from the all the files sharing the tree. * The pair is actually got by get_refcounted_extent. */ static void remove_refcounted_extent(struct refcount_tree *tree, uint64_t cpos, uint32_t clusters) { struct refcount_extent *extent; struct refcount_file *file; struct list_head *p, *next; struct rb_node *node; /* Remove the tuple from the refcounted file. */ list_for_each_safe(p, next, &tree->files_list) { file = list_entry(p, struct refcount_file, list); node = rb_first(&file->ref_extents); /* If the file has no extent, go to next file. */ if (!node) continue; extent = rb_entry(node, struct refcount_extent, ext_node); assert(extent->p_cpos >= cpos); if (cpos + clusters <= extent->p_cpos) continue; assert(extent->p_cpos + extent->clusters >= cpos + clusters); if (cpos + clusters == extent->p_cpos + extent->clusters) { rb_erase(&extent->ext_node, &file->ref_extents); ocfs2_free(&extent); } else { extent->clusters = (extent->p_cpos + extent->clusters) - (cpos + clusters); extent->p_cpos = cpos + clusters; } } } /* * Check all the files sharing the tree and if there is a file contains * the (p_cpos, len) with refcounted flag, we clear it. * Note: * This function is only called when checking a continuous clusters. * The pair (p_cpos, len) is a part of the original tuple we get from * get_refcounted_extent, so it can't be in 2 different refcount_extent. */ static errcode_t o2fsck_clear_refcount(o2fsck_state *ost, struct refcount_tree *tree, uint64_t p_cpos, uint32_t len) { errcode_t ret = 0; struct refcount_extent *extent; struct refcount_file *file; struct list_head *p, *next; struct rb_node *node; uint32_t v_start; list_for_each_safe(p, next, &tree->files_list) { file = list_entry(p, struct refcount_file, list); node = file->ref_extents.rb_node; /* If the file has no extent, go to next file. */ if (!node) continue; while (node) { extent = rb_entry(node, struct refcount_extent, ext_node); if (extent->p_cpos > p_cpos + len) node = node->rb_left; else if (extent->p_cpos + extent->clusters <= p_cpos) node = node->rb_right; else break; } if (node && (extent->p_cpos <= p_cpos && extent->p_cpos + extent->clusters >= p_cpos + len)) { v_start = p_cpos - extent->p_cpos + extent->v_cpos; ret = ocfs2_change_refcount_flag(ost->ost_fs, file->i_blkno, v_start, len, p_cpos, 0, OCFS2_EXT_REFCOUNTED); if (ret) { com_err(whoami, ret, "while clearing refcount flag at " "%u in file %"PRIu64, v_start, file->i_blkno); goto out; } } } out: return ret; } /* * o2fsck_refcount_punch_hole and o2fsck_change_refcount are just wrappers * for the corresponding libocfs2 functions with one addition: re-read * root refcount block since we may have changed the tree during the operation. */ static errcode_t o2fsck_refcount_punch_hole(o2fsck_state *ost, struct refcount_tree *tree, uint64_t p_cpos, uint32_t len) { errcode_t ret; ret = ocfs2_refcount_punch_hole(ost->ost_fs, tree->rf_blkno, p_cpos, len); if (ret) { com_err(whoami, ret, "while punching hole in " "(%"PRIu64", %u) in refcount tree %"PRIu64, p_cpos, len, tree->rf_blkno); goto out; } /* re-read the root blkno since we may have changed it somehow. */ ret = ocfs2_read_refcount_block(ost->ost_fs, tree->rf_blkno, tree->root_buf); out: return ret; } static errcode_t o2fsck_change_refcount(o2fsck_state *ost, struct refcount_tree *tree, uint64_t p_cpos, uint32_t len, uint32_t refcount) { errcode_t ret; ret = ocfs2_change_refcount(ost->ost_fs, tree->rf_blkno, p_cpos, len, refcount); if (ret) { com_err(whoami, ret, "while changing refcount in " "(%"PRIu64", %u) in refcount tree %"PRIu64" to %u", p_cpos, len, tree->rf_blkno, refcount); goto out; } /* re-read the root blkno since we may have changed it somehow. */ ret = ocfs2_read_refcount_block(ost->ost_fs, tree->rf_blkno, tree->root_buf); out: return ret; } /* * Given [cpos, end), remove all the refcount records in this range from * the refcount tree. */ static errcode_t o2fsck_remove_refcount_range(o2fsck_state *ost, struct refcount_tree *tree, uint64_t cpos, uint64_t end) { errcode_t ret = 0; int index; unsigned int len; struct ocfs2_refcount_rec rec; uint64_t range = end - cpos; while (range) { len = range > UINT_MAX ? UINT_MAX : range; ret = ocfs2_get_refcount_rec(ost->ost_fs, tree->root_buf, cpos, len, &rec, &index, tree->leaf_buf); if (ret) { com_err(whoami, ret, "while getting refcount rec at " "%"PRIu64" in tree %"PRIu64, cpos, tree->rf_blkno); goto out; } if (!rec.r_refcount) { cpos += rec.r_clusters; range -= rec.r_clusters; continue; } /* * In case we found some refcount rec, just ask for * punching hole for the whole range (cpos, len), and * o2fsck_refcount_punch_hole will handle the complex * issue for us. */ if (prompt(ost, PY, PR_REFCOUNT_REC_REDUNDANT, "refcount records among clusters (%"PRIu64 ", %u) are found with no physical clusters " "corresponding to them. Remove them?", cpos, len)) { ret = o2fsck_refcount_punch_hole(ost, tree, cpos, len); if (ret) { com_err(whoami, ret, "while punching " "hole in (%"PRIu64", %u) in refcount " "tree %"PRIu64, cpos, len, tree->rf_blkno); goto out; } } cpos += len; range -= len; } out: return ret; } /* * Given tuple(p_cpos, clusters, refcount), check whether the refcount * tree has the corresponding refcount record. If not, add/update them. * If the user don't allow us to change the refcount tree, add them to * to duplicate_clusters and let it handle them. */ static errcode_t o2fsck_check_clusters_in_refcount(o2fsck_state *ost, struct refcount_tree *tree, uint64_t p_cpos, uint32_t clusters, uint32_t refcount) { errcode_t ret = 0; uint32_t rec_len; int index; struct ocfs2_refcount_rec rec; if (!clusters) return 0; /* * the previous check ended at tree->p_cend, and now we get * p_cpos, so any refcount record between p_cend and p_cpos * should be considered as redundant. */ ret = o2fsck_remove_refcount_range(ost, tree, tree->p_cend, p_cpos); if (ret) { com_err(whoami, ret, "while removing refcount rec from " "%"PRIu64" to %"PRIu64" in tree %"PRIu64, tree->p_cend, p_cpos, tree->rf_blkno); goto out; } tree->p_cend = p_cpos + clusters; again: ret = ocfs2_get_refcount_rec(ost->ost_fs, tree->root_buf, p_cpos, clusters, &rec, &index, tree->leaf_buf); if (ret) { com_err(whoami, ret, "while getting refcount rec at " "%"PRIu64" in tree %"PRIu64, p_cpos, tree->rf_blkno); goto out; } /* * Actually ocfs2_get_refcount_rec will fake some refcount record * in case it can't find p_cpos in the refcount tree. So we really * shouldn't meet with a case rec->r_cpos > p_cpos. */ assert(rec.r_cpos <= p_cpos); rec_len = ocfs2_min(p_cpos + clusters, (uint64_t)rec.r_cpos + rec.r_clusters) - p_cpos; if (rec.r_refcount != refcount) { if (prompt(ost, PY, PR_REFCOUNT_COUNT_INVALID, "clusters %"PRIu64 " with len %u have %u refcount " "while there are %u files point to them. " "Correct the refcount value?", p_cpos, rec_len, rec.r_refcount, refcount)) { ret = o2fsck_change_refcount(ost, tree, p_cpos, rec_len, refcount); if (ret) { com_err(whoami, ret, "while updating refcount " "%u at %"PRIu64" len %u in tree " "%"PRIu64, refcount, p_cpos, rec_len, tree->rf_blkno); goto out; } } else { /* * XXX: * Do we need to ask user for adding them to dup? * * Call o2fsck_mark_clusters_allocated will add them * them to duplicate_clusters automatically. */ o2fsck_mark_clusters_allocated(ost, p_cpos, rec_len); ret = o2fsck_refcount_punch_hole(ost, tree, p_cpos, rec_len); if (ret) { com_err(whoami, ret, "while punching " "hole at %"PRIu64"in refcount " "tree %"PRIu64, p_cpos, tree->rf_blkno); goto out; } ret = o2fsck_clear_refcount(ost, tree, p_cpos, rec_len); if (ret) { com_err(whoami, ret, "while clearing refcount for " "cluster %"PRIu64" len %u in %"PRIu64, p_cpos, rec_len, tree->rf_blkno); goto out; } } } /* we have finished checking (p_cpos, clusters). */ if (p_cpos + clusters <= rec.r_cpos + rec.r_clusters) goto out; /* * now we have finished checking current refcount_rec, * p_cpos + clusters > rec.r_cpos + rec.r_clusters, * need to read next refcount_rec. */ clusters += p_cpos; p_cpos = rec.r_cpos + rec.r_clusters; clusters -= p_cpos; goto again; out: return ret; } static errcode_t o2fsck_check_refcount_clusters(o2fsck_state *ost, struct refcount_tree *tree, uint64_t start, uint32_t len, uint32_t refcount) { int val; errcode_t ret = 0; uint64_t p_cend; uint32_t clusters; o2fsck_mark_clusters_allocated(ost, start, len); while (len) { if (ost->ost_duplicate_clusters) { /* * Check whether the clusters can be found in * duplicated cluster list. */ p_cend = start; clusters = len; while (clusters) { ocfs2_bitmap_test( ost->ost_duplicate_clusters, p_cend, &val); if (val) break; clusters--; p_cend++; } } else p_cend = start + len; /* * p_cend points to the end cluster we will check in this loop. * * If there is a cluster which is already setted by other * owner(find in duplicate_clusters), p_end now points to it. * * So we check the refcounted clusters [start, p_cend) and then * punch a hole in refcount tree at p_cend in case. */ clusters = p_cend - start; ret = o2fsck_check_clusters_in_refcount(ost, tree, start, clusters, refcount); if (ret) { com_err(whoami, ret, "while checking " "refcounted clusters"); goto out; } if (len > clusters) { /* * We haven't finished our check and the reason * is that p_cend is setted in dup_clusters, so * punch a hole, clear the refcount flag for * p_cend and continue our check. */ ret = o2fsck_refcount_punch_hole(ost, tree, p_cend, 1); if (ret) { com_err(whoami, ret, "while punching " "hole at %"PRIu64"in refcount " "tree %"PRIu64, p_cend, tree->rf_blkno); goto out; } ret = o2fsck_clear_refcount(ost, tree, p_cend, 1); if (ret) { com_err(whoami, ret, "while clearing refcount for " "cluster %"PRIu64" in %"PRIu64, p_cend, tree->rf_blkno); goto out; } /* start check from next cluster. */ p_cend++; } len = start + len - p_cend; start = p_cend; } out: return ret; } /* * Given a refcount tree, check the refcounted clusters and their refcount. */ static errcode_t o2fsck_check_refcount(o2fsck_state *ost, struct refcount_tree *tree) { errcode_t ret; uint64_t p_cpos = 0; uint32_t clusters = 0, refcount = 0; struct ocfs2_refcount_block *root_rb; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &tree->root_buf); if (ret) { com_err(whoami, ret, "while allocating a block-sized buffer " "for a refcount block"); goto out; } ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &tree->leaf_buf); if (ret) { com_err(whoami, ret, "while allocating a block-sized buffer " "for a refcount block"); goto out; } ret = ocfs2_read_refcount_block(ost->ost_fs, tree->rf_blkno, tree->root_buf); if (ret) { com_err(whoami, ret, "while reading root refcount block at" " %"PRIu64, tree->rf_blkno); goto out; } root_rb = (struct ocfs2_refcount_block *)tree->root_buf; if (tree->files_count != root_rb->rf_count && prompt(ost, PY, PR_REFCOUNT_COUNT, "Refcount tree at %"PRIu64" claims to have %u " "files associated with it, but we only found %u." "Update the count number?", tree->rf_blkno, root_rb->rf_count, tree->files_count)) { root_rb->rf_count = tree->files_count; ret = ocfs2_write_refcount_block(ost->ost_fs, tree->rf_blkno, tree->root_buf); if (ret) { com_err(whoami, ret, "while updati rb_count for tree " "%"PRIu64, tree->rf_blkno); goto out; } } while (get_refcounted_extent(tree, &p_cpos, &clusters, &refcount)) { ret = o2fsck_check_refcount_clusters(ost, tree, p_cpos, clusters, refcount); if (ret) { com_err(whoami, ret, "while checking refcount clusters " "(%"PRIu64", %u, %u) in tree %"PRIu64, p_cpos, clusters, refcount, tree->rf_blkno); goto out; } remove_refcounted_extent(tree, p_cpos, clusters); } /* * Remove all the refcount rec passed p_cpos + clusters from the tree * since there is no corresponding refcounted clusters. */ if (tree->rf_end > p_cpos + clusters) { ret = o2fsck_remove_refcount_range(ost, tree, p_cpos + clusters, tree->rf_end); if (ret) com_err(whoami, ret, "while deleting redundant refcount rec"); } out: if (tree->root_buf) ocfs2_free(&tree->root_buf); if (tree->leaf_buf) ocfs2_free(&tree->leaf_buf); return ret; } errcode_t o2fsck_check_mark_refcounted_clusters(o2fsck_state *ost) { errcode_t ret = 0; struct refcount_tree *tree; struct rb_node *node; struct list_head *p, *next; struct refcount_file *file; if (!ocfs2_refcount_tree(OCFS2_RAW_SB(ost->ost_fs->fs_super))) return 0; while ((node = rb_first(&ost->ost_refcount_trees)) != NULL) { tree = rb_entry(node, struct refcount_tree, ref_node); if (tree->is_valid) { ret = o2fsck_check_refcount(ost, tree); if (ret) goto out; } list_for_each_safe(p, next, &tree->files_list) { file = list_entry(p, struct refcount_file, list); node = rb_first(&file->ref_extents); assert(!node); list_del(&file->list); ocfs2_free(&file); } rb_erase(&tree->ref_node, &ost->ost_refcount_trees); ocfs2_free(&tree); } out: return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/slot_recovery.c0000664000176100017610000001112711170734140015764 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * slot_recovery.c * * Slot recovery handler. * * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #include #include "util.h" #include "slot_recovery.h" #include "pass4.h" static errcode_t ocfs2_clear_truncate_log(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot) { errcode_t ret = 0; struct ocfs2_truncate_log *tl; struct ocfs2_truncate_rec *tr; int i, was_set = 0, cleared = 0; int max = ocfs2_truncate_recs_per_inode(fs->fs_blocksize); uint64_t blkno; if (!(di->i_flags & OCFS2_VALID_FL) || !(di->i_flags & OCFS2_SYSTEM_FL) || !(di->i_flags & OCFS2_DEALLOC_FL)) return OCFS2_ET_INVALID_ARGUMENT; tl = &di->id2.i_dealloc; if (tl->tl_used > max) return OCFS2_ET_INTERNAL_FAILURE; for (i = 0; i < tl->tl_used; i++) { tr = &tl->tl_recs[i]; if (tr->t_start == 0) continue; blkno = ocfs2_clusters_to_blocks(fs, tr->t_start); ret = ocfs2_test_clusters(fs, tr->t_clusters, blkno, 1, &was_set); if (ret) goto bail; if (!was_set) { ret = OCFS2_ET_INVALID_BIT; goto bail; } ret = ocfs2_free_clusters(fs, tr->t_clusters, blkno); if (ret) goto bail; cleared = 1; } tl->tl_used = 0; memset(tl->tl_recs, 0, fs->fs_blocksize - offsetof(struct ocfs2_dinode, id2.i_dealloc.tl_recs)); ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (!ret && cleared) printf("Slot %d's truncate log replayed successfully\n", slot); bail: return ret; } errcode_t o2fsck_replay_truncate_logs(ocfs2_filesys *fs) { return handle_slots_system_file(fs, TRUNCATE_LOG_SYSTEM_INODE, ocfs2_clear_truncate_log); } static errcode_t ocfs2_clear_local_alloc(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot) { errcode_t ret = 0; int bit_off, left, count, start, was_set = 0, cleared = 0; uint64_t la_start_blk; uint64_t blkno; void *bitmap; struct ocfs2_local_alloc *la; if (!(di->i_flags & OCFS2_VALID_FL) || !(di->i_flags & OCFS2_SYSTEM_FL) || !(di->i_flags & OCFS2_BITMAP_FL)) return OCFS2_ET_INVALID_ARGUMENT; if (!di->id1.bitmap1.i_total) goto bail; la = &di->id2.i_lab; if (di->id1.bitmap1.i_used == di->id1.bitmap1.i_total) goto clear_inode; la_start_blk = ocfs2_clusters_to_blocks(fs, la->la_bm_off); bitmap = la->la_bitmap; start = count = bit_off = 0; left = di->id1.bitmap1.i_total; while ((bit_off = ocfs2_find_next_bit_clear(bitmap, left, start)) != -1) { if ((bit_off < left) && (bit_off == start)) { count++; start++; continue; } if (count) { blkno = la_start_blk + ocfs2_clusters_to_blocks(fs, start - count); ret = ocfs2_test_clusters(fs, count, blkno, 1, &was_set); if (ret) goto bail; if (!was_set) { ret = OCFS2_ET_INVALID_BIT; goto bail; } ret = ocfs2_free_clusters(fs, count, blkno); if (ret) goto bail; cleared = 1; } if (bit_off >= left) break; count = 1; start = bit_off + 1; } clear_inode: di->id1.bitmap1.i_total = 0; di->id1.bitmap1.i_used = 0; la->la_bm_off = 0; memset(la->la_bitmap, 0, ocfs2_local_alloc_size(fs->fs_blocksize)); ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (!ret && cleared) printf("Slot %d's local alloc replayed successfully\n", slot); bail: return ret; } errcode_t o2fsck_replay_local_allocs(ocfs2_filesys *fs) { return handle_slots_system_file(fs, LOCAL_ALLOC_SYSTEM_INODE, ocfs2_clear_local_alloc); } static errcode_t ocfs2_clear_link_count(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot) { errcode_t ret = 0; if (!(di->i_flags & OCFS2_VALID_FL) || !(di->i_flags & OCFS2_SYSTEM_FL) || !S_ISDIR(di->i_mode)) return OCFS2_ET_INVALID_ARGUMENT; if (di->i_links_count == 2) goto bail; di->i_links_count = 2; ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (!ret) printf("Slot %d's orphan dir replayed successfully\n", slot); bail: return ret; } errcode_t o2fsck_replay_orphan_dirs(o2fsck_state *ost) { errcode_t ret; ret = replay_orphan_dir(ost, 1); if (ret) return ret; return handle_slots_system_file(ost->ost_fs, ORPHAN_DIR_SYSTEM_INODE, ocfs2_clear_link_count); } ./ocfs2-tools-1.6.4/fsck.ocfs2/strings.c0000644000176100017610000000651411115551035014557 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * A light wrapper around rbtree to store strings with the sole purpose of * detecting dupliates. * */ #include #include #include #include #include "ocfs2/ocfs2.h" #include "fsck.h" #include "strings.h" #include "util.h" struct string_entry { struct rb_node s_node; size_t s_strlen; char s_string[0]; /* null terminated */ }; /* I'm too lazy to share code with _insert right now */ int o2fsck_strings_exists(o2fsck_strings *strings, char *string, size_t strlen) { struct rb_node ** p = &strings->s_root.rb_node; struct rb_node * parent = NULL; struct string_entry *se; int cmp; while (*p) { parent = *p; se = rb_entry(parent, struct string_entry, s_node); /* we don't actually care about lexographical sorting */ cmp = strlen - se->s_strlen; if (cmp == 0) cmp = memcmp(string, se->s_string, strlen); if (cmp < 0) p = &(*p)->rb_left; else if (cmp > 0) p = &(*p)->rb_right; else { return 1; } } return 0; } errcode_t o2fsck_strings_insert(o2fsck_strings *strings, char *string, size_t strlen, int *is_dup) { struct rb_node ** p = &strings->s_root.rb_node; struct rb_node * parent = NULL; struct string_entry *se; size_t bytes; int cmp; if (is_dup) *is_dup = 0; while (*p) { parent = *p; se = rb_entry(parent, struct string_entry, s_node); /* we don't actually care about lexographical sorting */ cmp = strlen - se->s_strlen; if (cmp == 0) cmp = memcmp(string, se->s_string, strlen); #if 0 printf("%.*s %s %.*s\n", (int)strlen, string, cmp < 0 ? "<" : (cmp > 0 ? ">" : "==" ), (int)se->s_strlen, se->s_string); #endif if (cmp < 0) p = &(*p)->rb_left; else if (cmp > 0) p = &(*p)->rb_right; else { if (is_dup) *is_dup = 1; return 0; } } bytes = offsetof(struct string_entry, s_string[strlen]); se = malloc(bytes); if (se == NULL) return OCFS2_ET_NO_MEMORY; strings->s_allocated += bytes; se->s_strlen = strlen; memcpy(se->s_string, string, strlen); rb_link_node(&se->s_node, parent, p); rb_insert_color(&se->s_node, &strings->s_root); return 0; } void o2fsck_strings_init(o2fsck_strings *strings) { strings->s_root = RB_ROOT; } void o2fsck_strings_free(o2fsck_strings *strings) { struct string_entry *se; struct rb_node *node; while((node = rb_first(&strings->s_root)) != NULL) { se = rb_entry(node, struct string_entry, s_node); rb_erase(node, &strings->s_root); free(se); } strings->s_allocated = 0; } size_t o2fsck_strings_bytes_allocated(o2fsck_strings *strings) { return strings->s_allocated; } ./ocfs2-tools-1.6.4/fsck.ocfs2/util.c0000644000176100017610000002015711500500544014037 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * * -- * * Little helpers that are used by all passes. * * XXX * pull more in here.. look in include/pass?.h for incongruities * */ #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "util.h" void o2fsck_write_inode(o2fsck_state *ost, uint64_t blkno, struct ocfs2_dinode *di) { errcode_t ret; const char *whoami = __FUNCTION__; if (blkno != di->i_blkno) { com_err(whoami, OCFS2_ET_INTERNAL_FAILURE, "when asked to " "write an inode with an i_blkno of %"PRIu64" to block " "%"PRIu64, (uint64_t)di->i_blkno, blkno); return; } ret = ocfs2_write_inode(ost->ost_fs, blkno, (char *)di); if (ret) { com_err(whoami, ret, "while writing inode %"PRIu64, (uint64_t)di->i_blkno); ost->ost_saw_error = 1; } } void o2fsck_mark_cluster_allocated(o2fsck_state *ost, uint32_t cluster) { int was_set = 0; errcode_t ret; const char *whoami = __FUNCTION__; o2fsck_bitmap_set(ost->ost_allocated_clusters, cluster, &was_set); if (!was_set) return; if (!ost->ost_duplicate_clusters) { fprintf(stderr, "Duplicate clusters detected. Pass 1b will be run\n"); ret = ocfs2_cluster_bitmap_new(ost->ost_fs, "duplicate clusters", &ost->ost_duplicate_clusters); if (ret) { com_err(whoami, ret, "while allocating duplicate cluster bitmap"); o2fsck_abort(); } } verbosef("Cluster %"PRIu32" is allocated to more than one object\n", cluster); ocfs2_bitmap_set(ost->ost_duplicate_clusters, cluster, NULL); } void o2fsck_mark_clusters_allocated(o2fsck_state *ost, uint32_t cluster, uint32_t num) { while(num--) o2fsck_mark_cluster_allocated(ost, cluster++); } void o2fsck_mark_cluster_unallocated(o2fsck_state *ost, uint32_t cluster) { int was_set; o2fsck_bitmap_clear(ost->ost_allocated_clusters, cluster, &was_set); } errcode_t o2fsck_type_from_dinode(o2fsck_state *ost, uint64_t ino, uint8_t *type) { char *buf = NULL; errcode_t ret; struct ocfs2_dinode *dinode; const char *whoami = __FUNCTION__; *type = 0; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating an inode buffer to " "read and discover the type of inode %"PRIu64, ino); goto out; } ret = ocfs2_read_inode(ost->ost_fs, ino, buf); if (ret) { com_err(whoami, ret, "while reading inode %"PRIu64" to " "discover its file type", ino); goto out; } dinode = (struct ocfs2_dinode *)buf; *type = ocfs2_type_by_mode[(dinode->i_mode & S_IFMT)>>S_SHIFT]; out: if (buf) ocfs2_free(&buf); return ret; } size_t o2fsck_bitcount(unsigned char *bytes, size_t len) { static unsigned char nibble_count[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; size_t count = 0; for (; len--; bytes++) { count += nibble_count[*bytes >> 4]; count += nibble_count[*bytes & 0xf]; } return count; } errcode_t handle_slots_system_file(ocfs2_filesys *fs, int type, errcode_t (*func)(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot)) { errcode_t ret; uint64_t blkno; int slot, max_slots; char *buf = NULL; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; di = (struct ocfs2_dinode *)buf; max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; for (slot = 0; slot < max_slots; slot++) { ret = ocfs2_lookup_system_inode(fs, type, slot, &blkno); if (ret) goto bail; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto bail; if (func) { ret = func(fs, di, slot); if (ret) goto bail; } } bail: if (buf) ocfs2_free(&buf); return ret; } /* Number of blocks available in the I/O cache */ static int cache_blocks; /* * Number of blocks we've currently cached. This is an imperfect guess * designed for pre-caching. Code can keep slurping blocks until * o2fsck_worth_caching() returns 0. */ static int blocks_cached; void o2fsck_init_cache(o2fsck_state *ost, enum o2fsck_cache_hint hint) { errcode_t ret; uint64_t blocks_wanted, av_blocks; int leave_room; ocfs2_filesys *fs = ost->ost_fs; int max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; uint64_t pages_wanted, avpages; switch (hint) { case O2FSCK_CACHE_MODE_FULL: leave_room = 1; blocks_wanted = fs->fs_blocks; break; case O2FSCK_CACHE_MODE_JOURNAL: /* * We need enough blocks for all the journal * data. Let's guess at 256M journals. */ leave_room = 0; blocks_wanted = ocfs2_blocks_in_bytes(fs, max_slots * 1024 * 1024 * 256); break; case O2FSCK_CACHE_MODE_NONE: return; default: assert(0); } verbosef("Want %"PRIu64" blocks for the I/O cache\n", blocks_wanted); /* * leave_room means that we don't want our cache to be taking * all available memory. So we try to get twice as much as we * want; if that works, we know that getting exactly as much as * we want is going to be safe. */ if (leave_room) blocks_wanted <<= 1; if (blocks_wanted > INT_MAX) blocks_wanted = INT_MAX; av_blocks = blocks_wanted; avpages = sysconf(_SC_AVPHYS_PAGES); pages_wanted = blocks_wanted * fs->fs_blocksize / getpagesize(); if (pages_wanted > avpages) av_blocks = avpages * getpagesize() / fs->fs_blocksize; while (blocks_wanted > 0) { io_destroy_cache(fs->fs_io); verbosef("Asking for %"PRIu64" blocks of I/O cache\n", blocks_wanted); if (blocks_wanted > av_blocks) blocks_wanted = av_blocks; ret = io_init_cache(fs->fs_io, blocks_wanted); if (!ret) { /* * We want to pin our cache; there's no point in * having a large cache if half of it is in swap. * However, some callers may not be privileged * enough, so once we get down to a small enough * number (512 blocks), we'll stop caring. */ ret = io_mlock_cache(fs->fs_io); if (ret && (blocks_wanted <= 512)) ret = 0; } if (!ret) { verbosef("Got %"PRIu64" blocks\n", blocks_wanted); /* * We've found an allocation that works. If * we're not leaving room, we're done. But if * we're leaving room, we clear leave_room and go * around again. We expect to succeed there. */ if (!leave_room) { cache_blocks = blocks_wanted; break; } verbosef("Leaving room for other %s\n", "allocations"); leave_room = 0; } blocks_wanted >>= 1; } } int o2fsck_worth_caching(int blocks_to_read) { if ((blocks_to_read + blocks_cached) > cache_blocks) return 0; blocks_cached += blocks_to_read; return 1; } void o2fsck_reset_blocks_cached(void) { blocks_cached = 0; } void __o2fsck_bitmap_set(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval, const char *where) { errcode_t ret; ret = ocfs2_bitmap_set(bitmap, bitno, oldval); if (ret) { com_err(where, ret, "while trying to set bit %"PRIu64, bitno); o2fsck_abort(); } } void __o2fsck_bitmap_clear(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval, const char *where) { errcode_t ret; ret = ocfs2_bitmap_clear(bitmap, bitno, oldval); if (ret) { com_err(where, ret, "while trying to clear bit %"PRIu64, bitno); o2fsck_abort(); } } /* * What if we're somewhere we can't set an error and we need to abort fsck? * We don't want to just exit(1), as we may have some cluster locks, etc. * If we SIGTERM ourselves, our signal handler should do the right thing. */ void o2fsck_abort(void) { fprintf(stderr, "Aborting\n"); kill(getpid(), SIGTERM); } ./ocfs2-tools-1.6.4/fsck.ocfs2/xattr.c0000644000176100017610000004656211453177334014252 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * xattr.c * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #include #include #include "ocfs2/byteorder.h" #include "ocfs2/ocfs2.h" #include "xattr.h" #include "extent.h" #include "fsck.h" #include "problem.h" #include "util.h" static const char *whoami = "xattr.c"; #define IS_LAST_ENTRY(entry) (*(uint32_t *)(entry) == 0) #define HEADER_SIZE (sizeof(struct ocfs2_xattr_header)) #define ENTRY_SIZE (sizeof(struct ocfs2_xattr_entry)) #define MIN_VALUE 4 #define XE_OFFSET(xh, xe) ((char *)(xe) - (char *)(xh)) enum xattr_location { IN_INODE = 0, IN_BLOCK, IN_BUCKET }; /* These must be kept in sync with xattr_location */ static const char *xattr_object[] = { [IN_INODE] = "inode", [IN_BLOCK] = "block", [IN_BUCKET] = "bucket", }; struct xattr_info { enum xattr_location location; uint32_t max_offset; uint64_t blkno; }; /* * This use to describe the used area of xattr in inode, block and bucket. * The used area include all xattr structs, such as header, entry, name+value. */ struct used_area { struct list_head ua_list; /* list of used area */ uint16_t ua_offset; /* the offset of the area */ uint16_t ua_length; /* the length of the area */ struct ocfs2_xattr_entry ua_xe; /* store the valid xattr entry */ uint16_t ua_xe_valid; /* whether it is a valid xattr entry */ }; struct used_map { uint16_t um_size; /* the size of the map */ struct list_head um_areas; /* list of used area */ }; static int check_xattr_count(o2fsck_state *ost, struct ocfs2_dinode *di, struct ocfs2_xattr_header *xh, int *changed, struct xattr_info *xi) { struct ocfs2_xattr_entry *entry = xh->xh_entries; struct ocfs2_xattr_entry *pre_xe = entry; uint16_t det_count = 0; uint16_t max_count = (xi->max_offset - HEADER_SIZE) / (ENTRY_SIZE + MIN_VALUE); while (!IS_LAST_ENTRY(entry)) { /* * xattr entries in bucket had sorted by name_hash, * so this can help us to detect count. */ if (xi->location == IN_BUCKET && entry->xe_name_hash < pre_xe->xe_name_hash) break; if (det_count >= max_count) break; det_count++; pre_xe = entry; entry++; } if (xh->xh_count > det_count) { if (prompt(ost, PY, PR_XATTR_COUNT_INVALID, "Extended attributes in %s #%"PRIu64" claims to" " have %u entries, but fsck believes it is %u," " Fix the entries count?", xattr_object[xi->location], xi->blkno, xh->xh_count, det_count)) { xh->xh_count = det_count; if (!det_count && xi->location == IN_BUCKET) { xh->xh_free_start = OCFS2_XATTR_BUCKET_SIZE; xh->xh_name_value_len = 0; } *changed = 1; } else return -1; } return 0; } static struct used_area *new_used_area(uint16_t off, uint16_t len, struct ocfs2_xattr_entry *xe) { struct used_area *ua = NULL; ua = malloc(sizeof(struct used_area)); if (!ua) return NULL; memset(ua, 0 , sizeof(struct used_area)); ua->ua_offset = off; ua->ua_length = len; if (xe) { memcpy(&ua->ua_xe, xe, ENTRY_SIZE); ua->ua_xe_valid = 1; } return ua; } static errcode_t set_used_area(struct used_map *um, uint16_t off, uint16_t len, struct ocfs2_xattr_entry *xe) { struct used_area *new_area = NULL; if (!um) return OCFS2_ET_INVALID_ARGUMENT; new_area = new_used_area(off, len, xe); if (!new_area) { com_err(whoami, OCFS2_ET_NO_MEMORY, "Unable to allocate" " buffer for extended attribute "); return OCFS2_ET_NO_MEMORY; } INIT_LIST_HEAD(&new_area->ua_list); list_add_tail(&new_area->ua_list, &um->um_areas); return 0; } static void clear_used_area(struct used_map *um, uint16_t off, uint16_t len) { struct used_area *area = NULL; struct list_head *ua, *ua2; if (list_empty(&um->um_areas)) return; list_for_each_safe(ua, ua2, &um->um_areas) { area = list_entry(ua, struct used_area, ua_list); if (off == area->ua_offset && len == area->ua_length) { list_del(ua); free(area); return; } } return; } static int check_area_fits(struct used_map *um, uint16_t off, uint16_t len) { struct used_area *area = NULL; struct list_head *ua, *ua2; if (!um || (off + len) > um->um_size) return -1; if (list_empty(&um->um_areas)) return 0; list_for_each_safe(ua, ua2, &um->um_areas) { area = list_entry(ua, struct used_area, ua_list); if ((off + len) <= area->ua_offset) continue; if ((area->ua_offset + area->ua_length) <= off) continue; return -1; } return 0; } static void free_used_map(struct used_map *um) { struct used_area *area = NULL; struct list_head *ua, *ua2; if (list_empty(&um->um_areas)) return; list_for_each_safe(ua, ua2, &um->um_areas) { area = list_entry(ua, struct used_area, ua_list); list_del(ua); free(area); } return; } static errcode_t check_xattr_entry(o2fsck_state *ost, struct ocfs2_dinode *di, struct ocfs2_xattr_header *xh, int *changed, struct xattr_info *xi) { int i, ret = 0; uint16_t count; struct used_map *umap; count = xh->xh_count; umap = malloc(sizeof(struct used_map)); if (!umap) { com_err(whoami, OCFS2_ET_NO_MEMORY, "Unable to allocate" " buffer for extended attribute "); return OCFS2_ET_NO_MEMORY; } umap->um_size = xi->max_offset; INIT_LIST_HEAD(&umap->um_areas); /* set xattr header as used area */ set_used_area(umap, 0, sizeof(struct ocfs2_xattr_header), NULL); for (i = 0 ; i < xh->xh_count; i++) { struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; uint16_t value_len; uint32_t hash; if (check_area_fits(umap, XE_OFFSET(xh, xe), ENTRY_SIZE)) { if (!prompt(ost, PY, PR_XATTR_ENTRY_INVALID, "Extended attribute entry in %s #%" PRIu64" refers to a used area at %u," " clear this entry?", xattr_object[xi->location], xi->blkno, XE_OFFSET(xh, xe))) { ret = -1; break; } else goto wipe_entry; } /* check and fix name_offset */ if (xe->xe_name_offset >= xi->max_offset) { if (!prompt(ost, PY, PR_XATTR_NAME_OFFSET_INVALID, "Extended attribute entry in %s #%"PRIu64 " refers to an invalid name offset %u," " clear this entry?", xattr_object[xi->location], xi->blkno, xe->xe_name_offset)) { ret = -1; break; } else goto wipe_entry; } /* check type and value size */ if ((ocfs2_xattr_is_local(xe) && xe->xe_value_size > OCFS2_XATTR_INLINE_SIZE) || (!ocfs2_xattr_is_local(xe) && xe->xe_value_size <= OCFS2_XATTR_INLINE_SIZE)) { char *local; if (ocfs2_xattr_is_local(xe)) local = ""; else local = "not "; if (!prompt(ost, PY, PR_XATTR_LOCATION_INVALID, "Extended attribute entry in %s #%"PRIu64 " claims to have value %sin local, but the" " value size is %"PRIu64 ", clear this entry?", xattr_object[xi->location], xi->blkno, local, xe->xe_value_size)) { ret = -1; break; } else goto wipe_entry; } /* mark the entry area as used*/ set_used_area(umap, XE_OFFSET(xh, xe), ENTRY_SIZE, xe); /* get the value's real size in inode, block or bucket */ value_len = ocfs2_xattr_value_real_size(xe->xe_name_len, xe->xe_value_size); if (check_area_fits(umap, xe->xe_name_offset, value_len)) { if (!prompt(ost, PY, PR_XATTR_VALUE_INVALID, "Extended attribute entry in %s #%"PRIu64 " refers to a used area at %u," " clear this entry?", xattr_object[xi->location], xi->blkno, xe->xe_name_offset)) { ret = -1; break; } else { clear_used_area(umap, XE_OFFSET(xh, xe), ENTRY_SIZE); goto wipe_entry; } } /* mark the value area as used */ set_used_area(umap, xe->xe_name_offset, value_len, NULL); /* check and fix name hash */ hash = ocfs2_xattr_name_hash( ost->ost_fs->fs_super->id2.i_super.s_uuid_hash, (void *)xh + xe->xe_name_offset, xe->xe_name_len); if (xe->xe_name_hash != hash && prompt(ost, PY, PR_XATTR_HASH_INVALID, "Extended attribute entry in %s #%"PRIu64 " refers to an invalid name hash %u," " Fix the name hash?", xattr_object[xi->location], xi->blkno, xe->xe_name_hash)) { xe->xe_name_hash = hash; *changed = 1; } continue; wipe_entry: /* * we don't wipe entry at here, just reduce the count, * we will wipe them when we finish the check. */ count -= 1; *changed = 1; } if (*changed && xh->xh_count != count) { struct used_area *area = NULL; struct list_head *ua, *ua2; /* * according to used map, remove bad entries from entry area, * and left the name+value in the object. */ i = 0; list_for_each_safe(ua, ua2, &umap->um_areas) { area = list_entry(ua, struct used_area, ua_list); if (!area->ua_xe_valid) continue; memcpy(&xh->xh_entries[i], &area->ua_xe, ENTRY_SIZE); i++; } xh->xh_count = i; } free_used_map(umap); free(umap); return ret; } static errcode_t check_xattr_value(o2fsck_state *ost, struct ocfs2_dinode *di, struct ocfs2_xattr_header *xh, uint64_t start, int *changed) { int i; struct extent_info ei = {0, }; errcode_t ret = 0; uint64_t owner; ei.chk_rec_func = o2fsck_check_extent_rec; ei.mark_rec_alloc_func = o2fsck_mark_tree_clusters_allocated; ei.para = di; for (i = 0 ; i < xh->xh_count; i++) { int change = 0; struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; if (!ocfs2_xattr_is_local(xe)) { int offset = xe->xe_name_offset + OCFS2_XATTR_SIZE(xe->xe_name_len); struct ocfs2_xattr_value_root *xv = (struct ocfs2_xattr_value_root *) ((void *)xh + offset); struct ocfs2_extent_list *el = &xv->xr_list; owner = start + offset / ost->ost_fs->fs_blocksize; ret = check_el(ost, &ei, owner, el, 1, &change); if (ret) return ret; if (change) *changed = 1; } } return ret; } static errcode_t check_xattr(o2fsck_state *ost, struct ocfs2_dinode *di, struct ocfs2_xattr_header *xh, int *changed, struct xattr_info *xi) { errcode_t ret; uint16_t min_offs, total_len; /* At first we check and fix the total xattr entry count */ if (check_xattr_count(ost, di, xh, changed, xi)) return 0; /* then check and fix the xattr entry */ if (check_xattr_entry(ost, di, xh, changed, xi)) return 0; ret = check_xattr_value(ost, di, xh, xi->blkno, changed); if (ret) return ret; if (xi->location == IN_BUCKET) { /* check and fix xh_free_start */ min_offs = ocfs2_xattr_min_offset(xh, xi->max_offset); if (xh->xh_free_start != min_offs && prompt(ost, PY, PR_XATTR_FREE_START_INVALID, "Extended attribute in %s #%"PRIu64" claims to" " have free space start at %u , but fsck believes" " it is %u, Fix the value of free start?", xattr_object[xi->location], xi->blkno, xh->xh_free_start, min_offs)) { xh->xh_free_start = min_offs; *changed = 1; } /* check and fix xh_name_value_len */ total_len = ocfs2_xattr_name_value_len(xh); if (xh->xh_name_value_len != total_len && prompt(ost, PY, PR_XATTR_VALUE_LEN_INVALID, "Extended attribute in %s #%"PRIu64" claims to have" " the total length %u of all EAs name and value" " in this object, but fsck believes it is %u," " Fix the value of the total length?", xattr_object[xi->location], xi->blkno, xh->xh_name_value_len, total_len)) { xh->xh_name_value_len = total_len; *changed = 1; } } return 0; } static uint16_t detect_xattr_bucket_count(char *bucket, uint32_t max_buckets) { int i; char *bucket_buf = NULL; struct ocfs2_xattr_header *xh; uint16_t max_count, max_offset; max_offset = OCFS2_XATTR_BUCKET_SIZE; max_count = (OCFS2_XATTR_BUCKET_SIZE - HEADER_SIZE) / (ENTRY_SIZE + MIN_VALUE); bucket_buf = bucket; for (i = 0; i < max_buckets; i++) { xh = (struct ocfs2_xattr_header *)bucket_buf; if (xh->xh_count < max_count && xh->xh_free_start > (xh->xh_count * ENTRY_SIZE && xh->xh_free_start <= max_offset && xh->xh_name_value_len <= max_offset - xh->xh_free_start)) { bucket_buf += OCFS2_XATTR_BUCKET_SIZE; continue; } else return i; } return i; } static errcode_t ocfs2_check_xattr_buckets(o2fsck_state *ost, struct ocfs2_dinode *di, uint64_t blkno, uint32_t clusters) { int i; errcode_t ret = 0; char *bucket = NULL; char *bucket_buf = NULL; struct ocfs2_xattr_header *xh; int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(ost->ost_fs); uint32_t bpc = ocfs2_xattr_buckets_per_cluster(ost->ost_fs); uint32_t max_buckets = clusters * bpc; uint32_t max_blocks = max_buckets * blk_per_bucket; uint32_t num_buckets = 0; uint64_t blk = 0; /* malloc space for all buckets */ ret = ocfs2_malloc_blocks(ost->ost_fs->fs_io, max_blocks, &bucket); if (ret) { com_err(whoami, ret, "while allocating room to read" " extended attributes bucket"); goto out; } /* read all buckets for detect (some of them may not be used) */ bucket_buf = bucket; blk = blkno; for (i = 0; i < max_buckets; i++) { ret = ocfs2_read_xattr_bucket(ost->ost_fs, blk, bucket_buf); if (ret) { max_buckets = i; break; } blk += blk_per_bucket; bucket_buf += OCFS2_XATTR_BUCKET_SIZE; } /* * The real bucket num in this series of blocks is stored * in the 1st bucket. */ xh = (struct ocfs2_xattr_header *)bucket; if (xh->xh_num_buckets == 0 || xh->xh_num_buckets > max_buckets) { num_buckets = detect_xattr_bucket_count(bucket, max_buckets); if (prompt(ost, PY, PR_XATTR_BUCKET_COUNT_INVALID, "Extended attribute buckets start at %"PRIu64 " claims to have %u buckets, but fsck believes" " it is %u, Fix the bucket count?", blkno, xh->xh_num_buckets, num_buckets ? num_buckets : 1)) { if (num_buckets == 0) { /* * If buckets count is 0, we need clean * xh_count and set xh_num_buckets to 1. */ xh->xh_count = 0; xh->xh_free_start = OCFS2_XATTR_BUCKET_SIZE; xh->xh_num_buckets = 1; } else xh->xh_num_buckets = num_buckets; /* only update first bucket */ ret = ocfs2_write_xattr_bucket(ost->ost_fs, blkno, bucket); if (ret) { com_err(whoami, ret, "while writing bucket of" " extended attributes "); goto out; } if (num_buckets == 0) goto out; } else goto out; } else num_buckets = xh->xh_num_buckets; bucket_buf = bucket; for (i = 0; i < num_buckets; i++) { int changed = 0; struct xattr_info xi = { .location = IN_BUCKET, .max_offset = OCFS2_XATTR_BUCKET_SIZE, .blkno = blkno, }; xh = (struct ocfs2_xattr_header *)bucket_buf; ret = check_xattr(ost, di, xh, &changed, &xi); if (ret) break; if (changed) { ret = ocfs2_write_xattr_bucket(ost->ost_fs, blkno, bucket_buf); if (ret) { com_err(whoami, ret, "while writing bucket of" " extended attributes "); goto out; } } blkno += blk_per_bucket; bucket_buf += OCFS2_XATTR_BUCKET_SIZE; } out: if (bucket) ocfs2_free(&bucket); return ret; } static errcode_t o2fsck_check_xattr_index_block(o2fsck_state *ost, struct ocfs2_dinode *di, struct ocfs2_xattr_block *xb, int *changed) { struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; errcode_t ret = 0; uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0; uint64_t p_blkno = 0; struct extent_info ei = {0, }; if (!el->l_next_free_rec) return 0; ei.chk_rec_func = o2fsck_check_extent_rec; ei.mark_rec_alloc_func = o2fsck_mark_tree_clusters_allocated; ei.para = di; ret = check_el(ost, &ei, xb->xb_blkno, el, ocfs2_xattr_recs_per_xb(ost->ost_fs->fs_blocksize), changed); if (ret) return ret; /* * We need to write the changed xattr tree first so that the following * ocfs2_xattr_get_rec can get the updated information. */ if (*changed) { ret = ocfs2_write_xattr_block(ost->ost_fs, di->i_xattr_loc, (char *)xb); if (ret) { com_err(whoami, ret, "while writing root block of" " extended attributes "); return ret; } } while (name_hash > 0) { ret = ocfs2_xattr_get_rec(ost->ost_fs, xb, name_hash, &p_blkno, &e_cpos, &num_clusters); if (ret) { com_err(whoami, ret, "while getting bucket record" " of extended attributes "); goto out; } ret = ocfs2_check_xattr_buckets(ost, di, p_blkno, num_clusters); if (ret) { com_err(whoami, ret, "while iterating bucket" " of extended attributes "); goto out; } if (e_cpos == 0) break; name_hash = e_cpos - 1; } out: return ret; } static errcode_t o2fsck_check_xattr_block(o2fsck_state *ost, struct ocfs2_dinode *di, int *i_changed) { errcode_t ret; char *blk = NULL; struct ocfs2_xattr_block *xb = NULL; int b_changed = 0; ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &blk); if (ret) { com_err(whoami, ret, "while allocating room to read block" "of extended attribute "); return ret; } ret = ocfs2_read_xattr_block(ost->ost_fs, di->i_xattr_loc, blk); if (ret) { com_err(whoami, ret, "while reading externel block of" " extended attributes "); goto out; } xb = (struct ocfs2_xattr_block *)blk; if (strcmp((char *)xb->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE)) { if (prompt(ost, PY, PR_XATTR_BLOCK_INVALID, "Extended attributes block %"PRIu64" has bad signature" " %.*s, remove this block?", (uint64_t)di->i_xattr_loc, 7, xb->xb_signature)) { di->i_xattr_loc = 0; *i_changed = 1; } goto out; } if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) { struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header; struct xattr_info xi = { .location = IN_BLOCK, .max_offset = ost->ost_fs->fs_blocksize - offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header), .blkno = di->i_xattr_loc, }; ret = check_xattr(ost, di, xh, &b_changed, &xi); } else ret = o2fsck_check_xattr_index_block(ost, di, xb, &b_changed); if (!ret && b_changed) { ret = ocfs2_write_xattr_block(ost->ost_fs, di->i_xattr_loc, blk); if (ret) com_err(whoami, ret, "while writing externel block of" " extended attributes "); } out: if (blk) ocfs2_free(&blk); return ret; } static errcode_t o2fsck_check_xattr_ibody(o2fsck_state *ost, struct ocfs2_dinode *di, int *i_changed) { struct ocfs2_xattr_header *xh = NULL; struct xattr_info xi = { .location = IN_INODE, .max_offset = di->i_xattr_inline_size, .blkno = di->i_blkno, }; xh = (struct ocfs2_xattr_header *) ((void *)di + ost->ost_fs->fs_blocksize - di->i_xattr_inline_size); return check_xattr(ost, di, xh, i_changed, &xi); } /* * o2fsck_check_xattr * * Check extended attribute in inode block or external block. */ errcode_t o2fsck_check_xattr(o2fsck_state *ost, struct ocfs2_dinode *di) { errcode_t ret = 0; int i_changed = 0; if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL)) return 0; if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) { ret = o2fsck_check_xattr_ibody(ost, di, &i_changed); if (ret) return ret; if (i_changed) { o2fsck_write_inode(ost, di->i_blkno, di); i_changed = 0; } } if (di->i_xattr_loc) ret = o2fsck_check_xattr_block(ost, di, &i_changed); if (!ret && i_changed) o2fsck_write_inode(ost, di->i_blkno, di); return ret; } ./ocfs2-tools-1.6.4/fsck.ocfs2/fsck.ocfs2.8.in0000644000176100017610000001043211500500544015350 00000000000000.TH "fsck.ocfs2" "8" "September 2010" "Version @VERSION@" "OCFS2 Manual Pages" .SH "NAME" fsck.ocfs2 \- Check an \fIOCFS2\fR file system. .SH "SYNOPSIS" \fBfsck.ocfs2\fR [ \fB\-pafFGnuvVy\fR ] [ \fB\-b\fR \fIsuperblock block\fR ] [ \fB\-B\fR \fIblock size\fR ] \fIdevice\fR .SH "DESCRIPTION" .PP \fBfsck.ocfs2\fR is used to check an OCFS2 file system. \fIdevice\fR is the file where the file system is stored (e.g. \fI/dev/sda1\fR). It will almost always be a device file but a regular file will work as well. .SH "OPTIONS" .TP \fB\-a\fR This option does the same thing as the \fB-p\fR option. It is provided for backwards compatibility only: it is suggested that people use the \fB-p\fR option whenever possible. .TP \fB\-b\fR \fIsuperblock block\fR Normally, \fBfsck.ocfs2\fR will read the superblock from the first block of the device. This option specifies an alternate block that the superblock should be read from. (Use \fB\-r\fR instead of this option.) .TP \fB\-B\fR \fIblocksize\fR The \fIblock size\fR, specified in bytes, can range from 512 to 4096. A value of 0, the default, is used to indicate that the blocksize should be automatically detected. .TP \fB\-D\fR Optimize directories in filesystem. This option causes fsck.ocfs2 to coalesce the directory entries in order to improve the filesystem performance. .TP \fB\-f\fR Force checking even if the file system is clean. .TP \fB\-F\fR By default \fBfsck.ocfs2\fR will check with the cluster services to ensure that the volume is not in-use (mounted) on any node in the cluster before proceeding. \fB-F\fR skips this check and should only be used when it can be guaranteed that the volume is not mounted on any node in the cluster. \fBWARNING: If the cluster check is disabled and the volume is mounted on one or more nodes, file system corruption is very likely. If unsure, do not use this option.\fR .TP \fB\-G\fR Usually \fBfsck.ocfs2\fR will silently assume inodes whose generation number does not match the generation number of the super block are unused inodes. This option causes \fBfsck.ocfs2\fR to ask the user if these inodes should in fact be marked unused. .TP \fB\-n\fR Give the 'no' answer to all questions that fsck will ask. This guarantees that the file system will not be modified and the device will be opened read-only. The output of \fBfsck.ocfs2\fR with this option can be redirected to produce a record of a file system's faults. .TP \fB\-p\fR Automatically repair ("preen") the file system. This option will cause \fBfsck.ocfs2\fR to automatically fix any problem that can be safely corrected without human intervention. If there are problems that require intervention, the descriptions will be printed and fsck.ocfs2 will exit with the value 4 logically or'd into the exit code. (See the \fBEXIT CODE\fR section.) This option is normally used by the system's boot scripts. .TP \fB\-r\fR \fIbackup-number\fR \fImkfs.ocfs2\fR makes upto 6 backup copies of the superblock at offsets 1G, 4G, 16G, 64G, 256G and 1T depending on the size of the volume. Use this option to specify the backup, 1 thru 6, to use to recover the superblock. .TP \fB\-y\fR Give the 'yes' answer to all questions that fsck will ask. This will repair all faults that \fBfsck.ocfs2\fR finds but will not give the operator a chance to intervene if \fBfsck.ocfs2\fR decides that it wants to drastically repair the file system. .TP \fB\-v\fR This option causes \fBfsck.ocfs2\fR to produce a very large amount of debugging output. .TP \fB\-V\fR Print version information and exit. .SH EXIT CODE The exit code returned by \fBfsck.ocfs2\fR is the sum of the following conditions: .br \ 0\ \-\ No errors .br \ 1\ \-\ File system errors corrected .br \ 2\ \-\ File system errors corrected, system should .br \ \ \ \ be rebooted .br \ 4\ \-\ File system errors left uncorrected .br \ 8\ \-\ Operational error .br \ 16\ \-\ Usage or syntax error .br \ 32\ \-\ fsck.ocfs2 canceled by user request .br \ 128\ \-\ Shared library error .br .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR debugfs.ocfs2(8) .BR tunefs.ocfs2(8) .BR mounted.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation. This man page entry derives some text, especially the exit code summary, from .BR e2fsck(8) by Theodore Y. Ts'o . .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/fsck.ocfs2/fsck.ocfs2.checks.8.in0000644000176100017610000012702711500500544016620 00000000000000.TH "fsck.ocfs2.checks" "8" "September 2010" "Version @VERSION@" "OCFS2 Manual Pages" .SH "NAME" fsck.ocfs2.checks \- Consistency checks that .BR fsck.ocfs2(8) performs and its means for fixing inconsistencies. .SH "DESCRIPTION" .PP .BR fsck.ocfs2(8) is used to check an OCFS2 file system. It performs many consistency checks and will offer to fix faults that it finds. This man page lists the problems it may find and describes their fixes. The problems are indexed by the error number that .BR fsck.ocfs2(8) emits when it describes the problem and asks if it should be fixed. The prompts are constructed such that answering 'no' results in no changes to the file system. This may result in errors later on that stop .BR fsck.ocfs2(8) from proceeding. .SH "CHECKS" \" escape.c .SS "EB_BLKNO" Extent blocks contain a record of the disk block where they are located. An extent block was found at a block that didn't match its recorded location. Answering yes will update the data structure in the extent block to reflect its real location on disk. .SS "EB_GEN" Extent blocks are created with a generation number to match the generation number of the volume at the time of creation. An extent block was found which contains a generation number that doesn't match. Answering yes implies that the generation number is correct and that the extent block is from a previous file system. The extent block will be ignored and the file that contains it will lose the data it referenced. .SS "EB_GEN_FIX" Extent blocks are created with a generation number to match the generation number of the volume at the time of creation. An extent block was found which contains a generation number that doesn't match. Answering yes implies that the generation number in the extent block is incorrect and that the extent block is valid. The generation number in the block is updated to match the generation number in the volume. .SS "EXTENT_MARKED_UNWRITTEN" An extent record has the UNWRITTEN flag set, but the filesystem feature set does not include unwritten extents. Answering yes clears the UNWRITTEN flag. This is safe to do; as the feature is disabled anyway. .SS "EXTENT_MARKED_REFCOUNTED" An extent record has the REFCOUNTED flag set, but neither the filesystem nor the file has the REFCOUNTED flag set. Answering yes clears the REFCOUNTED flag. .SS "EXTENT_BLKNO_UNALIGNED" The block that marks the start of an extent should always fall on the start of a cluster. An extent was found that starts part-way into a cluster. Answering yes moves the start of the extent back to the start of the addressed cluster. This may add data to the middle of the file that contains this extent. .SS "EXTENT_CLUSTERS_OVERRUN" An extent was found which claims to contain clusters which are beyond the end of the volume. Answering yes clamps the extent to the end of the volume. This may result in a reduced file size for the file that contains the extent, but it couldn't have addressed those final clusters anyway. One can imagine this problem arising if there are problems shrinking a volume. .SS "EXTENT_EB_INVALID" Deep extent trees are built by forming a tree out of extent blocks. An extent tree references an invalid extent block. Answering yes stops the tree from referencing the invalid extent block. This may truncate data from the file which contains the tree. .SS "EXTENT_LIST_DEPTH" Extent lists contain a record of their depth in the tree. An extent list was found whose recorded depth doesn't match the position they have in the tree. Answering yes updates the depth field in the list to match the tree on disk. .SS "EXTENT_LIST_COUNT" The number of entries in an extent list is bounded by either the size of the inode or the size of the block which contains it. An extent list was found which claims to have more entries than would fit in its container. Answering yes updates the count field in the extent list to match the container. Answering no to this question may stop further fixes from being done because the count value can not be trusted. .SS "EXTENT_LIST_FREE" The number of free entries in an extent list must be less than the total number of entries in the list. A list was found which claims to have more free entries than possible entries. Answering yes sets the number of free entries in the list equal to the total possible entries. .SS "EXTENT_BLKNO_RANGE" An extent record was found which references a block which can not be referenced by an extent. The referenced block is either very early in the volume, and thus reserved, or beyond the end of the volume. Answering yes removes this extent record from the tree. This may remove data from the file which owns the tree but any such data was inaccessible. .SS "CHAIN_CPG" The bitmap inode indicates a different clusters per group than the group descriptor. This value is typically static and only modified by tunefs during volume resize and that too only on volumes having only one cluster group. Answering yes updates the clusters per group on the bitmap inode to the corresponding value in the group descriptor. .SS "SUPERBLOCK_CLUSTERS" The super block indicates a different total clusters value than the global bitmap. This is only possible due to a failed volume resize operation. Answering yes updates the total clusters in the super block to the value specified in the global bitmap. .SS "FIXED_CHAIN_CLUSTERS" The global bitmap inode was repaired, resulting in a change to the total cluster count of the filesystem. Answering yes updates the total clusters in the super block to the value specified in the global bitmap. \" pass0.c .SS "GROUP_UNEXPECTED_DESC" The group descriptors that make up the global bitmap chain allocator reside at predictable locations on disk. A group descriptor was found in the global bitmap allocator which isn't at one of these locations and so shouldn't be in the allocator. Answering yes removes this descriptor from the global bitmap allocator. .SS "GROUP_EXPECTED_DESC" The group descriptors that make up the global bitmap chain allocator reside at predictable locations on disk. A group descriptor at one of these locations was not linked into the global bitmap allocator. Answering yes will relink this group into the allocator. .SS "GROUP_GEN" A group descriptor was found with a generation number that doesn't match the generation number of the volume. Answering yes sets the group descriptor's generation equal to the generation number in the volume. .SS "GROUP_PARENT" Group descriptors contain a pointer to the allocator inode which contains the chain they belong to. A group descriptor was found in an allocator inode that doesn't match the descriptor's parent pointer. Answering yes updates the group descriptor's parent pointer to match the inode it resides in. .SS "GROUP_DUPLICATE" Group descriptors contain a pointer to the allocator inode which contains the chain they belong to. A group descriptor was found in two allocator inodes so it may be duplicated. Answering yes removes the group descriptor from current allocator inode. .SS "GROUP_BLKNO" Group descriptors have a field which records their block location on disk. A group descriptor was found at a given location but is recorded as being located somewhere else. Answering yes updates the group descriptor's recorded location to match where it actually is found on disk. .SS "GROUP_CHAIN" Group descriptors are found in a number of different singly-linked chains in an allocator inode. A group descriptor records the chain number that it is linked in. A group descriptor was found whose chain field doesn't match the chain it was found in. Answering yes sets the group descriptor's chain field to match the chain it is found in. .SS "GROUP_FREE_BITS" A group descriptor records the number of bits in its bitmap that are free. A group descriptor was found which claims to have more free bits than are valid in its bitmap. Answering yes decreases the number of recorded free bits so that it equals the total number of bits in the group descriptor's bitmap. .SS "CHAIN_COUNT" The chain list embedded in an inode is limited by the block size and the number of bytes consumed by the rest of the inode. A chain list header was found which claimed that there are more entries in the list then could fit in the inode. Answering yes resets the header's cl_count member to the maximum size allowed by the block size after accounting for the space consumed by the inode. .SS "CHAIN_NEXT_FREE" This is identical to CHAIN_COUNT except that it is testing and fixing the pointer to the next free list entry recorded in the cl_next_free_rec member instead of the total number of entries. .SS "CHAIN_EMPTY" Chain entries need to be packed such that there are no chains without descriptors found before the chain that is marked as free by the chain header. A chain without descriptors was found found before that chain that was marked free. Answering yes will remove the unused chain and shift the remaining chains forward in the list. .SS "CHAIN_I_CLUSTERS" Chain allocator inodes have an i_clusters value that represents the number of clusters used by the allocator. An inode was found whose i_clusters value doesn't match the number of clusters its chains cover. Answering yes updates i_clusters in the inode to reflect what was actually found by walking the chain. .SS "CHAIN_I_SIZE" Chain allocator inodes multiply the number of bytes per cluster by the their i_clusters value and store it in i_size. An inode was found which didn't have the correct value in its i_size. Answering yes updates i_size to be the product of i_clusters and the cluster size. Nothing else uses this value, and previous versions of tools didn't calculate it properly, so don't be too worried if this error appears. .SS "CHAIN_GROUP_BITS" The inode that contains an embedded chain list has fields which record the total number of bits covered by the chain as well as the amount free. These fields didn't match what was found in the chain. Answering yes updates the fields in the inode to reflect what was actually found by walking the chain. .SS "CHAIN_HEAD_LINK_RANGE" The header that starts a chain tried to reference a group descriptor at a block number that couldn't be valid. Answering yes will clear the reference to this invalid block and truncate the chain that it started. .SS "CHAIN_LINK_GEN" A reference was made to a group descriptor whose generation number doesn't match the generation of the volume. Answering yes to this question implies that the group descriptor is invalid and the chain is truncated at the point that it referred to this invalid group descriptor. Answering no to this question considers the group descriptor as valid and its generation may be fixed. .SS "CHAIN_LINK_MAGIC" Chains are built by chain headers and group descriptors which are linked together by block references. A reference was made to a group descriptor at a given block but a valid group descriptor signature wasn't found at that block. Answering yes clears the reference to this invalid block and truncates the chain at the point of the reference. .SS "CHAIN_LINK_RANGE" Chains are built by chain headers and group descriptors which are linked together by block references. A reference a block was found which can't possibly be valid because it was either too small or extended beyond the volume. Answering yes truncates the chain in question by zeroing the invalid block reference. This shortens the chain in question and could result in more fixes later if the part of the chain that couldn't be referenced was valid at some point. .SS "CHAIN_BITS" A chain's header contains members which record the total number of bits in the chain as well as the number of bits that are free. After walking through a chain it was found that the number of bits recorded in its header don't match what was found by totalling up the group descriptors. Answering yes updates the c_total and c_free members of the header to reflect what was found in the group descriptors in the chain. .SS "DISCONTIG_BG_DEPTH" A discontiguous block group has an extent list which records all the clusters allocated to it. Discontiguous block groups only support extent lists with a tree depth of 0. A block group claims to have a tree depth greater than 0. Answering yes will set the tree depth of the extent list to 0. .SS "DISCONTIG_BG_COUNT" A discontiguous block group has an extent list which records all the clusters allocated to it. A block group claims to have more records than can actually fit. Answering yes will set the record count to the maximum possible. .SS "DISCONTIG_BG_REC_RANGE" Block groups set aside clusters to be used for metadata. A discontiguous block group claims to contain clusters beyond the end of the volume. Answering yes will remove the block group. .SS "DISCONTIG_BG_CORRUPT_LEAVES" A discontiguous block group has an extent list which records all the clusters allocated to it. A group has more than one extent claiming to have an impossible number of clusters. Answering yes will remove the block group. .SS "DISCONTIG_BG_CLUSTERS" Extent records in a discontiguous block group were found having more clusters allocated then a block group can have. Answering yes will remove the block group. .SS "DISCONTIG_BG_LESS_CLUSTERS" Extent records in a discontiguous block group were found having less clusters allocated then a block group can have. Answering yes will remove the block group. .SS "DISCONTIG_BG_NEXT_FREE_REC" A discontiguous block group has an extent list which records all the clusters allocated to it. A group was found with fewer filled in extents than it claims to have. The filled in extents describe a complete and correct group. Answering yes will set the used extent count to the number of filled extents. .SS "DISCONTIG_BG_LIST_CORRUPT" A discontiguous block group has an extent list which records all the clusters allocated to it. The group claims to have more extents than is possible, and the existing extents contain errors. Answering yes will remove the block group. .SS "DISCONTIG_BG_REC_CORRUPT" A discontiguous block group has a extent list which records all the clusters allocated to it. A group was found with one extent claiming too many clusters but the sum of the remaining extents are equal to the total clusters a group must have. Answering yes will remove the block group. .SS "DISCONTIG_BG_LEAF_CLUSTERS" A discontiguous block group has a extent list which records all the clusters allocated to it. A group was found with one extent claiming too many clusters, but the remaining extents are correct. Answering yes will set the number of the clusters on the broken extent to the difference between the total clusters a group must have and the sum of the remaining extents. \" pass1.c .SS "INODE_ALLOC_REPAIR" The inode allocator did not accurately reflect the set of inodes that are free and in use in the volume. Answering yes will update the inode allocator bitmaps. Each bit that doesn't match the state of its inode will be inverted. .SS "INODE_SUBALLOC" Each inode records the node whose allocator is responsible for the inode. An inode was found in a given node's allocator but the inode itself claimed to belong to a different node. Answering yes will correct the inode to point to the node's allocator that it belongs to. .SS "LALLOC_SIZE" Each node has a local allocator contained in a block that is used to allocate clusters in batches. A node's local allocator claims to reflect more bytes than are possible for the volume's block size. Answering yes decreases the local allocator's size to reflect the volume's block size. .SS "LALLOC_NZ_USED" A given node's local allocator isn't in use but it claims to have bits in use in its bitmap. Answering yes zeros this used field. .SS "LALLOC_NZ_BM" A given node's local allocator isn't in use but it has a field which records the bitmap as starting at a non-zero cluster offset. Answering yes zeros the bm_off field. .SS "LALLOC_BM_OVERRUN" Each local allocator contains a reference to the first cluster that its bitmap addresses. A given local allocator was found which references a starting cluster that is beyond the end of the volume. Answering yes resets the given local allocator. No allocated data will be lost. .SS "LALLOC_BM_SIZE" The given local allocator claims to cover more bits than are possible for the size in bytes of its bitmap. Answering yes decreases the number of bits the allocator covers to reflect the size in bytes of the bitmap and resets the allocator. No allocated data will be lost. .SS "LALLOC_BM_STRADDLE" The given local allocator claims to cover a region of clusters which extents beyond the end of the volume. Answering yes resets the given local allocator. No allocated data will be lost. .SS "LALLOC_USED_OVERRUN" The given local allocator claims to have more bits in use than it has total bits in its bitmap. Answering yes decreases the number of bits used so that it equals the total number of available bits. .SS "LALLOC_CLEAR" A local allocator inode was found to have problems. This gives the operator a chance to just reset the local allocator inode. Answering yes clears the local allocator. No information is lost but the global bitmap allocator may need to be updated to reflect clusters that were reserved for the local allocator but were free. .SS "DEALLOC_COUNT" The given truncate log inode contains a count that is greater than the value that is possible given the size of the inode. Answering yes resets the count value to the possible maximum. .SS "DEALLOC_USED" The given truncate log inode claims to have more records in use than it is possible to store in the inode. Answering yes resets the record of the number used to the maximum value possible. .SS "TRUNCATE_REC_START_RANGE" A truncate record was found which claims to start at a cluster that is beyond the number of clusters in the volume. Answering yes will clear the truncate record. This may result in previously freed space being marked as allocated. This will be fixed up later as the allocator is updated to match what is used by the file system. .SS "TRUNCATE_REC_WRAP" Clusters are recorded as 32bit values. A truncate record was found which claims to have enough clusters to cause this value to wrap. This could never be the case and is a sure sign of corruption. Answering yes will clear the truncate record. This may result in previously freed space being marked as allocated. This will be fixed up later as the allocator is updated to match what is used by the file system. .SS "TRUNCATE_REC_RANGE" A truncate record was found which claims to reference a region of clusters which partially extends beyond the number of clusters in the volume. Answering yes will clear the truncate record. This may result in previously freed space being marked as allocated. This will be fixed up later as the allocator is updated to match what is used by the file system. .SS "INODE_GEN" Inodes are created with a generation number to match the generation number of the volume at the time of creation. An Inode was found which contains a generation number that doesn't match. Answering yes implies that the generation number is correct and that the inode is from a previous file system. The inode will be recorded as free. .SS "INODE_GEN_FIX" Inodes are created with a generation number to match the generation number of the volume at the time of creation. An inode was found which contains a generation number that doesn't match. Answering yes implies that the generation number in the inode is incorrect and that the inode is valid. The generation number in the inode is updated to match the generation number in the volume. .SS "INODE_BLKNO" Inodes contain a field that must match the block that they reside in. An inode was found at a block that doesn't match the field in the inode. Answering yes updates the field to match the inode's position on disk. .SS "ROOT_NOTDIR" The super block contains a reference to the inode that contains the root directory. This block was found to contain an inode that isn't a directory. Answering yes clears this inode. The operator will be asked to recreate the root directory at a point in the near future. .SS "INODE_NZ_DTIME" Inodes contain a field describing the time at which they were deleted. This can not be set for an inode that is still in use. An inode was found which is in use but which contains a non-zero dtime. Answering yes implies that the inode is still valid and resets its dtime to zero. .SS "LINK_FAST_DATA" The target name for a symbolic link is stored either as file contents for that inode or in the inode structure itself on disk. Only small destination names are stored in the inode structure. The i_blocks field of the inode indicates that the name is stored in the inode when it is zero. An inode was found that has both i_blocks set to zero and file contents. Answering yes clears the inode and so deletes the link. .SS "LINK_NULLTERM" The targets of links on disk must be null terminated. A link was found whose target wasn't null terminated. Answering yes clears the inode and so deletes the link. .SS "LINK_SIZE" The size of a link on disk must match the length of its target string. A link was found whose size does not. Answering yes updates the link's size to reflect the length of its target string. .SS "LINK_BLOCKS" Links can not be sparse. There must be exactly as many blocks allocated as are needed to cover its size. A link was found which doesn't have enough blocks allocated to cover its size. Answering yes clears the link's inode thus deleting the link. .SS "DIR_ZERO" Directories must at least contain a block that has the "." and ".." entries. A directory was found which doesn't contain any blocks. Answering yes to this question clears the directory's inode thus deleting the directory. .SS "INODE_SIZE" Certain inodes record the size of the data they reference in an i_size field. This can be the number of bytes in a file, directory, or symlink target which are stored in data mapped by extents of clusters. This error occurs when the extent lists are walked and the amount of data found does not match what is stored in i_size. Answering yes to this question updates the inode's i_size to match the amount of data referenced by the extent lists. It is vitally important that i_size matches the extent lists and so answering yes is strongly encouraged. .SS "INODE_SPARSE_SIZE" Certain inodes record the size of the data they reference in an i_size field. This can be the number of bytes in a file, directory, or symlink target which are stored in data mapped by extents of clusters. This error occurs when a sparse inode was found that had data allocated past its i_size. Answering yes to this question will update the inode's i_size to cover all of its allocated storage. It is vitally important that i_size matches the extent lists and so answering yes is strongly encouraged. .SS "INODE_INLINE_SIZE" Inodes can only fit a certain amount of inline data. This inode has its data inline but claims an i_size larger than will actually fit. Answering yes to this question updates the inode's i_size to the maximum available inline space. .SS "INODE_CLUSTERS" Inodes contain a record of how many clusters are allocated to them. An inode was found whose recorded number of clusters doesn't match the number of blocks that were found associated with the inode. Answering yes resets the inode's number of clusters to reflect the number of blocks that were associated with the file. .SS "INODE_SPARSE_CLUSTERS" Inodes contain a record of how many clusters are allocated to them. An sparse inode was found whose recorded number of clusters doesn't match the number of blocks that were found associated with the inode. Answering yes resets the inode's number of clusters to reflect the number of blocks that were associated with the file. .SS "INODE_INLINE_CLUSTERS" Inlined inode should not have allocated clusters. An inode who has inline data flag set was found with clusters allocated. Answering yes resets the inode's number of clusters to zero. .SS "LALLOC_REPAIR" An active local allocator did not accurately reflect the set of clusters that are free and in use in its region. Answering yes will update the local allocator bitmap. Each bit that doesn't match the use of its cluster will be inverted. .SS "LALLOC_USED" A local allocator records the number of bits that are used in its bitmap. An allocator was found whose used value doesn't reflect the number of bits that are set in its bitmap. Answering yes sets the used value to match the number of bits set in the allocator's bitmap. .SS "CLUSTER_ALLOC_BIT" A specific cluster's use didn't match the setting of its bit in the cluster allocator. Answering yes will invert the bit in the allocator to match the use of the cluster -- either allocated and in use or free. .SS "REFCOUNT_FLAG_INVALID" Refcount file can only exist in a volume with refcount supported, Fsck has found that a file in a non-refcount volume has refcount flag set. Answering yes remove this flag from the file. .SS "REFCOUNT_LOC_INVALID" Refcount loc can only be valid if the file has refcount flag set. Fsck has found that a file has refcount loc while it does't have refcount flag set. Answering yes reset refcount loc to zero for the file. .SS "RB_BLKNO" refcount blocks contain a record of the disk block where they are located. An refcount block was found at a block that didn't match its recorded location. Answering yes will update the data structure in the refcount block to reflect its real location on disk. .SS "RB_GEN" Refcount blocks are created with a generation number to match the generation number of the volume at the time of creation. An refcount block was found which contains a generation number that doesn't match. Answering yes implies that the generation number is correct and that the refcount block is from a previous file system. The refcount block will be removed and the file that uses it will lose the refcounted information, but it may be regenerated later. .SS "RB_GEN_FIX" Refcount blocks are created with a generation number to match the generation number of the volume at the time of creation. An refcount block was found which contains a generation number that doesn't match. Answering yes implies that the generation number in the refcount block is incorrect and that the refcount block is valid. The generation number in the block is updated to match the generation number in the volume. .SS "RB_PARENT" refcount blocks contain a record of the parent this disk block belongs to. An refcount block was found storing a wrong parent location. Answering yes will update the data structure in the refcount block to reflect its parent's real location on disk. .SS "REFCOUNT_LIST_COUNT" The number of entries in a refcount list is bounded by the size of the block which contains it. An refcount list was found which claims to have more entries than would fit in its container. Answering yes updates the count field in the refcount list to match the container. Answering no to this question may stop further fixes from being done because the count value can not be trusted. .SS "REFCOUNT_LIST_USED" The number of free entries in a refcount list must be less than the total number of entries in the list. A list was found which claims to have more free entries than possible entries. Answering yes sets the number of free entries in the list equal to the total possible entries. .SS "REFCOUNT_CLUSTER_RANGE" A refcount record was found which references a cluster which can not be referenced by a refcount. The referenced cluster is either very early in the volume, and thus reserved, or beyond the end of the volume. Answering yes removes this refcount record from the tree. .SS "REFCOUNT_CLUSTER_COLLISION" A refcount record was found which references a cluster which has a collision with the previous valid refcount record. Answering yes removes this refcount record from the tree. .SS "REFCOUNT_LIST_EMPTY" A refcount list was found which has no refcount record in it. It is normally caused by a corrupted refcount record. Answering yes removes this refcount block from the tree. It will be re-generated in refcounted extent records handler if all the other information is sane. .SS "REFCOUNT_BLOCK_INVALID" Refcount block stores the refcount record for physical clusters of a file. It is found refering an invalid refcount block. Answering yes remove this refcount block. .SS "REFCOUNT_CLUSTERS" Refcount tree contains a record of how many clusters are allocated to them. A tree was found whose recorded number of clusters doesn't match the number of blocks that were found associated with it. Answering yes resets the number of clusters to reflect the real number of clusters that were associated with the tree. .SS "REFCOUNT_ROOT_BLOCK_INVALID" Root refcount block is the root of the refcount record for a file. It is found refering an invalid refcount block. Answering yes remove this refcount block and clear refcount flag from this file. .SS "REFCOUNT_REC_REDUNDANT" Refcount record is used to store the refcount for physical clusters. Some refcount record is found to have no physical clusters corresponding to it. Answering yes remove the refcount record. .SS "REFCOUNT_COUNT_INVALID" Refcount record is used to store the refcount for physical clusters. A record record is found whichs claims the wrong refcount for some physical clusters. Answering yes update the corresponding refcount record. .SS "REFCOUNT_COUNT" Refcount tree contains a record of how many files refering to this tree. A tree was found whose recorded number of files doesn't match the real files refering to the tree. Answering yes resets the number of files to reflect the real number of files that were associated with the tree. \" pass1b.c .SS "DUP_CLUSTERS_SYSFILE_CLONE" A system file inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. System files may be cloned but may not be deleted. Allocation system files may not be cloned or deleted. Answering yes will copy the data of this inode to newly allocated extents. This will break the claim on the overcommitted clusters. .SS "DUP_CLUSTERS_CLONE" An inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. Answering yes will copy the data of this inode to newly allocated extents. This will break the claim on the overcommitted clusters. .SS "DUP_CLUSTERS_DELETE" An inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. Answering yes will remove this inode, thus breaking its claim on the overcommitted clusters. .SS "DUP_CLUSTERS_ADD_REFCOUNT" An inode claims clusters that are also claimed by another inode. ocfs2 does not allow this. Answering yes will try to add a refcount record for all these inodes, so that they will share the cluster. \" pass2.c .SS "DIRENT_DOTTY_DUP" There can be only one instance of both the "." and ".." entries in a directory. A directory entry was found which duplicated one of these entries. Answering yes will remove the duplicate directory entry. .SS "DIRENT_NOT_DOTTY" The first and second directory entries in a directory must be "." and ".." respectively. One of these directory entries was found to not match these rules. Answering yes will force the directory entry to be either "." or "..". This might consume otherwise valid entries and cause some files to appear in lost+found. .SS "DIRENT_DOT_INODE" The inode field of the "." directory entry must refer to the directory inode that contains the given directory block. A "." entry was found which doesn't do so. Answering yes sets the directory entry's inode reference to the parent directory that contains the entry. .SS "DIRENT_DOT_EXCESS" A "." directory entry was found whose lengths exceeds the amount required for the single dot in the name. Answering yes creates another empty directory entry in this excess space. .SS "DIRENT_ZERO" A directory entry was found with a zero length name. Answering yes clears the directory entry so its space can be reused. .SS "DIRENT_NAME_CHARS" Directory entries can not contain either the NULL character (ASCII 0) or the forward slash (ASCII 47). A directory entry was found which contains either. Answering yes will change each instance of these forbidden characters into a period (ASCII 46). .SS "DIRENT_INODE_RANGE" Each directory entry contains a inode field which the entry's name corresponds to. An entry was found which referenced an inode number that is invalid for the current volume. Answering yes clears this entry so its space can be reused. If the entry once corresponded to a real inode and was corrupted this inode may appear in lost+found. .SS "DIRENT_INODE_FREE" Each directory entry contains a inode field which the entry's name corresponds to. An entry was found which referenced an inode number that isn't in use. Answering yes clears this directory entry. .SS "DIRENT_TYPE" Each directory entry contains a field which describes the type of file that the entry refers to. An entry was found whose type doesn't match the inode it is referring to. Answering yes resets the entry's type to match the target inode. .SS "DIR_PARENT_DUP" Each directory can only be pointed to by one directory entry in a parent directory. A directory entry was found which was the second entry to point to a given directory inode. Answering yes clears this entry which was the second to refer to a given directory. This reflects the policy that hard links to directories are not allowed. .SS "DIRENT_DUPLICATE" File names within a directory must be unique. A file name occurred in more than one directory entry in a given directory. Answering yes renames the duplicate entry to a name that doesn't collide with recent entries and is unlikely to collide with future entries in the directory. .SS "DIRENT_LENGTH" There are very few directory entry lengths that are valid. The lengths must be greater than the minimum required to record a single character directory, be rounded to 12 bytes, be within the amount of space remaining in a directory block, and be properly rounded for the size of the name of the directory entry. An entry was found which didn't meet these criteria. Answering yes will try to repair the directory entry. This runs a very good chance of invalidating all the entries in the directory block. Orphaned inodes may appear in lost+found. .SS "DIR_TRAILER_INODE" A directory block trailer is a fake directory entry at the end of the block. The trailer has compatibility fields for when it is viewed as a directory entry. The inode field must be zero. Answering yes will set the inode field to zero. .SS "DIR_TRAILER_NAME_LEN" A directory block trailer is a fake directory entry at the end of the block. The trailer has compatibility fields for when it is viewed as a directory entry. The name length field must be zero. Answering yes will set the name length field to zero. .SS "DIR_TRAILER_REC_LEN" A directory block trailer is a fake directory entry at the end of the block. The trailer has compatibility fields for when it is viewed as a directory entry. The record length field must be equal to the size of the trailer. Answering yes will set the record length field to the size of the trailer. .SS "DIR_TRAILER_BLKNO" A directory block trailer is a fake directory entry at the end of the block. The self-referential block number is incorrect. Answering yes will set the block number to the correct block on disk. .SS "DIR_TRAILER_PARENT_INODE" A directory block trailer is a fake directory entry at the end of the block. It has a pointer to the directory inode it belongs to. This pointer is incorrect. Answering yes will set the parent inode pointer to the inode referencing this directory block. \" pass3.c .SS "ROOT_DIR_MISSING" The super block contains a reference to the inode that serves as the root directory. This reference points to an inode that isn't in use. Answering yes will create a new inode and update the super block to refer to this inode as the root directory. .SS "LOSTFOUND_MISSING" The super block contains a reference to the inode that serves as the lost+found directory. This reference points to an inode that isn't in use. Answering yes will create a new lost+found directory in the root directory. .SS "DIR_NOT_CONNECTED" Every directory in the file system should be reachable by a directory entry in its parent directory. This is verified by walking every directory in the system. A directory inode was found during this walk which doesn't have a parent directory entry. Answering yes moves this directory entry into the lost+found directory and gives it a name based on its inode number. .SS "DIR_DOTDOT" A directory inode's ".." directory entry must refer to the parent directory. A directory was found whose ".." doesn't refer to its parent. Answering yes will read the directory block for the given directory and update its ".." entry to reflect its parent. \" pass4.c .SS "INODE_NOT_CONNECTED" Most all inodes in the system should be referenced by a directory entry. An inode was found which isn't referred to by any directory entry. Answering yes moves this inode into the lost+found directory and gives it a name based on its inode number. .SS "INODE_COUNT" Each inode records the number of directory entries that refer to it. An inode was found whose recorded count doesn't match the number of entries that refer to it. Answering yes sets the inode's count to match the number of referring directory entries. .SS "INODE_ORPHANED" While files are being deleted they are placed in an internal directory. If the machine crashes while this is taking place the files will be left in this directory. Fsck has found an inode in this directory and would like to finish the job of truncating and removing it. Answering yes removes the file data associated with the inode and frees the inode. .SS "RECOVER_BACKUP_SUPERBLOCK" When \fIfsck.ocfs2\fR successfully uses the specified backup superblock, it provides the user with this option to overwrite the existing superblock with that backup. Answering yes will refresh the superblock from the backup. Answering no will only disable the copying of the backup superblock and will not effect the remaining \fIfsck.ocfs2\fR processing. .SS "ORPHAN_DIR_MISSING" While files are being deleted they are placed in an internal directory, named orphan directory. If an orphan directory does not exist, an OCFS2 volume cannot be mounted successfully. Fsck has found the orphan directory is missing and would like to create it for future use. Answering yes creates the orphan directory in the system directory. .SS "JOURNAL_FILE_INVALID" OCFS2 uses JDB for journalling and some journal files exist in the system directory. Fsck has found some journal files that are invalid. Answering yes to this question will regenerate the invalid journal files. .SS "JOURNAL_UNKNOWN_FEATURE" Fsck has found some journal files with unknown features. Other journals on the filesystem have only known features, so this is likely a corruption. If you think your filesystem may be newer than this version of fsck.ocfs2, say N here and grab the latest version of fsck.ocfs2. Answering yes resets the journal features to match other journals. .SS "JOURNAL_MISSING_FEATURE" Fsck has found some journal files have features that are not set on all journal files. All journals on filesystem should have the same set of features. Answering yes will set all journals to the union of set features. .SS "JOURNAL_TOO_SMALL" Fsck has found some journal files are too small. Answering yes extends these journals. .SS "RECOVER_CLUSTER_INFO" The currently active cluster stack is different than the one the filesystem is configured for. Thus, fsck.ocfs2 cannot determine whether the filesystem is mounted on an another node or not. The recommended solution is to exit and run fsck.ocfs2 on this device from a node that has the appropriate active cluster stack. However, you can proceed with the fsck if you are sure that the volume is not in use on any node. Answering yes reconfigures the filesystem to use the current cluster stack. DANGER: YOU MUST BE ABSOLUTELY SURE THAT NO OTHER NODE IS USING THIS FILESYSTEM BEFORE CONTINUING. OTHERWISE, YOU CAN CORRUPT THE FILESYSTEM AND LOSE DATA. .SS "INLINE_DATA_FLAG_INVALID" Inline file can only exist in a volume with inline supported, Fsck has found that a file in a non-inline volume has inline flag set. Answering yes remove this flag from the file. .SS "INLINE_DATA_COUNT_INVALID" For an inline file, there is a limit for id2.id_data.id_count. Fsck has found that this value isn't right. Answering yes change this value to the right number. .SS "XATTR_BLOCK_INVALID" Extended attributes are stored off an extended attribute block referenced by the inode. This inode references an invalid extended attribute block. Answering yes will remove this block. .SS "XATTR_COUNT_INVALID" The count of extended attributes in an inode, block, or bucket does not match the number of entries found by fsck. Answering yes will change this to the correct count. .SS "XATTR_ENTRY_INVALID" An extended attribute entry points to already used space. Answering yes will remove this entry. .SS "XATTR_NAME_OFFSET_INVALID" The name_offset field of an extended attribute entry is not correct. Without a correct name_offset field, the entry cannot be used. Answering yes will remove this entry. .SS "XATTR_VALUE_INVALID" The value region of an extended attribute points to already used space. Answering yes will remove this entry. .SS "XATTR_LOCATION_INVALID" The xe_local field and xe_value_size field of an extended attribute entry does not match. So the entry cannot be used. Answering yes will remove this entry. .SS "XATTR_HASH_INVALID" Extended attributes use a hash of their name for lookup purposes. The name_hash of this extended attribute entry is not correct. Answering yes will change this to the correct hash. .SS "XATTR_FREE_START_INVALID" Extended attributes use free_start to indicate the offset of the free space in inode, block, or bucket. The free_start field of this object is not correct. Answering yes will change this to the correct offset. .SS "XATTR_VALUE_LEN_INVALID" Extended attributes use name_value_len to store the total length of all entry's name and value in inode, block or bucket. the name_value_len filed of this object is not correct. Answering yes will change this to the correct value. .SS "XATTR_BUCKET_COUNT_INVALID" The count of extended attributes bucket pointed by one extent record does not match the number of buckets found by fsck. Answering yes will change this to the correct count. \" pass5.c .SS "QMAGIC_INVALID" The magic number in the header of quota file does not match the proper number. Answering yes will make fsck use values in the quota file header anyway. .SS "QTREE_BLK_INVALID" Block with references to other blocks with quota data is corrupted. Answering yes will make fsck use references in the block. .SS "DQBLK_INVALID" The structure with quota limits was found in a corrupted block. Answering yes will use the values of limits for the user / group. .SS "DUP_DQBLK_INVALID" The structure with quota limits was found in a corrupted block and fsck has already found quota limits for this user / group. Answering yes will use new values of limits for the user / group. .SS "DUP_DQBLK_VALID" The structure with quota limits was found in a correct block but fsck has already found quota limits for this user / group. Answering yes will use new values of limits for the user / group. .SS "IV_DX_TREE" A directory index was found on an inode but that feature is not enabled on the file system. Answering yes will truncate the invalid index. .SS "DX_LOOKUP_FAILED" A directory entry is missing an entry in the directory index. The missing index entry will cause lookups on this name to fail. Answering yes will rebuild the directory index, restoring the missing entry. .SH "SEE ALSO" .BR fsck.ocfs2(8) .SH "AUTHORS" Oracle Corporation. .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/mkfs.ocfs2/0000775000176100017610000000000011515641641013017 500000000000000./ocfs2-tools-1.6.4/mkfs.ocfs2/Makefile0000644000176100017610000000142511115551036014371 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make sbindir = $(root_sbindir) SBIN_PROGRAMS = mkfs.ocfs2 LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2 LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm $(DL_LIBS) LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a INCLUDES = -I$(TOPDIR)/include -I. DEFINES = -DVERSION=\"$(VERSION)\" CFILES = mkfs.c check.c HFILES = mkfs.h OBJS = $(subst .c,.o,$(CFILES)) MANS = mkfs.ocfs2.8 DIST_FILES = $(CFILES) $(HFILES) mkfs.ocfs2.8.in mkfs.ocfs2: $(OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LINK) $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) $(COM_ERR_LIBS) $(UUID_LIBS) include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/mkfs.ocfs2/mkfs.ocfs2.80000664000176100017610000003417511515641632015015 00000000000000.TH "mkfs.ocfs2" "8" "September 2010" "Version 1.6.4" "OCFS2 Manual Pages" .SH "NAME" mkfs.ocfs2 \- Creates an \fIOCFS2\fR file system. .SH "SYNOPSIS" \fBmkfs.ocfs2\fR [\fB\-b\fR \fIblock\-size\fR] [\fB\-C\fR \fIcluster\-size\fR] [\fB\-L\fR \fIvolume\-label\fR] [\fB\-M\fR \fImount-type\fR] [\fB\-N\fR \fInumber\-of\-nodes\fR] [\fB\-J\fR \fIjournal\-options\fR] [\fB\-\-fs\-features=\fR\fI[no]sparse...\fR] [\fB\-\-fs\-feature\-level=\fR\fIfeature\-level\fR] [\fB\-T\fR \fIfilesystem\-type\fR] [\fB\-FqvV\fR] \fIdevice\fR [\fIblocks-count\fI] .SH "DESCRIPTION" .PP \fBmkfs.ocfs2\fR is used to create an \fIOCFS2\fR file system on a \fIdevice\fR, usually a partition on a shared disk. In order to prevent data loss, \fBmkfs.ocfs2\fR will not format an existing \fIOCFS2\fR volume if it detects that it is mounted on another node in the cluster. This tool requires the cluster service to be online. .SH "OPTIONS" .TP \fB\-b, \-\-block\-size\fR \fIblock\-size\fR Valid block size values are 512, 1K, 2K and 4K bytes per block. If omitted, a value will be heuristically determined based on the expected usage of the file system (see the \fB\-T\fR option). A block size of 512 bytes is never recommended. Choose 1K, 2K or 4K. .TP \fB\-C, \-\-cluster\-size\fR \fIcluster\-size\fR Valid cluster size values are 4K, 8K, 16K, 32K, 64K, 128K, 256K, 512K and 1M. If omitted, a value will be heuristically determined based on the expected usage of the file system (see the \fB\-T\fR option). For volumes expected to store large files, like database files, while a cluster size of 128K or more is recommended, one can opt for a smaller size as long as that value is not smaller than the database block size. For others, use 4K. .TP \fB\-F, \-\-force\fR For existing \fIOCFS2\fR volumes, \fImkfs.ocfs2\fR ensures the volume is not mounted on any node in the cluster before formatting. For that to work, \fImkfs.ocfs2\fR expects the cluster service to be online. Specify this option to disable this check. .TP \fB\-J, \-\-journal-options\fR \fIoptions\fR Create the journal using options specified on the command\-line. Journal options are comma separated, and may take an argument using the equals ('=') sign. The following options are supported: .RS 1.2i .TP \fBsize\fR=\fIjournal\-size\fR Create a journal of size \fIjournal\-size\fR. Minimum size is 4M. If omitted, a value is heuristically determined based upon the file system size. .RE .RS 1.2i .TP \fBblock32\fR Use a standard 32bit journal. The journal will be able to access up to 2^32-1 blocks. This is the default. It has been the journal format for \fIOCFS2\fR volumes since the beginning. The journal is compatible with all versions of \fIOCFS2\fR. Prepending \fBno\fR is equivalent to the \fBblock64\fR journal option. .RE .RS 1.2i .TP \fBblock64\fR Use a 64bit journal. The journal will be able to access up to 2^64-1 blocks. This allows large filesystems that can extend to the theoretical limits of \fIOCFS2\fR. It requires a new-enough filesystem driver that uses the new journalled block device, \fBJBD2\fR. Prepending \fBno\fR is equivalent to the \fBblock32\fR journal option. .RE .TP \fB\-L, \-\-label\fR \fIvolume\-label\fR Set the volume label for the file system. This is useful for mounting\-by\-label. Limit the label to under 64 bytes. .TP \fB\-M, \-\-mount\fR \fImount\-type\fR Valid types are \fIlocal\fR and \fIcluster\fR. Local mount allows users to mount the volume without the cluster overhead and works only with \fIOCFS2\fR bundled with Linux kernels 2.6.20 or later. Defaults to \fIcluster\fR. .TP \fB\-N, \-\-node\-slots\fR \fInumber\-of\-node\-slots\fR Valid number ranges from 1 to 255. This number specifies the maximum number of nodes that can concurrently mount the partition. If omitted, the number defaults to 8. The number of slots can be later tuned up or down using \fItunefs.ocfs2\fR. .TP \fB\-T\fR \fIfilesystem\-type\fR Specify how the filesystem is going to be used, so that \fImkfs.ocfs2\fR can chose optimal filesystem parameters for that use. The supported filesystem types are: .RS 1.2i .TP \fBmail\fR Appropriate for file systems that will host lots of small files. .RE .RS 1.2i .TP \fBdatafiles\fR Appropriate for file systems that will host a relatively small number of very large files. .RE .RS 1.2i .TP \fBvmstore\fR Appropriate for file systems that will host Virtual machine images. .RE .TP \fB\-\-fs\-features=\fR\fR\fI[no]sparse...\fR Turn specific file system features on or off. A comma separated list of feature flags can be provided, and \fImkfs.ocfs2\fR will try to create the file system with those features set according to the list. To turn a feature on, include it in the list. To turn a feature off, prepend \fBno\fR to the name. Choices here will override individual features set via the \fB\-\-fs\-feature\-level\fR option. \fBRefer to the section titled feature compatibility before selecting specific features.\fR The following flags are supported: .RS 1.2i .TP \fBbackup-super\fR \fImkfs.ocfs2\fR, by default, makes up to 6 backup copies of the super block at offsets 1G, 4G, 16G, 64G, 256G and 1T depending on the size of the volume. This can be useful in disaster recovery. This feature is fully compatible with all versions of the file system and generally should not be disabled. .RE .RS 1.2i .TP \fBlocal\fR Create the file system as a local mount, so that it can be mounted without a cluster stack. .RE .RS 1.2i .TP \fBsparse\fR Enable support for sparse files. With this, \fIOCFS2\fR can avoid allocating (and zeroing) data to fill holes. Turn this feature on if you can, otherwise extends and some writes might be less performant. .RE .RS 1.2i .TP \fBunwritten\fR Enable unwritten extents support. With this turned on, an application can request that a range of clusters be pre-allocated within a file. \fIOCFS2\fR will mark those extents with a special flag so that expensive data zeroing doesn't have to be performed. Reads and writes to a pre-allocated region act as reads and writes to a hole, except a write will not fail due to lack of data allocation. This feature requires \fBsparse\fR file support to be turned on. .RE .RS 1.2i .TP \fBinline-data\fR Enable inline-data support. If this feature is turned on, \fIOCFS2\fR will store small files and directories inside the inode block. Data is transparently moved out to an extent when it no longer fits inside the inode block. In some cases, this can also make a positive impact on cold-cache directory and file operations. .RE .RS 1.2i .TP \fBextended-slotmap\fR The slot-map is a hidden file on an \fIOCFS2\fR fs which is used to map mounted nodes to system file resources. The extended slot map allows a larger range of possible node numbers, which is useful for userspace cluster stacks. This feature is automatically turned on when needed, thus users have no need to turn this on manually. .RE .RS 1.2i .TP \fBmetaecc\fR Enables metadata checksums. With this enabled, the file system computes and stores the checksums in all metadata blocks. It also computes and stores an error correction code capable of fixing single bit errors. .RE .RS 1.2i .TP \fBrefcount\fR Enables creation of reference counted trees. With this enabled, the file system allows users to create inode-based snapshots and clones known as \fBreflinks\fR. .RE .RS 1.2i .TP \fBxattr\fR Enable extended attributes support. With this enabled, users can attach name:value pairs to objects within the file system. In \fIOCFS2\fR, the names can be upto 255 bytes in length, terminated by the first NUL byte. While it is not required, printable names (ASCII) are recommended. The values can be upto 64KB of arbitrary binary data. Attributes can be attached to all types of inodes: regular files, directories, symbolic links, device nodes, etc. This feature is required for users wanting to use extended security facilities like POSIX ACLs or SELinux. .RE .RS 1.2i .TP \fBusrquota\fR Enable user quota support. With this feature enabled, filesystem will track amount of space and number of inodes (files, directories, symbolic links) each user owns. It is then possible to limit the maximum amount of space or inodes user can have. See a documentation of quota-tools package for more details. .RE .RS 1.2i .TP \fBgrpquota\fR Enable group quota support. With this feature enabled, filesystem will track amount of space and number of inodes (files, directories, symbolic links) each group owns. It is then possible to limit the maximum amount of space or inodes user can have. See a documentation of quota-tools package for more details. .RE .RS 1.2i .TP \fBindexed-dirs\fR Enable directory indexing support. With this feature enabled, the file system creates indexed tree for non-inline directory entries. For large scale directories, directory entry lookup perfromance from the indexed tree is faster then from the legacy directory blocks. .RE .RS 1.2i .TP \fBdiscontig-bg\fR Enables discontiguous block groups. With this feature enabled, the file system is able to grow the inode and the extent allocators even when there is no contiguous free chunk available. It allows the file system to grow the allocators in smaller (discontiguous) chunks. .RE .TP \fB\-\-fs\-feature\-level=\fR\fR\fIfeature\-level\fR Choose from a set of pre-determined file-system features. This option is designed to allow users to conveniently choose a set of file system features which fits their needs. There is no downside to trying a set of features which your module might not support - if it won't mount the new file system simply reformat at a lower level. Feature levels can be fine-tuned via the \fB\-\-fs\-features\fR option. Currently, there are 3 types of feature levels: .RS 1.2i .TP \fBmax-compat\fR Chooses fewer features but ensures that the file system can be mounted from older versions of the \fIOCFS2\fR module. .RE .RS 1.2i .TP \fBdefault\fR The default feature set tries to strike a balance between providing new features and maintaining compatibility with relatively recent versions of \fIOCFS2\fR. It currently enables \fBsparse\fR, \fBunwritten\fR \fBinline-data\fR and \fBxattr\fR. It also enables \fBrefcount\fR for the \fIvmstore\fR volumes. .RE .RS 1.2i .TP \fBmax-features\fR Choose the maximum amount of features available. This will typically provide the best performance from \fIOCFS2\fR at the expense of creating a file system that is only compatible with very recent versions of the \fIOCFS2\fR kernel module. .RE .TP \fB\-\-no-backup-super\fR This option is deprecated, please use \fB--fs-features=nobackup-super\fR instead. .TP \fB\-n, --dry-run\fR Display the heuristically determined values without overwriting the existing file system. .TP \fB\-q, \-\-quiet\fR Quiet mode. .TP \fB\-v, \-\-verbose\fR Verbose mode. .TP \fB\-V, \-\-version\fR Print version and exit. .TP \fIblocks-count\fR Usually \fBmkfs.ocfs2\fR automatically determines the size of the given device and creates a file system that uses all of the available space on the device. This optional argument specifies that the file system should only consume the given number of file system blocks (see \fB-b\fR) on the device. .SH "FEATURE COMPATIBILITY" This section lists the file system features that have been added to the \fIOCFS2\fR file system and the version that it first appeared in. The table below lists the versions of the mainline Linux kernel and that of the file system for the Enterprise Linux Distributions. Users should use this information to enable only those features that are available in the file system that they are using. Before enabling new features, users are advised to review to the section titled \fBfeature values\fR. .TS CENTER ALLBOX; LI LI LI LB C C. Feature Mainline Kernel Version Enterprise OCFS2 Version local Linux 2.6.20 OCFS2 1.2 sparse Linux 2.6.22 OCFS2 1.4 unwritten Linux 2.6.23 OCFS2 1.4 inline-data Linux 2.6.24 OCFS2 1.4 extended-slotmap Linux 2.6.27 OCFS2 1.6 metaecc Linux 2.6.29 OCFS2 1.6 grpquota Linux 2.6.29 OCFS2 1.6 usrquota Linux 2.6.29 OCFS2 1.6 xattr Linux 2.6.29 OCFS2 1.6 indexed-dirs Linux 2.6.30 OCFS2 1.6 refcount Linux 2.6.32 OCFS2 1.6 discontig-bg Linux 2.6.35 OCFS2 1.6 .TE .TS ; L. Users can query the features enabled in the file system as follows: .TE .TS ; L. [root@node1 ~]# tunefs.ocfs2 -Q "Label: %V\\nFeatures: %H %O\\n" /dev/sdg1 Label: apache_files_10 Features: sparse inline-data unwritten .TE .SH "FEATURE VALUES" This section lists the hex values that are associated with the file system features. This information is useful when debugging mount failures that are due to feature incompatibility. When a user attempts to mount an \fBOCFS2\fR volume that has features enabled that are not supported by the running file system software, it will fail with an error like: \fBERROR: couldn't mount because of unsupported optional features (200).\fR By referring to the table below, it becomes apparent that the user attempted to mount a volume with the \fIxattr\fR (extended attributes) feature enabled with a version of the file system software that did not support it. At this stage, the user has the option of either upgrading the file system software, or, disabling that on-disk feature using \fBtunefs.ocfs2\fR. Some features allow the file system to be mounted with an older version of the software provided the mount is read-only. If a user attempts to mount such a volume in a read-write mode, it will fail with an error like: \fBERROR: couldn't mount RDWR because of unsupported optional features (1).\fR This error indicates that the volume had the \fIunwritten\fR RO compat feature enabled. This volume can be mounted by an older file system software only in the read-only mode. In this case, the user has the option of either mounting the volume with the \fIro\fR mount option, or, disabling that on-disk feature using \fBtunefs.ocfs2\fR. .TS CENTER ALLBOX; LI LI LI LB C C. Feature Category Hex value local Incompat 8 sparse Incompat 10 inline-data Incompat 40 extended-slotmap Incompat 100 xattr Incompat 200 indexed-dirs Incompat 400 metaecc Incompat 800 refcount Incompat 1000 discontig-bg Incompat 2000 unwritten RO Compat 1 usrquota RO Compat 2 grpquota RO Compat 4 .TE .SH "SEE ALSO" .BR debugfs.ocfs2(8) .BR fsck.ocfs2(8) .BR tunefs.ocfs2(8) .BR mounted.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/mkfs.ocfs2/mkfs.c0000664000176100017610000021610111506552637014052 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * mkfs.c * * OCFS2 format utility * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #include "mkfs.h" static State *get_state(int argc, char **argv); static int get_number(char *arg, uint64_t *res); static void parse_journal_opts(char *progname, const char *opts, uint64_t *journal_size_in_bytes, int *journal64); static void usage(const char *progname); static void version(const char *progname); static void fill_defaults(State *s); static int get_bits(State *s, int num); static uint64_t get_valid_size(uint64_t num, uint64_t lo, uint64_t hi); static void *do_malloc(State *s, size_t size); static void do_pwrite(State *s, const void *buf, size_t count, uint64_t offset); static AllocBitmap *initialize_bitmap(State *s, uint32_t bits, uint32_t unit_bits, const char *name, SystemFileDiskRecord *bm_record); static int find_clear_bits(void *buf, unsigned int size, uint32_t num_bits, uint32_t offset); static int alloc_bytes_from_bitmap(State *s, uint64_t bytes, AllocBitmap *bitmap, uint64_t *start, uint64_t *num); static int alloc_from_bitmap(State *s, uint64_t num_bits, AllocBitmap *bitmap, uint64_t *start, uint64_t *num); static uint64_t alloc_inode(State *s, uint16_t *suballoc_bit); static DirData *alloc_directory(State *s); static void add_entry_to_directory(State *s, DirData *dir, char *name, uint64_t byte_off, uint8_t type); static uint32_t blocks_needed(State *s); static uint32_t sys_blocks_needed(uint32_t num_slots); static uint32_t system_dir_blocks_needed(State *s); static void check_32bit_blocks(State *s); static void format_superblock(State *s, SystemFileDiskRecord *rec, SystemFileDiskRecord *root_rec, SystemFileDiskRecord *sys_rec); static void format_file(State *s, SystemFileDiskRecord *rec); static void write_metadata(State *s, SystemFileDiskRecord *rec, void *src); static void write_bitmap_data(State *s, AllocBitmap *bitmap); static void write_directory_data(State *s, DirData *dir); static void write_group_data(State *s, AllocGroup *group); static void format_leading_space(State *s); //static void replacement_journal_create(State *s, uint64_t journal_off); static void open_device(State *s); static void close_device(State *s); static int initial_slots_for_volume(uint64_t size); static void generate_uuid(State *s); static void create_generation(State *s); static void init_record(State *s, SystemFileDiskRecord *rec, int type, int mode); static void print_state(State *s); static void clear_both_ends(State *s); static int ocfs2_clusters_per_group(int block_size, int cluster_size_bits); static AllocGroup * initialize_alloc_group(State *s, const char *name, SystemFileDiskRecord *alloc_inode, uint64_t blkno, uint16_t chain, uint16_t cpg, uint16_t bpc); static void index_system_dirs(State *s, ocfs2_filesys *fs); static void create_lost_found_dir(State *s, ocfs2_filesys *fs); static void format_journals(State *s, ocfs2_filesys *fs); static void format_slotmap(State *s, ocfs2_filesys *fs); static int format_backup_super(State *s, ocfs2_filesys *fs); static void mkfs_compute_meta_ecc(State *s, void *data, struct ocfs2_block_check *bc); extern char *optarg; extern int optind, opterr, optopt; static SystemFileInfo system_files[] = { { "bad_blocks", SFI_OTHER, 1, S_IFREG | 0644 }, { "global_inode_alloc", SFI_CHAIN, 1, S_IFREG | 0644 }, { "slot_map", SFI_OTHER, 1, S_IFREG | 0644 }, { "heartbeat", SFI_HEARTBEAT, 1, S_IFREG | 0644 }, { "global_bitmap", SFI_CLUSTER, 1, S_IFREG | 0644 }, { "aquota.user", SFI_QUOTA, 1, S_IFREG | 0644 }, { "aquota.group", SFI_QUOTA, 1, S_IFREG | 0644 }, { "orphan_dir:%04d", SFI_OTHER, 0, S_IFDIR | 0755 }, { "extent_alloc:%04d", SFI_CHAIN, 0, S_IFREG | 0644 }, { "inode_alloc:%04d", SFI_CHAIN, 0, S_IFREG | 0644 }, { "journal:%04d", SFI_JOURNAL, 0, S_IFREG | 0644 }, { "local_alloc:%04d", SFI_LOCAL_ALLOC, 0, S_IFREG | 0644 }, { "truncate_log:%04d", SFI_TRUNCATE_LOG, 0, S_IFREG | 0644 }, { "aquota.user:%04d", SFI_QUOTA, 0, S_IFREG | 0644 }, { "aquota.group:%04d", SFI_QUOTA, 0, S_IFREG | 0644 }, }; struct fs_type_translation { const char *ft_str; enum ocfs2_mkfs_types ft_type; }; static struct fs_type_translation ocfs2_mkfs_types_table[] = { {"datafiles", OCFS2_MKFSTYPE_DATAFILES}, {"mail", OCFS2_MKFSTYPE_MAIL}, {"vmstore", OCFS2_MKFSTYPE_VMSTORE}, {NULL, OCFS2_MKFSTYPE_DEFAULT}, }; enum { BACKUP_SUPER_OPTION = CHAR_MAX + 1, FEATURE_LEVEL, FEATURES_OPTION, CLUSTER_STACK_OPTION, CLUSTER_NAME_OPTION, }; static uint64_t align_bytes_to_clusters_ceil(State *s, uint64_t bytes) { uint64_t ret = bytes + s->cluster_size - 1; if (ret < bytes) /* deal with wrapping */ ret = UINT64_MAX; ret = ret >> s->cluster_size_bits; ret = ret << s->cluster_size_bits; return ret; } static void handle_signal (int sig) { switch (sig) { case SIGTERM: case SIGINT: printf("\nProcess Interrupted.\n"); exit(1); } return ; } /* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock */ static void block_signals (int how) { sigset_t sigs; sigfillset(&sigs); sigdelset(&sigs, SIGTRAP); sigdelset(&sigs, SIGSEGV); sigprocmask(how, &sigs, (sigset_t *) 0); return ; } /* Is this something to skip for heartbeat-only devices */ static int hb_dev_skip(State *s, int system_inode) { int ret = 0; if (s->hb_dev) { switch (system_inode) { case GLOBAL_BITMAP_SYSTEM_INODE: case GLOBAL_INODE_ALLOC_SYSTEM_INODE: case HEARTBEAT_SYSTEM_INODE: break; default: ret = 1; } } return ret; } static void fill_fake_fs(State *s, ocfs2_filesys *fake_fs, void *buf) { memset(buf, 0, s->blocksize); memset(fake_fs, 0, sizeof(ocfs2_filesys)); fake_fs->fs_super = buf; fake_fs->fs_blocksize = s->blocksize; fake_fs->fs_clustersize = s->cluster_size; OCFS2_RAW_SB(fake_fs->fs_super)->s_feature_incompat = s->feature_flags.opt_incompat; OCFS2_RAW_SB(fake_fs->fs_super)->s_feature_ro_compat = s->feature_flags.opt_ro_compat; OCFS2_RAW_SB(fake_fs->fs_super)->s_feature_compat = s->feature_flags.opt_compat; } static void mkfs_init_dir_trailer(State *s, DirData *dir, void *buf) { char super_buf[OCFS2_MAX_BLOCKSIZE]; ocfs2_filesys fake_fs; struct ocfs2_dir_entry *de; struct ocfs2_dinode fake_di = { .i_blkno = dir->record->fe_off >> s->blocksize_bits, }; uint64_t blkno = dir->record->extent_off; /* Find out how far we are in our directory */ blkno += ((char *)buf) - ((char *)dir->buf); blkno >>= s->blocksize_bits; fill_fake_fs(s, &fake_fs, super_buf); if (ocfs2_supports_dir_trailer(&fake_fs)) { de = buf; de->rec_len = ocfs2_dir_trailer_blk_off(&fake_fs); ocfs2_init_dir_trailer(&fake_fs, &fake_di, blkno, buf); } } /* Should we skip this inode because of features enabled / disabled? */ static int feature_skip(State *s, int system_inode) { switch (system_inode) { case USER_QUOTA_SYSTEM_INODE: case LOCAL_USER_QUOTA_SYSTEM_INODE: return !(s->feature_flags.opt_ro_compat & OCFS2_FEATURE_RO_COMPAT_USRQUOTA); case GROUP_QUOTA_SYSTEM_INODE: case LOCAL_GROUP_QUOTA_SYSTEM_INODE: return !(s->feature_flags.opt_ro_compat & OCFS2_FEATURE_RO_COMPAT_GRPQUOTA); default: return 0; } } static inline uint32_t system_dir_bytes_needed(State *s) { int each = OCFS2_DIR_REC_LEN(SYSTEM_FILE_NAME_MAX); return each * sys_blocks_needed(s->initial_slots); } static void format_quota_files(State *s, ocfs2_filesys *fs) { errcode_t ret; ocfs2_quota_hash *usr_hash = NULL, *grp_hash = NULL; /* Write correct data into quota files */ if (!feature_skip(s, USER_QUOTA_SYSTEM_INODE)) { ret = ocfs2_init_fs_quota_info(fs, USRQUOTA); if (ret) { com_err(s->progname, ret, "while looking up global user quota file"); goto error; } fs->qinfo[USRQUOTA].flags = 0; fs->qinfo[USRQUOTA].qi_info.dqi_syncms = OCFS2_DEF_QUOTA_SYNC; fs->qinfo[USRQUOTA].qi_info.dqi_bgrace = OCFS2_DEF_BLOCK_GRACE; fs->qinfo[USRQUOTA].qi_info.dqi_igrace = OCFS2_DEF_INODE_GRACE; ret = ocfs2_new_quota_hash(&usr_hash); if (ret) { com_err(s->progname, ret, "while creating user quota hash."); goto error; } ret = ocfs2_init_global_quota_file(fs, USRQUOTA); if (ret) { com_err(s->progname, ret, "while creating global user " "quota file"); goto error; } ret = ocfs2_init_local_quota_files(fs, USRQUOTA); if (ret) { com_err(s->progname, ret, "while initializing local user quota files"); goto error; } } if (!feature_skip(s, GROUP_QUOTA_SYSTEM_INODE)) { ret = ocfs2_init_fs_quota_info(fs, GRPQUOTA); if (ret) { com_err(s->progname, ret, "while looking up global group quota file"); goto error; } fs->qinfo[GRPQUOTA].flags = 0; fs->qinfo[GRPQUOTA].qi_info.dqi_syncms = OCFS2_DEF_QUOTA_SYNC; fs->qinfo[GRPQUOTA].qi_info.dqi_bgrace = OCFS2_DEF_BLOCK_GRACE; fs->qinfo[GRPQUOTA].qi_info.dqi_igrace = OCFS2_DEF_INODE_GRACE; ret = ocfs2_new_quota_hash(&grp_hash); if (ret) { com_err(s->progname, ret, "while creating group quota hash."); goto error; } ret = ocfs2_init_global_quota_file(fs, GRPQUOTA); if (ret) { com_err(s->progname, ret, "while creating global group " "quota file"); goto error; } ret = ocfs2_init_local_quota_files(fs, GRPQUOTA); if (ret) { com_err(s->progname, ret, "while initializing local group quota files"); goto error; } } ret = ocfs2_compute_quota_usage(fs, usr_hash, grp_hash); if (ret) { com_err(s->progname, ret, "while computing quota usage"); goto error; } if (usr_hash) { ret = ocfs2_write_release_dquots(fs, USRQUOTA, usr_hash); if (ret) { com_err(s->progname, ret, "while writing user quota usage"); goto error; } ret = ocfs2_free_quota_hash(usr_hash); if (ret) { com_err(s->progname, ret, "while releasing user quota hash"); goto error; } } if (grp_hash) { ret = ocfs2_write_release_dquots(fs, GRPQUOTA, grp_hash); if (ret) { com_err(s->progname, ret, "while writing group quota usage"); goto error; } ret = ocfs2_free_quota_hash(grp_hash); if (ret) { com_err(s->progname, ret, "while releasing group quota hash"); goto error; } } return; error: clear_both_ends(s); exit(1); } static void grow_extent_allocator(State *s, ocfs2_filesys *fs) { errcode_t ret; int i; for (i = 0; i < OCFS2_RAW_SB(fs->fs_super)->s_max_slots; i++) { ret = ocfs2_grow_chain_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, i, s->extent_alloc_size_in_clusters); if (ret) { com_err(s->progname, ret, "while growing the extent " "allocator for slot %d by %d clusters", i, s->extent_alloc_size_in_clusters); goto error; } } return; error: clear_both_ends(s); exit(1); } static void finish_normal_format(State *s) { errcode_t ret; int num; ocfs2_filesys *fs; /* These routines use libocfs2 to do their work. */ ret = ocfs2_open(s->device_name, OCFS2_FLAG_RW, 0, 0, &fs); if (ret) { com_err(s->progname, ret, "while opening file system for final " "operations."); clear_both_ends(s); exit(1); } /* 8MB should cover an allocator and some other stuff */ ret = io_init_cache_size(fs->fs_io, 8 * 1024 * 1024); if (ret) com_err(s->progname, ret, "while initializing the I/O cache. Continuing " "without a cache (safe, but slower)"); if (!s->no_backup_super) { if (!s->quiet) printf("Writing backup superblock: "); num = format_backup_super(s, fs); if (!s->quiet) printf("%d block(s)\n", num); } if (!s->quiet) printf("Formatting Journals: "); format_journals(s, fs); if (!s->quiet) printf("done\n"); if (!s->quiet) printf("Growing extent allocator: "); grow_extent_allocator(s, fs); if (!s->quiet) printf("done\n"); if (!s->quiet) printf("Formatting slot map: "); format_slotmap(s, fs); if (!s->quiet) printf("done\n"); if (!s->quiet) printf("Formatting quota files: "); format_quota_files(s, fs); if (!s->quiet) printf("done\n"); if (s->dx_dirs && !s->inline_data) { /* * We want to do this after quota, but before adding * any new entries to directories. */ if (!s->quiet) printf("Indexing system directories: "); index_system_dirs(s, fs); if (!s->quiet) printf("done\n"); } if (!s->quiet) printf("Writing lost+found: "); create_lost_found_dir(s, fs); if (!s->quiet) printf("done\n"); ocfs2_close(fs); } int main(int argc, char **argv) { State *s; SystemFileDiskRecord *record[NUM_SYSTEM_INODES]; SystemFileDiskRecord crap_rec; SystemFileDiskRecord superblock_rec; SystemFileDiskRecord root_dir_rec; SystemFileDiskRecord system_dir_rec; int i, j, num; DirData *orphan_dir[OCFS2_MAX_SLOTS]; DirData *root_dir; DirData *system_dir; uint64_t need; SystemFileDiskRecord *tmprec; char fname[SYSTEM_FILE_NAME_MAX]; setbuf(stdout, NULL); setbuf(stderr, NULL); if (signal(SIGTERM, handle_signal) == SIG_ERR) { fprintf(stderr, "Could not set SIGTERM\n"); exit(1); } if (signal(SIGINT, handle_signal) == SIG_ERR) { fprintf(stderr, "Could not set SIGINT\n"); exit(1); } initialize_ocfs_error_table(); initialize_o2dl_error_table(); initialize_o2cb_error_table(); s = get_state(argc, argv); /* bail if volume already mounted on cluster, etc. */ switch (ocfs2_check_volume(s)) { case -1: return 1; case 1: if (s->prompt) { fprintf(stdout, "Proceed (y/N): "); if (toupper(getchar()) != 'Y') { printf("Aborting operation.\n"); return 1; } } break; case 0: default: break; } open_device(s); fill_defaults(s); generate_uuid (s); create_generation(s); print_state (s); check_32bit_blocks(s); if (s->dry_run) { close_device(s); return 0; } clear_both_ends(s); init_record(s, &superblock_rec, SFI_OTHER, S_IFREG | 0644); init_record(s, &root_dir_rec, SFI_OTHER, S_IFDIR | 0755); init_record(s, &system_dir_rec, SFI_OTHER, S_IFDIR | 0755); for (i = 0; i < NUM_SYSTEM_INODES; i++) { num = system_files[i].global ? 1 : s->initial_slots; record[i] = do_malloc(s, sizeof(SystemFileDiskRecord) * num); for (j = 0; j < num; j++) { init_record(s, &record[i][j], system_files[i].type, system_files[i].mode); } } root_dir = alloc_directory(s); system_dir = alloc_directory(s); for (i = 0; i < s->initial_slots; ++i) orphan_dir[i] = alloc_directory(s); need = (s->volume_size_in_clusters + 7) >> 3; need = ((need + s->cluster_size - 1) >> s->cluster_size_bits) << s->cluster_size_bits; if (!s->quiet) printf("Creating bitmaps: "); tmprec = &(record[GLOBAL_BITMAP_SYSTEM_INODE][0]); tmprec->extent_off = 0; tmprec->extent_len = need; s->global_bm = initialize_bitmap (s, s->volume_size_in_clusters, s->cluster_size_bits, "global bitmap", tmprec); /* * Now allocate the global inode alloc group */ tmprec = &(record[GLOBAL_INODE_ALLOC_SYSTEM_INODE][0]); need = blocks_needed(s); alloc_bytes_from_bitmap(s, need << s->blocksize_bits, s->global_bm, &(crap_rec.extent_off), &(crap_rec.extent_len)); s->system_group = initialize_alloc_group(s, "system inode group", tmprec, crap_rec.extent_off >> s->blocksize_bits, 0, crap_rec.extent_len >> s->cluster_size_bits, s->cluster_size / s->blocksize); tmprec->group = s->system_group; tmprec->chain_off = tmprec->group->gd->bg_blkno << s->blocksize_bits; fsync(s->fd); if (!s->quiet) printf("done\n"); if (!s->quiet) printf("Initializing superblock: "); superblock_rec.fe_off = (uint64_t)OCFS2_SUPER_BLOCK_BLKNO << s->blocksize_bits; if (!s->inline_data) { alloc_from_bitmap(s, 1, s->global_bm, &root_dir_rec.extent_off, &root_dir_rec.extent_len); root_dir_rec.dir_data = NULL; } else root_dir_rec.dir_data = root_dir; root_dir_rec.fe_off = alloc_inode(s, &root_dir_rec.suballoc_bit); root_dir->record = &root_dir_rec; add_entry_to_directory(s, root_dir, ".", root_dir_rec.fe_off, OCFS2_FT_DIR); add_entry_to_directory(s, root_dir, "..", root_dir_rec.fe_off, OCFS2_FT_DIR); need = system_dir_bytes_needed(s); if (!s->inline_data || need > ocfs2_max_inline_data_with_xattr(s->blocksize, NULL)) { need = system_dir_blocks_needed(s) << s->blocksize_bits; alloc_bytes_from_bitmap(s, need, s->global_bm, &system_dir_rec.extent_off, &system_dir_rec.extent_len); system_dir_rec.dir_data = NULL; } else system_dir_rec.dir_data = system_dir; system_dir_rec.fe_off = alloc_inode(s, &system_dir_rec.suballoc_bit); system_dir->record = &system_dir_rec; add_entry_to_directory(s, system_dir, ".", system_dir_rec.fe_off, OCFS2_FT_DIR); add_entry_to_directory(s, system_dir, "..", system_dir_rec.fe_off, OCFS2_FT_DIR); for (i = 0; i < NUM_SYSTEM_INODES; i++) { if (hb_dev_skip(s, i)) continue; if (feature_skip(s, i)) continue; num = (system_files[i].global) ? 1 : s->initial_slots; for (j = 0; j < num; j++) { record[i][j].fe_off = alloc_inode(s, &(record[i][j].suballoc_bit)); sprintf(fname, system_files[i].name, j); add_entry_to_directory(s, system_dir, fname, record[i][j].fe_off, S_ISDIR(system_files[i].mode) ? OCFS2_FT_DIR : OCFS2_FT_REG_FILE); } } /* back when we initialized the alloc group we hadn't allocated * an inode for the global allocator yet */ tmprec = &(record[GLOBAL_INODE_ALLOC_SYSTEM_INODE][0]); s->system_group->gd->bg_parent_dinode = tmprec->fe_off >> s->blocksize_bits; tmprec = &(record[HEARTBEAT_SYSTEM_INODE][0]); need = (O2NM_MAX_NODES + 1) << s->blocksize_bits; alloc_bytes_from_bitmap(s, need, s->global_bm, &tmprec->extent_off, &tmprec->extent_len); tmprec->file_size = need; if (!hb_dev_skip(s, ORPHAN_DIR_SYSTEM_INODE)) { for (i = 0; i < s->initial_slots; ++i) { tmprec = &record[ORPHAN_DIR_SYSTEM_INODE][i]; orphan_dir[i]->record = tmprec; if (!s->inline_data) { alloc_from_bitmap(s, 1, s->global_bm, &tmprec->extent_off, &tmprec->extent_len); tmprec->dir_data = NULL; } else tmprec->dir_data = orphan_dir[i]; add_entry_to_directory(s, orphan_dir[i], ".", tmprec->fe_off, OCFS2_FT_DIR); add_entry_to_directory(s, orphan_dir[i], "..", system_dir_rec.fe_off, OCFS2_FT_DIR); } } fsync(s->fd); if (!s->quiet) printf("done\n"); if (!s->quiet) printf("Writing system files: "); format_file(s, &root_dir_rec); format_file(s, &system_dir_rec); for (i = 0; i < NUM_SYSTEM_INODES; i++) { if (hb_dev_skip(s, i)) continue; if (feature_skip(s, i)) continue; num = system_files[i].global ? 1 : s->initial_slots; for (j = 0; j < num; j++) { tmprec = &(record[i][j]); format_file(s, tmprec); } } /* OHMYGODTHISISTHEWORSTCODEEVER: We write out the bitmap here * *again* because we did a bunch of allocs above after our * initial write-out. */ tmprec = &(record[GLOBAL_BITMAP_SYSTEM_INODE][0]); format_file(s, tmprec); write_bitmap_data(s, s->global_bm); write_group_data(s, s->system_group); write_directory_data(s, root_dir); write_directory_data(s, system_dir); if (!hb_dev_skip(s, ORPHAN_DIR_SYSTEM_INODE)) { for (i = 0; i < s->initial_slots; ++i) write_directory_data(s, orphan_dir[i]); } tmprec = &(record[HEARTBEAT_SYSTEM_INODE][0]); write_metadata(s, tmprec, NULL); fsync(s->fd); if (!s->quiet) printf("done\n"); if (!s->quiet) printf("Writing superblock: "); block_signals(SIG_BLOCK); format_leading_space(s); format_superblock(s, &superblock_rec, &root_dir_rec, &system_dir_rec); block_signals(SIG_UNBLOCK); if (!s->quiet) printf("done\n"); if (!s->hb_dev) finish_normal_format(s); close_device(s); if (!s->quiet) printf("%s successful\n\n", s->progname); return 0; } static void parse_fs_type_opts(char *progname, const char *typestr, enum ocfs2_mkfs_types *fs_type) { int i; *fs_type = OCFS2_MKFSTYPE_DEFAULT; for(i = 0; ocfs2_mkfs_types_table[i].ft_str; i++) { if (strcmp(typestr, ocfs2_mkfs_types_table[i].ft_str) == 0) { *fs_type = ocfs2_mkfs_types_table[i].ft_type; break; } } if (*fs_type == OCFS2_MKFSTYPE_DEFAULT) { com_err(progname, 0, "Bad fs type option specified."); exit(1); } } static State * get_state(int argc, char **argv) { char *progname; unsigned int blocksize = 0; unsigned int cluster_size = 0; char *vol_label = NULL; char *stack_name = NULL; char *cluster_name = NULL; unsigned int initial_slots = 0; char *dummy; State *s; int c; int verbose = 0, quiet = 0, force = 0, xtool = 0, hb_dev = 0; int show_version = 0, dry_run = 0; char *device_name; int ret; uint64_t val; uint64_t journal_size_in_bytes = 0; int journal64 = 0; enum ocfs2_mkfs_types fs_type = OCFS2_MKFSTYPE_DEFAULT; int mount = -1; int no_backup_super = -1; enum ocfs2_feature_levels level = OCFS2_FEATURE_LEVEL_DEFAULT; ocfs2_fs_options feature_flags = {0,0,0}, reverse_flags = {0,0,0}; static struct option long_options[] = { { "block-size", 1, 0, 'b' }, { "cluster-size", 1, 0, 'C' }, { "label", 1, 0, 'L' }, { "node-slots", 1, 0, 'N' }, { "verbose", 0, 0, 'v' }, { "quiet", 0, 0, 'q' }, { "version", 0, 0, 'V' }, { "journal-options", 0, 0, 'J'}, { "heartbeat-device", 0, 0, 'H'}, { "force", 0, 0, 'F'}, { "mount", 1, 0, 'M'}, { "dry-run", 0, 0, 'n' }, { "no-backup-super", 0, 0, BACKUP_SUPER_OPTION }, { "fs-feature-level=", 1, 0, FEATURE_LEVEL }, { "fs-features=", 1, 0, FEATURES_OPTION }, { "cluster-stack=", 1, 0, CLUSTER_STACK_OPTION }, { "cluster-name=", 1, 0, CLUSTER_NAME_OPTION }, { 0, 0, 0, 0} }; if (argc && *argv) progname = basename(argv[0]); else progname = strdup("mkfs.ocfs2"); while (1) { c = getopt_long(argc, argv, "b:C:L:N:J:M:vnqVFHxT:", long_options, NULL); if (c == -1) break; switch (c) { case 'b': ret = get_number(optarg, &val); if (ret || val < OCFS2_MIN_BLOCKSIZE || val > OCFS2_MAX_BLOCKSIZE) { com_err(progname, 0, "Specify a blocksize between %d and %d " "in powers of 2", OCFS2_MIN_BLOCKSIZE, OCFS2_MAX_BLOCKSIZE); exit(1); } blocksize = (unsigned int) get_valid_size(val, OCFS2_MIN_BLOCKSIZE, OCFS2_MAX_BLOCKSIZE); break; case 'C': ret = get_number(optarg, &val); if (ret || val < OCFS2_MIN_CLUSTERSIZE || val > OCFS2_MAX_CLUSTERSIZE) { com_err(progname, 0, "Specify a clustersize between %d and " "%d in powers of 2", OCFS2_MIN_CLUSTERSIZE, OCFS2_MAX_CLUSTERSIZE); exit(1); } cluster_size = (unsigned int) get_valid_size(val, OCFS2_MIN_CLUSTERSIZE, OCFS2_MAX_CLUSTERSIZE); break; case 'L': vol_label = strdup(optarg); if (strlen(vol_label) >= OCFS2_MAX_VOL_LABEL_LEN) { com_err(progname, 0, "Volume label too long: must be less " "than %d characters", OCFS2_MAX_VOL_LABEL_LEN); exit(1); } break; case 'M': if (!strncasecmp(optarg, MOUNT_LOCAL_STR, strlen(MOUNT_LOCAL_STR))) mount = MOUNT_LOCAL; else if (!strncasecmp(optarg, MOUNT_CLUSTER_STR, strlen(MOUNT_CLUSTER_STR))) mount = MOUNT_CLUSTER; else { com_err(progname, 0, "Invalid mount type %s", optarg); exit(1); } break; case 'N': initial_slots = strtoul(optarg, &dummy, 0); if (initial_slots > OCFS2_MAX_SLOTS || *dummy != '\0') { com_err(progname, 0, "Initial node slots must be no more " "than %d", OCFS2_MAX_SLOTS); exit(1); } else if (initial_slots < 1) { com_err(progname, 0, "Initial node slots must be at " "least 1"); exit(1); } break; case 'J': parse_journal_opts(progname, optarg, &journal_size_in_bytes, &journal64); break; case 'H': hb_dev = 1; break; case 'v': verbose = 1; break; case 'n': dry_run = 1; break; case 'q': quiet = 1; break; case 'V': show_version = 1; break; case 'F': force = 1; break; case 'x': xtool = 1; break; case 'T': parse_fs_type_opts(progname, optarg, &fs_type); break; case BACKUP_SUPER_OPTION: no_backup_super = 1; break; case FEATURE_LEVEL: ret = ocfs2_parse_feature_level(optarg, &level); if (ret) { com_err(progname, ret, "when parsing fs-feature-level string"); exit(1); } break; case FEATURES_OPTION: ret = ocfs2_parse_feature(optarg, &feature_flags, &reverse_flags); if (ret) { com_err(progname, ret, "when parsing fs-features string"); exit(1); } break; case CLUSTER_STACK_OPTION: if (!optarg || !strlen(optarg)) { com_err(progname, 0, "Option --cluster-stack requires an argument"); exit(1); } if (strlen(optarg) != OCFS2_STACK_LABEL_LEN) { com_err(progname, 0, "Invalid argument to --cluster-stack"); exit(1); } if (stack_name) free(stack_name); stack_name = strdup(optarg); break; case CLUSTER_NAME_OPTION: if (!optarg || !strlen(optarg)) { com_err(progname, 0, "Option --cluster-name requires an argument"); exit(1); } if (strlen(optarg) > OCFS2_CLUSTER_NAME_LEN) { com_err(progname, 0, "Cluster name is too long"); exit(1); } if (cluster_name) free(cluster_name); cluster_name = strdup(optarg); break; default: usage(progname); break; } } if ((optind == argc) && !show_version) usage(progname); srand48(time(NULL)); device_name = argv[optind]; optind++; s = malloc(sizeof(State)); memset(s, 0, sizeof(State)); if (optind < argc) { s->specified_size_in_blocks = strtoull(argv[optind], &dummy, 0); if ((*dummy)) { com_err(progname, 0, "Block count bad - %s", argv[optind]); exit(1); } optind++; } if (optind < argc) usage(progname); if (!quiet || show_version) version(progname); if (show_version) exit(0); s->progname = progname; s->verbose = verbose; s->quiet = quiet; s->force = force; s->dry_run = dry_run; s->prompt = xtool ? 0 : 1; s->blocksize = blocksize; s->cluster_size = cluster_size; s->vol_label = vol_label; s->initial_slots = initial_slots; s->device_name = strdup(device_name); s->fd = -1; s->format_time = time(NULL); s->journal_size_in_bytes = journal_size_in_bytes; s->journal64 = journal64; s->hb_dev = hb_dev; s->fs_type = fs_type; ret = ocfs2_merge_feature_flags_with_level(&s->feature_flags, fs_type, level, &feature_flags, &reverse_flags); if (ret) { com_err(s->progname, ret, "while reconciling specified features with chosen " "defaults"); exit(1); } if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT) s->mount = MOUNT_LOCAL; else s->mount = MOUNT_CLUSTER; if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA) s->inline_data = 1; else s->inline_data = 0; if (s->feature_flags.opt_compat & OCFS2_FEATURE_COMPAT_BACKUP_SB) s->no_backup_super = 0; else s->no_backup_super = 1; if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS) s->dx_dirs = 1; else s->dx_dirs = 0; /* Here if the user set these flags explicitly, we will use them and * discard the setting in the features set. */ if (mount != -1) s->mount = mount; if ((stack_name || cluster_name) && (s->mount == MOUNT_LOCAL)) { com_err(progname, 0, "Local mount is incompatible with specifying a cluster stack"); exit(1); } if (stack_name) s->cluster_stack = stack_name; if (cluster_name) s->cluster_name = cluster_name; if (no_backup_super != -1) s->no_backup_super = no_backup_super; return s; } static int get_number(char *arg, uint64_t *res) { char *ptr = NULL; uint64_t num; num = strtoull(arg, &ptr, 0); if ((ptr == arg) || (num == UINT64_MAX)) return(-EINVAL); switch (*ptr) { case '\0': break; case 'g': case 'G': num *= 1024; /* FALL THROUGH */ case 'm': case 'M': num *= 1024; /* FALL THROUGH */ case 'k': case 'K': num *= 1024; /* FALL THROUGH */ case 'b': case 'B': break; default: return -EINVAL; } *res = num; return 0; } /* derived from e2fsprogs */ static void parse_journal_opts(char *progname, const char *opts, uint64_t *journal_size_in_bytes, int *journal64) { char *options, *token, *next, *p, *arg; int ret, journal_usage = 0; uint64_t val; int invert; options = strdup(opts); for (token = options; token && *token; token = next) { p = strchr(token, ','); next = NULL; invert = 0; if (p) { *p = '\0'; next = p + 1; } arg = strstr(token, "no"); if (arg == token) { invert = 1; token += strlen("no"); } arg = strchr(token, '='); if (arg) { *arg = '\0'; arg++; } if (strcmp(token, "size") == 0) { if (!arg || invert) { journal_usage++; continue; } ret = get_number(arg, &val); if (ret || val < OCFS2_MIN_JOURNAL_SIZE) { com_err(progname, 0, "Invalid journal size: %s\nSize must " "be greater than %d bytes", arg, OCFS2_MIN_JOURNAL_SIZE); exit(1); } *journal_size_in_bytes = val; } else if (strcmp(token, "block32") == 0) { if (arg) { journal_usage++; continue; } *journal64 = invert; } else if (strcmp(token, "block64") == 0) { if (arg) { journal_usage++; continue; } *journal64 = !invert; } else journal_usage++; } if (journal_usage) { com_err(progname, 0, "Bad journal options specified. Valid journal " "options are:\n" "\tsize=\n" "\t[no]block32\n" "\t[no]block64\n"); exit(1); } free(options); } static void usage(const char *progname) { fprintf(stderr, "usage: %s [-b block-size] [-C cluster-size] " "[-J journal-options]\n\t\t[-L volume-label] [-M mount-type] " "[-N number-of-node-slots]\n\t\t[-T filesystem-type] [-HFqvV] " "\n\t\t[--fs-feature-level=[default|max-compat|max-features]] " "\n\t\t[--fs-features=[[no]sparse,...]]" "[--no-backup-super] device [blocks-count]\n", progname); exit(0); } static void version(const char *progname) { fprintf(stderr, "%s %s\n", progname, VERSION); } static unsigned int journal_size_default(State *s) { unsigned int j_blocks; if (s->volume_size_in_blocks < 32768) j_blocks = OCFS2_MIN_JOURNAL_SIZE / s->blocksize; else if (s->volume_size_in_blocks < 262144) j_blocks = 4096; else { /* Each journal gets ~.625% of the blocks in the file * system, with a min of 16384 and a max of 65536 */ j_blocks = s->volume_size_in_blocks / 160; if (j_blocks < 16384) j_blocks = 16384; else if (j_blocks > 65536) j_blocks = 65536; } return j_blocks; } static unsigned int journal_size_datafiles(void) { return 8192; } static unsigned int journal_size_mail(State *s) { if (s->volume_size_in_blocks < 262144) return 16384; else if (s->volume_size_in_blocks < 524288) return 32768; return 65536; } static unsigned int journal_size_vmstore(State *s) { if (s->volume_size_in_blocks < 262144) return 8192; else if (s->volume_size_in_blocks < 524288) return 16384; return 32768; } /* stolen from e2fsprogs, modified to fit ocfs2 patterns */ static uint64_t figure_journal_size(uint64_t size, State *s) { unsigned int j_blocks; if (s->hb_dev) return 0; if (s->volume_size_in_blocks < 2048) { fprintf(stderr, "Filesystem too small for a journal\n"); exit(1); } if (size > 0) { j_blocks = size >> s->blocksize_bits; /* mke2fs knows about free blocks at this point, but * we don't so lets just take a wild guess as to what * the fs overhead we're looking at will be. */ if ((j_blocks * s->initial_slots + 1024) > s->volume_size_in_blocks) { fprintf(stderr, "Journal size too big for filesystem.\n"); exit(1); } return align_bytes_to_clusters_ceil(s, size); } switch (s->fs_type) { case OCFS2_MKFSTYPE_DATAFILES: j_blocks = journal_size_datafiles(); break; case OCFS2_MKFSTYPE_MAIL: j_blocks = journal_size_mail(s); break; case OCFS2_MKFSTYPE_VMSTORE: j_blocks = journal_size_vmstore(s); break; default: j_blocks = journal_size_default(s); break; } return align_bytes_to_clusters_ceil(s, j_blocks << s->blocksize_bits); } static uint32_t cluster_size_default(State *s) { uint32_t cluster_size, cluster_size_bits; uint64_t volume_size; for (cluster_size = OCFS2_MIN_CLUSTERSIZE; cluster_size < OCFS2_MAX_CLUSTERSIZE; cluster_size <<= 1) { cluster_size_bits = get_bits(s, cluster_size); volume_size = s->volume_size_in_bytes >> cluster_size_bits; if (volume_size <= CLUSTERS_MAX) break; } return cluster_size; } static uint32_t cluster_size_datafiles(State *s) { uint32_t cluster_size; uint64_t volume_gigs = s->volume_size_in_bytes / (1024 * 1024 * 1024); if (volume_gigs < 2) { com_err(s->progname, 0, "Selected file system type requires a device of at " "least 2 gigabytes\n"); exit(1); } if (volume_gigs < 64) cluster_size = 128; else if (volume_gigs < 96) cluster_size = 256; else if (volume_gigs < 128) cluster_size = 512; else cluster_size = 1024; return cluster_size * 1024; } static uint32_t figure_extent_alloc_size(State *s) { uint32_t cpg; int numgroups; uint64_t unitsize, totalsize; double curr_percent, target_percent; if (!s->initial_slots) return 0; switch (s->fs_type) { case OCFS2_MKFSTYPE_DATAFILES: case OCFS2_MKFSTYPE_VMSTORE: target_percent = 0.3; break; case OCFS2_MKFSTYPE_MAIL: default: target_percent = 0.1; break; } cpg = ocfs2_clusters_per_group(s->blocksize, s->cluster_size_bits); /* size of the allocator across all slots with one group */ unitsize = cpg * s->cluster_size * s->initial_slots; totalsize = unitsize; for (numgroups = 1; ; ++numgroups) { curr_percent = (double)totalsize * 100 / s->volume_size_in_bytes; if (curr_percent >= target_percent) break; totalsize += unitsize; } if (curr_percent > MAX_EXTALLOC_RESERVE_PERCENT) --numgroups; assert(numgroups >= 0); return cpg * numgroups; } static void fill_defaults(State *s) { size_t pagesize; errcode_t err; uint32_t blocksize; int sectsize; uint64_t ret; struct ocfs2_cluster_group_sizes cgs; uint64_t tmp; pagesize = getpagesize(); s->pagesize_bits = get_bits(s, pagesize); err = ocfs2_get_device_sectsize(s->device_name, §size); if (err) { if (err == OCFS2_ET_CANNOT_DETERMINE_SECTOR_SIZE) sectsize = 0; else { com_err(s->progname, err, "while getting hardware sector size of " "device %s", s->device_name); exit(1); } } if (!sectsize) sectsize = OCFS2_MIN_BLOCKSIZE; /* Heartbeat devices use the minimum size, unless specified */ if (!s->blocksize && s->hb_dev) s->blocksize = sectsize; if (s->blocksize) blocksize = s->blocksize; else blocksize = OCFS2_MAX_BLOCKSIZE; if (blocksize < sectsize) { com_err(s->progname, 0, "the block device %s has a hardware sector size (%d) " "that is larger than the selected block size (%u)", s->device_name, sectsize, blocksize); exit(1); } if (!s->volume_size_in_blocks) { err = ocfs2_get_device_size(s->device_name, blocksize, &ret); if (err) { com_err(s->progname, err, "while getting size of device %s", s->device_name); exit(1); } if (s->hb_dev) { uint64_t dev_size = 0; if ((ret * blocksize) > (2 * 1024 * 1024)) { fprintf(stderr, "%s: Warning: Volume larger than required for a heartbeat device\n", s->progname); } /* Blocks for system dir, root dir, * global allocator*/ dev_size = 4; /* Blocks for hb region */ dev_size += OCFS2_MAX_SLOTS; /* Slop for superblock + cluster bitmap */ dev_size += 10; /* Convert to bytes */ dev_size *= blocksize; /* Convert to megabytes */ dev_size = (dev_size + (1024 * 1024) - 1) >> ONE_MB_SHIFT; dev_size <<= ONE_MB_SHIFT; dev_size /= blocksize; if (ret > dev_size) ret = dev_size; } s->volume_size_in_blocks = ret; if (s->specified_size_in_blocks) { if (s->specified_size_in_blocks > s->volume_size_in_blocks) { com_err(s->progname, 0, "%"PRIu64" blocks were specified and " "this is greater than the %"PRIu64" " "blocks that make up %s.\n", s->specified_size_in_blocks, s->volume_size_in_blocks, s->device_name); exit(1); } s->volume_size_in_blocks = s->specified_size_in_blocks; } } s->volume_size_in_bytes = s->volume_size_in_blocks * blocksize; if (!s->blocksize) { if (s->volume_size_in_bytes <= 1024 * 1024 * 3) { s->blocksize = OCFS2_MIN_BLOCKSIZE; } else { int shift = 30; s->blocksize = OCFS2_MAX_BLOCKSIZE; while (s->blocksize > 1024) { if (s->volume_size_in_bytes >= 1U << shift) break; s->blocksize >>= 1; shift--; } } if (!s->specified_size_in_blocks) { err = ocfs2_get_device_size(s->device_name, s->blocksize, &ret); s->volume_size_in_blocks = ret; } else s->volume_size_in_blocks = s->specified_size_in_blocks; s->volume_size_in_bytes = s->volume_size_in_blocks * s->blocksize; } s->blocksize_bits = get_bits(s, s->blocksize); if (!s->cluster_size) { switch (s->fs_type) { case OCFS2_MKFSTYPE_DATAFILES: case OCFS2_MKFSTYPE_VMSTORE: s->cluster_size = cluster_size_datafiles(s); break; default: s->cluster_size = cluster_size_default(s); break; } } s->cluster_size_bits = get_bits(s, s->cluster_size); /* volume size needs to be cluster aligned */ s->volume_size_in_clusters = s->volume_size_in_bytes >> s->cluster_size_bits; tmp = (uint64_t)s->volume_size_in_clusters; s->volume_size_in_bytes = tmp << s->cluster_size_bits; s->volume_size_in_blocks = s->volume_size_in_bytes >> s->blocksize_bits; s->reserved_tail_size = 0; ocfs2_calc_cluster_groups(s->volume_size_in_clusters, s->blocksize, &cgs); s->global_cpg = cgs.cgs_cpg; s->nr_cluster_groups = cgs.cgs_cluster_groups; s->tail_group_bits = cgs.cgs_tail_group_bits; #if 0 printf("volume_size_in_clusters = %u\n", s->volume_size_in_clusters); printf("global_cpg = %u\n", s->global_cpg); printf("nr_cluster_groups = %u\n", s->nr_cluster_groups); printf("tail_group_bits = %u\n", s->tail_group_bits); #endif if (s->hb_dev) s->initial_slots = 0; if (!s->hb_dev && !s->initial_slots) { if (s->mount == MOUNT_LOCAL) s->initial_slots = 1; else s->initial_slots = initial_slots_for_volume(s->volume_size_in_bytes); } if (!s->vol_label) { s->vol_label = strdup(""); } s->journal_size_in_bytes = figure_journal_size(s->journal_size_in_bytes, s); s->extent_alloc_size_in_clusters = figure_extent_alloc_size(s); } static int get_bits(State *s, int num) { int i, bits = 0; for (i = 32; i >= 0; i--) { if (num == (1U << i)) bits = i; } if (bits == 0) { com_err(s->progname, 0, "Could not get bits for number %d", num); exit(1); } return bits; } static uint64_t get_valid_size(uint64_t num, uint64_t lo, uint64_t hi) { uint64_t tmp = lo; for ( ; lo <= hi; lo <<= 1) { if (lo == num) return num; if (lo < num) tmp = lo; else break; } return tmp; } static void * do_malloc(State *s, size_t size) { void *buf; int ret; ret = posix_memalign(&buf, OCFS2_MAX_BLOCKSIZE, size); if (ret != 0) { com_err(s->progname, 0, "Could not allocate %lu bytes of memory", (unsigned long)size); exit(1); } return buf; } static void do_pwrite(State *s, const void *buf, size_t count, uint64_t offset) { ssize_t ret; ret = pwrite64(s->fd, buf, count, offset); if (ret == -1) { com_err(s->progname, 0, "Could not write: %s", strerror(errno)); exit(1); } } static AllocGroup * initialize_alloc_group(State *s, const char *name, SystemFileDiskRecord *alloc_inode, uint64_t blkno, uint16_t chain, uint16_t cpg, uint16_t bpc) { AllocGroup *group; group = do_malloc(s, sizeof(AllocGroup)); memset(group, 0, sizeof(AllocGroup)); group->gd = do_malloc(s, s->blocksize); memset(group->gd, 0, s->blocksize); strcpy((char *)group->gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE); group->gd->bg_generation = s->vol_generation; group->gd->bg_size = (uint32_t)ocfs2_group_bitmap_size(s->blocksize, 0, 0); group->gd->bg_bits = cpg * bpc; group->gd->bg_chain = chain; group->gd->bg_parent_dinode = alloc_inode->fe_off >> s->blocksize_bits; group->gd->bg_blkno = blkno; /* First bit set to account for the descriptor block */ ocfs2_set_bit(0, group->gd->bg_bitmap); group->gd->bg_free_bits_count = group->gd->bg_bits - 1; alloc_inode->bi.total_bits += group->gd->bg_bits; alloc_inode->bi.used_bits++; group->alloc_inode = alloc_inode; group->name = strdup(name); return group; } static AllocBitmap * initialize_bitmap(State *s, uint32_t bits, uint32_t unit_bits, const char *name, SystemFileDiskRecord *bm_record) { AllocBitmap *bitmap; uint64_t blkno; int i, j, cpg, chain, c_to_b_bits; int recs_per_inode = ocfs2_chain_recs_per_inode(s->blocksize); int wrapped = 0; bitmap = do_malloc(s, sizeof(AllocBitmap)); memset(bitmap, 0, sizeof(AllocBitmap)); bitmap->valid_bits = bits; bitmap->unit_bits = unit_bits; bitmap->unit = 1 << unit_bits; bitmap->name = strdup(name); bm_record->file_size = s->volume_size_in_bytes; bm_record->fe_off = 0ULL; bm_record->bi.used_bits = 0; /* this will be set as we add groups. */ bm_record->bi.total_bits = 0; bm_record->bitmap = bitmap; bitmap->bm_record = bm_record; bitmap->groups = do_malloc(s, s->nr_cluster_groups * sizeof(AllocGroup *)); memset(bitmap->groups, 0, s->nr_cluster_groups * sizeof(AllocGroup *)); c_to_b_bits = s->cluster_size_bits - s->blocksize_bits; /* to the next aligned cluster */ s->first_cluster_group = (OCFS2_SUPER_BLOCK_BLKNO + 1); s->first_cluster_group += ((1 << c_to_b_bits) - 1); s->first_cluster_group >>= c_to_b_bits; s->first_cluster_group_blkno = (uint64_t)s->first_cluster_group << c_to_b_bits; bitmap->groups[0] = initialize_alloc_group(s, "stupid", bm_record, s->first_cluster_group_blkno, 0, s->global_cpg, 1); /* The first bit is set by initialize_alloc_group, hence * we start at 1. For this group (which contains the clusters * containing the superblock and first group descriptor), we * have to set these by hand. */ for (i = 1; i <= s->first_cluster_group; i++) { ocfs2_set_bit(i, bitmap->groups[0]->gd->bg_bitmap); bitmap->groups[0]->gd->bg_free_bits_count--; bm_record->bi.used_bits++; } bitmap->groups[0]->chain_total = s->global_cpg; bitmap->groups[0]->chain_free = bitmap->groups[0]->gd->bg_free_bits_count; chain = 1; blkno = (uint64_t) s->global_cpg << (s->cluster_size_bits - s->blocksize_bits); cpg = s->global_cpg; for(i = 1; i < s->nr_cluster_groups; i++) { if (i == (s->nr_cluster_groups - 1)) cpg = s->tail_group_bits; bitmap->groups[i] = initialize_alloc_group(s, "stupid", bm_record, blkno, chain, cpg, 1); if (wrapped) { /* link the previous group to this guy. */ j = i - recs_per_inode; bitmap->groups[j]->gd->bg_next_group = blkno; bitmap->groups[j]->next = bitmap->groups[i]; } bitmap->groups[chain]->chain_total += bitmap->groups[i]->gd->bg_bits; bitmap->groups[chain]->chain_free += bitmap->groups[i]->gd->bg_free_bits_count; blkno += (uint64_t) s->global_cpg << (s->cluster_size_bits - s->blocksize_bits); chain++; if (chain >= recs_per_inode) { chain = 0; wrapped = 1; } } if (!wrapped) bitmap->num_chains = chain; else bitmap->num_chains = recs_per_inode; /* by now, this should be accurate. */ if (bm_record->bi.total_bits != s->volume_size_in_clusters) { fprintf(stderr, "bitmap total and num clusters don't " "match! %u, %u\n", bm_record->bi.total_bits, s->volume_size_in_clusters); exit(1); } return bitmap; } #if 0 static void destroy_bitmap(AllocBitmap *bitmap) { free(bitmap->buf); free(bitmap); } #endif static int find_clear_bits(void *buf, unsigned int size, uint32_t num_bits, uint32_t offset) { uint32_t next_zero, off, count = 0, first_zero = -1; off = offset; while ((size - off + count >= num_bits) && (next_zero = ocfs2_find_next_bit_clear(buf, size, off)) != size) { if (next_zero >= size) break; if (next_zero != off) { first_zero = next_zero; off = next_zero + 1; count = 0; } else { off++; if (count == 0) first_zero = next_zero; } count++; if (count == num_bits) goto bail; } first_zero = -1; bail: if (first_zero != (uint32_t)-1 && first_zero > size) { fprintf(stderr, "erf... first_zero > bitmap->valid_bits " "(%d > %d)", first_zero, size); first_zero = -1; } return first_zero; } static int alloc_bytes_from_bitmap(State *s, uint64_t bytes, AllocBitmap *bitmap, uint64_t *start, uint64_t *num) { uint32_t num_bits = 0; num_bits = (bytes + bitmap->unit - 1) >> bitmap->unit_bits; return alloc_from_bitmap(s, num_bits, bitmap, start, num); } static int alloc_from_bitmap(State *s, uint64_t num_bits, AllocBitmap *bitmap, uint64_t *start, uint64_t *num) { uint32_t start_bit = (uint32_t) - 1; void *buf = NULL; int i, found, chain; AllocGroup *group; struct ocfs2_group_desc *gd = NULL; unsigned int size; found = 0; for(i = 0; i < bitmap->num_chains && !found; i++) { group = bitmap->groups[i]; do { gd = group->gd; if (gd->bg_free_bits_count >= num_bits) { buf = gd->bg_bitmap; size = gd->bg_bits; start_bit = find_clear_bits(buf, size, num_bits, 0); found = 1; break; } group = group->next; } while (group); } if (start_bit == (uint32_t)-1) { com_err(s->progname, 0, "Could not allocate %"PRIu64" bits from %s bitmap", num_bits, bitmap->name); exit(1); } if (gd->bg_blkno == s->first_cluster_group_blkno) *start = (uint64_t) start_bit; else *start = (uint64_t) start_bit + ((gd->bg_blkno << s->blocksize_bits) >> s->cluster_size_bits); *start = *start << bitmap->unit_bits; *num = ((uint64_t)num_bits) << bitmap->unit_bits; gd->bg_free_bits_count -= num_bits; chain = gd->bg_chain; bitmap->groups[chain]->chain_free -= num_bits; bitmap->bm_record->bi.used_bits += num_bits; #if 0 printf("alloc requested %"PRIu64" bits, given len = %"PRIu64", at " "start = %"PRIu64". used_bits = %u\n", num_bits, *num, *start, bitmap->bm_record->bi.used_bits); #endif while (num_bits--) { ocfs2_set_bit(start_bit, buf); start_bit++; } return 0; } static int alloc_from_group(State *s, uint16_t count, AllocGroup *group, uint64_t *start_blkno, uint16_t *num_bits) { uint16_t start_bit, end_bit; start_bit = ocfs2_find_first_bit_clear(group->gd->bg_bitmap, group->gd->bg_bits); while (start_bit < group->gd->bg_bits) { end_bit = ocfs2_find_next_bit_set(group->gd->bg_bitmap, group->gd->bg_bits, start_bit); if ((end_bit - start_bit) >= count) { *num_bits = count; for (*num_bits = 0; *num_bits < count; *num_bits += 1) { ocfs2_set_bit(start_bit + *num_bits, group->gd->bg_bitmap); } group->gd->bg_free_bits_count -= *num_bits; group->alloc_inode->bi.used_bits += *num_bits; *start_blkno = group->gd->bg_blkno + start_bit; return 0; } start_bit = end_bit; } com_err(s->progname, 0, "Could not allocate %"PRIu16" bits from %s alloc group", count, group->name); exit(1); return 1; } static uint64_t alloc_inode(State *s, uint16_t *suballoc_bit) { uint64_t ret; uint16_t num; alloc_from_group(s, 1, s->system_group, &ret, &num); *suballoc_bit = (int)(ret - s->system_group->gd->bg_blkno); /* Did I mention I hate this code? */ return (ret << s->blocksize_bits); } static DirData * alloc_directory(State *s) { DirData *dir; dir = do_malloc(s, sizeof(DirData)); memset(dir, 0, sizeof(DirData)); return dir; } static void add_entry_to_directory(State *s, DirData *dir, char *name, uint64_t byte_off, uint8_t type) { struct ocfs2_dir_entry *de, *de1; int new_rec_len; void *new_buf, *p; int new_size, rec_len, real_len; new_rec_len = OCFS2_DIR_REC_LEN(strlen(name)); if (dir->buf) { de = (struct ocfs2_dir_entry *)(dir->buf + dir->last_off); rec_len = de->rec_len; real_len = OCFS2_DIR_REC_LEN(de->name_len); if ((de->inode == 0 && rec_len >= new_rec_len) || (rec_len >= real_len + new_rec_len)) { if (de->inode) { de1 =(struct ocfs2_dir_entry *) ((char *) de + real_len); de1->rec_len = de->rec_len - real_len; de->rec_len = real_len; de = de1; } goto got_it; } new_size = dir->record->file_size + s->blocksize; } else { new_size = s->blocksize; } new_buf = memalign(s->blocksize, new_size); if (new_buf == NULL) { com_err(s->progname, 0, "Failed to grow directory"); exit(1); } if (dir->buf) { memcpy(new_buf, dir->buf, dir->record->file_size); free(dir->buf); p = new_buf + dir->record->file_size; memset(p, 0, s->blocksize); } else { p = new_buf; memset(new_buf, 0, new_size); } dir->buf = new_buf; dir->record->file_size = new_size; de = (struct ocfs2_dir_entry *)p; de->inode = 0; de->rec_len = s->blocksize; if (!s->inline_data || !dir->record->dir_data) mkfs_init_dir_trailer(s, dir, p); got_it: de->name_len = strlen(name); de->inode = byte_off >> s->blocksize_bits; de->file_type = type; strcpy(de->name, name); dir->last_off = ((char *)de - (char *)dir->buf); if (type == OCFS2_FT_DIR) dir->record->links++; } static uint32_t blocks_needed(State *s) { uint32_t num; num = SUPERBLOCK_BLOCKS; num += ROOTDIR_BLOCKS; num += SYSDIR_BLOCKS; num += LOSTDIR_BLOCKS; num += sys_blocks_needed(MAX(32, s->initial_slots)); return num; } static uint32_t sys_blocks_needed(uint32_t num_slots) { uint32_t num = 0; uint32_t cnt = sizeof(system_files) / sizeof(SystemFileInfo); int i; for (i = 0; i < cnt; ++i) { if (system_files[i].global) ++num; else num += num_slots; } return num; } static uint32_t system_dir_blocks_needed(State *s) { int each = OCFS2_DIR_REC_LEN(SYSTEM_FILE_NAME_MAX); int entries_per_block = s->blocksize / each; return (sys_blocks_needed(s->initial_slots) + entries_per_block - 1) / entries_per_block; } #if 0 /* This breaks stuff that depends on volume_size_in_clusters and * volume_size_in_blocks, and I'm not even sure it's necessary. If * needed, this sort of calculation should be done before * fill_defaults where we calculate a bunch of other things based on * #blocks and #clusters. */ static void adjust_volume_size(State *s) { uint32_t max; uint64_t vsize = s->volume_size_in_bytes - (MIN_RESERVED_TAIL_BLOCKS << s->blocksize_bits); max = MAX(s->pagesize_bits, s->blocksize_bits); max = MAX(max, s->cluster_size_bits); vsize >>= max; vsize <<= max; s->volume_size_in_blocks = vsize >> s->blocksize_bits; s->volume_size_in_clusters = vsize >> s->cluster_size_bits; s->reserved_tail_size = s->volume_size_in_bytes - vsize; s->volume_size_in_bytes = vsize; } #endif /* this will go away once we have patches to jbd to support 64bit blocks. * ocfs2 will only fail mounts when it finds itself asked to mount a large * device in a kernel that doesn't have a smarter jbd. */ static void check_32bit_blocks(State *s) { uint64_t max = UINT32_MAX; if (s->journal64) return; if (s->volume_size_in_blocks <= max) return; fprintf(stderr, "ERROR: jbd can only store block numbers in 32 bits. " "%s can hold %"PRIu64" blocks which overflows this limit. If " "you have a new enough Ocfs2 with JBD2 support, you can try " "formatting with the \"-Jblock64\" option to turn on support " "for this size block device.\n" "Otherwise, consider increasing the block size or " "decreasing the device size.\n", s->device_name, s->volume_size_in_blocks); exit(1); } static void mkfs_swap_inode_from_cpu(State *s, struct ocfs2_dinode *di) { ocfs2_filesys fake_fs; char super_buf[OCFS2_MAX_BLOCKSIZE]; fill_fake_fs(s, &fake_fs, super_buf); ocfs2_swap_inode_from_cpu(&fake_fs, di); } static void mkfs_swap_group_desc_from_cpu(State *s, struct ocfs2_group_desc *gd) { ocfs2_filesys fake_fs; char super_buf[OCFS2_MAX_BLOCKSIZE]; fill_fake_fs(s, &fake_fs, super_buf); ocfs2_swap_group_desc_from_cpu(&fake_fs, gd); } static void mkfs_swap_group_desc_to_cpu(State *s, struct ocfs2_group_desc *gd) { ocfs2_filesys fake_fs; char super_buf[OCFS2_MAX_BLOCKSIZE]; fill_fake_fs(s, &fake_fs, super_buf); ocfs2_swap_group_desc_to_cpu(&fake_fs, gd); } static void format_superblock(State *s, SystemFileDiskRecord *rec, SystemFileDiskRecord *root_rec, SystemFileDiskRecord *sys_rec) { struct ocfs2_dinode *di; uint64_t super_off = rec->fe_off; di = do_malloc(s, s->blocksize); memset(di, 0, s->blocksize); strcpy((char *)di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE); di->i_suballoc_slot = (__u16)OCFS2_INVALID_SLOT; di->i_suballoc_bit = (__u16)-1; di->i_generation = s->vol_generation; di->i_fs_generation = s->vol_generation; di->i_atime = 0; di->i_ctime = s->format_time; di->i_mtime = s->format_time; di->i_blkno = super_off >> s->blocksize_bits; di->i_flags = OCFS2_VALID_FL | OCFS2_SYSTEM_FL | OCFS2_SUPER_BLOCK_FL; di->i_clusters = s->volume_size_in_clusters; di->id2.i_super.s_major_rev_level = OCFS2_MAJOR_REV_LEVEL; di->id2.i_super.s_minor_rev_level = OCFS2_MINOR_REV_LEVEL; di->id2.i_super.s_root_blkno = root_rec->fe_off >> s->blocksize_bits; di->id2.i_super.s_system_dir_blkno = sys_rec->fe_off >> s->blocksize_bits; di->id2.i_super.s_mnt_count = 0; di->id2.i_super.s_max_mnt_count = OCFS2_DFL_MAX_MNT_COUNT; di->id2.i_super.s_state = 0; di->id2.i_super.s_errors = 0; di->id2.i_super.s_lastcheck = s->format_time; di->id2.i_super.s_checkinterval = OCFS2_DFL_CHECKINTERVAL; di->id2.i_super.s_creator_os = OCFS2_OS_LINUX; di->id2.i_super.s_blocksize_bits = s->blocksize_bits; di->id2.i_super.s_clustersize_bits = s->cluster_size_bits; di->id2.i_super.s_max_slots = s->initial_slots; di->id2.i_super.s_first_cluster_group = s->first_cluster_group_blkno; if (s->hb_dev) { s->feature_flags.opt_incompat = OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV; s->feature_flags.opt_compat = OCFS2_FEATURE_COMPAT_JBD2_SB; s->feature_flags.opt_ro_compat = 0; } if (s->mount == MOUNT_LOCAL) s->feature_flags.opt_incompat |= OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT; if (s->cluster_stack) { s->feature_flags.opt_incompat |= (OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP| OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK); memcpy(di->id2.i_super.s_cluster_info.ci_stack, s->cluster_stack, OCFS2_STACK_LABEL_LEN); memcpy(di->id2.i_super.s_cluster_info.ci_cluster, s->cluster_name, OCFS2_CLUSTER_NAME_LEN); } /* * we clear the "backup_sb" here since it should be written by * format_backup_super, not by us. And we have already set the * "s->no_backup_super" according to the features in get_state, * so it is safe to clear the flag here. */ s->feature_flags.opt_compat &= ~OCFS2_FEATURE_COMPAT_BACKUP_SB; if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_XATTR) di->id2.i_super.s_xattr_inline_size = OCFS2_MIN_XATTR_INLINE_SIZE; di->id2.i_super.s_feature_incompat = s->feature_flags.opt_incompat; di->id2.i_super.s_feature_compat = s->feature_flags.opt_compat; di->id2.i_super.s_feature_ro_compat = s->feature_flags.opt_ro_compat; strcpy((char *)di->id2.i_super.s_label, s->vol_label); memcpy(di->id2.i_super.s_uuid, s->uuid, 16); /* s_uuid_hash is also used by Indexed Dirs */ if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_XATTR || s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS) di->id2.i_super.s_uuid_hash = ocfs2_xattr_uuid_hash(s->uuid); if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS) { di->id2.i_super.s_dx_seed[0] = mrand48(); di->id2.i_super.s_dx_seed[1] = mrand48(); di->id2.i_super.s_dx_seed[2] = mrand48(); } mkfs_swap_inode_from_cpu(s, di); mkfs_compute_meta_ecc(s, di, &di->i_check); do_pwrite(s, di, s->blocksize, super_off); free(di); } /* * This function is in libocfs2/alloc.c. Needless to add, when * changing code here, update the same in alloc.c too. */ static int ocfs2_clusters_per_group(int block_size, int cluster_size_bits) { int megabytes; switch (block_size) { case 4096: case 2048: megabytes = 4; break; case 1024: megabytes = 2; break; case 512: default: megabytes = 1; break; } return (megabytes << ONE_MB_SHIFT) >> cluster_size_bits; } static void format_file(State *s, SystemFileDiskRecord *rec) { struct ocfs2_dinode *di; int mode, i; uint32_t clusters; AllocBitmap *bitmap; mode = rec->mode; clusters = (rec->extent_len + s->cluster_size - 1) >> s->cluster_size_bits; di = do_malloc(s, s->blocksize); memset(di, 0, s->blocksize); strcpy((char *)di->i_signature, OCFS2_INODE_SIGNATURE); di->i_generation = s->vol_generation; di->i_fs_generation = s->vol_generation; di->i_suballoc_slot = (__u16)OCFS2_INVALID_SLOT; di->i_suballoc_bit = rec->suballoc_bit; di->i_blkno = rec->fe_off >> s->blocksize_bits; di->i_uid = 0; di->i_gid = 0; di->i_size = rec->file_size; di->i_mode = mode; di->i_links_count = rec->links; di->i_flags = rec->flags; di->i_atime = di->i_ctime = di->i_mtime = s->format_time; di->i_dtime = 0; di->i_clusters = clusters; if (rec->flags & OCFS2_LOCAL_ALLOC_FL) { di->id2.i_lab.la_size = ocfs2_local_alloc_size(s->blocksize); goto write_out; } if (rec->flags & OCFS2_DEALLOC_FL) { di->id2.i_dealloc.tl_count = ocfs2_truncate_recs_per_inode(s->blocksize); goto write_out; } if (rec->flags & OCFS2_BITMAP_FL) { di->id1.bitmap1.i_used = rec->bi.used_bits; di->id1.bitmap1.i_total = rec->bi.total_bits; } if (rec->cluster_bitmap) { di->id2.i_chain.cl_count = ocfs2_chain_recs_per_inode(s->blocksize); di->id2.i_chain.cl_cpg = ocfs2_group_bitmap_size(s->blocksize, 0, 0) * 8; di->id2.i_chain.cl_bpc = 1; if (s->nr_cluster_groups > ocfs2_chain_recs_per_inode(s->blocksize)) { di->id2.i_chain.cl_next_free_rec = di->id2.i_chain.cl_count; } else di->id2.i_chain.cl_next_free_rec = s->nr_cluster_groups; di->i_clusters = s->volume_size_in_clusters; bitmap = rec->bitmap; for(i = 0; i < bitmap->num_chains; i++) { di->id2.i_chain.cl_recs[i].c_blkno = bitmap->groups[i]->gd->bg_blkno; di->id2.i_chain.cl_recs[i].c_free = bitmap->groups[i]->chain_free; di->id2.i_chain.cl_recs[i].c_total = bitmap->groups[i]->chain_total; } goto write_out; } if (rec->flags & OCFS2_CHAIN_FL) { di->id2.i_chain.cl_count = ocfs2_chain_recs_per_inode(s->blocksize); di->id2.i_chain.cl_cpg = ocfs2_clusters_per_group(s->blocksize, s->cluster_size_bits); di->id2.i_chain.cl_bpc = s->cluster_size / s->blocksize; di->id2.i_chain.cl_next_free_rec = 0; if (rec->chain_off) { di->id2.i_chain.cl_next_free_rec = 1; di->id2.i_chain.cl_recs[0].c_free = rec->group->gd->bg_free_bits_count; di->id2.i_chain.cl_recs[0].c_total = rec->group->gd->bg_bits; di->id2.i_chain.cl_recs[0].c_blkno = rec->chain_off >> s->blocksize_bits; di->id2.i_chain.cl_cpg = rec->group->gd->bg_bits / di->id2.i_chain.cl_bpc; di->i_clusters = di->id2.i_chain.cl_cpg; di->i_size = di->i_clusters << s->cluster_size_bits; } goto write_out; } di->id2.i_list.l_count = ocfs2_extent_recs_per_inode(s->blocksize); di->id2.i_list.l_next_free_rec = 0; di->id2.i_list.l_tree_depth = 0; if (rec->extent_len) { di->id2.i_list.l_next_free_rec = 1; di->id2.i_list.l_recs[0].e_cpos = 0; ocfs2_set_rec_clusters(0, &di->id2.i_list.l_recs[0], clusters); di->id2.i_list.l_recs[0].e_blkno = rec->extent_off >> s->blocksize_bits; } else if (S_ISDIR(di->i_mode) && s->inline_data && rec->dir_data) { DirData *dir = rec->dir_data; struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)(dir->buf + dir->last_off); int dir_len = dir->last_off + OCFS2_DIR_REC_LEN(de->name_len); if (dir_len > ocfs2_max_inline_data_with_xattr(s->blocksize, di)) { com_err(s->progname, 0, "Inline a dir which shouldn't be inline.\n"); clear_both_ends(s); exit(1); } de->rec_len -= s->blocksize - ocfs2_max_inline_data_with_xattr(s->blocksize, di); memset(&di->id2, 0, s->blocksize - offsetof(struct ocfs2_dinode, id2)); di->id2.i_data.id_count = ocfs2_max_inline_data_with_xattr(s->blocksize, di); memcpy(di->id2.i_data.id_data, dir->buf, dir_len); di->i_dyn_features |= OCFS2_INLINE_DATA_FL; di->i_size = ocfs2_max_inline_data_with_xattr(s->blocksize, di); } write_out: mkfs_swap_inode_from_cpu(s, di); mkfs_compute_meta_ecc(s, di, &di->i_check); do_pwrite(s, di, s->blocksize, rec->fe_off); free(di); } static void write_metadata(State *s, SystemFileDiskRecord *rec, void *src) { void *buf; buf = do_malloc(s, rec->extent_len); memset(buf, 0, rec->extent_len); if (src) memcpy(buf, src, rec->file_size); do_pwrite(s, buf, rec->extent_len, rec->extent_off); free(buf); } static void write_bitmap_data(State *s, AllocBitmap *bitmap) { int i; uint64_t parent_blkno; struct ocfs2_group_desc *gd, *gd_buf; char *buf = NULL; buf = do_malloc(s, s->cluster_size); memset(buf, 0, s->cluster_size); parent_blkno = bitmap->bm_record->fe_off >> s->blocksize_bits; for(i = 0; i < s->nr_cluster_groups; i++) { gd = bitmap->groups[i]->gd; if (strcmp((char *)gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE)) { fprintf(stderr, "bad group descriptor!\n"); exit(1); } /* Ok, we didn't get a chance to fill in the parent * blkno until now. */ gd->bg_parent_dinode = parent_blkno; memcpy(buf, gd, s->blocksize); gd_buf = (struct ocfs2_group_desc *)buf; mkfs_swap_group_desc_from_cpu(s, gd_buf); mkfs_compute_meta_ecc(s, buf, &gd_buf->bg_check); do_pwrite(s, buf, s->cluster_size, gd->bg_blkno << s->blocksize_bits); } free(buf); } static void write_group_data(State *s, AllocGroup *group) { uint64_t blkno = group->gd->bg_blkno; mkfs_swap_group_desc_from_cpu(s, group->gd); mkfs_compute_meta_ecc(s, group->gd, &group->gd->bg_check); do_pwrite(s, group->gd, s->blocksize, blkno << s->blocksize_bits); mkfs_swap_group_desc_to_cpu(s, group->gd); } static void mkfs_swap_dir(State *s, DirData *dir, errcode_t (*swap_entry_func)(void *buf, uint64_t bytes)) { char *p = dir->buf; unsigned int offset = 0; unsigned int end = s->blocksize; char super_buf[OCFS2_MAX_BLOCKSIZE]; ocfs2_filesys fake_fs; struct ocfs2_dir_block_trailer *trailer; if (!dir->record->extent_len) return; fill_fake_fs(s, &fake_fs, super_buf); if (!s->inline_data || !dir->record->dir_data) if (ocfs2_supports_dir_trailer(&fake_fs)) end = ocfs2_dir_trailer_blk_off(&fake_fs); while (offset < dir->record->file_size) { trailer = ocfs2_dir_trailer_from_block(&fake_fs, p); swap_entry_func(p, end); if (end != s->blocksize) ocfs2_swap_dir_trailer(trailer); /* Remember, this does nothing if the feature isn't set */ ocfs2_compute_meta_ecc(&fake_fs, p, &trailer->db_check); offset += s->blocksize; p += s->blocksize; } } static void mkfs_swap_dir_from_cpu(State *s, DirData *dir) { mkfs_swap_dir(s, dir, ocfs2_swap_dir_entries_from_cpu); } static void mkfs_swap_dir_to_cpu(State *s, DirData *dir) { mkfs_swap_dir(s, dir, ocfs2_swap_dir_entries_to_cpu); } static void write_directory_data(State *s, DirData *dir) { if (!dir->record->extent_len) return; if (dir->buf) mkfs_swap_dir_from_cpu(s, dir); write_metadata(s, dir->record, dir->buf); if (dir->buf) mkfs_swap_dir_to_cpu(s, dir); } static void format_leading_space(State *s) { int num_blocks = 2, size; struct ocfs1_vol_disk_hdr *hdr; struct ocfs1_vol_label *lbl; void *buf; char *p; size = num_blocks << s->blocksize_bits; p = buf = do_malloc(s, size); memset(buf, 2, size); hdr = buf; strcpy((char *)hdr->signature, "this is an ocfs2 volume"); strcpy((char *)hdr->mount_point, "this is an ocfs2 volume"); p += 512; lbl = (struct ocfs1_vol_label *)p; strcpy((char *)lbl->label, "this is an ocfs2 volume"); strcpy((char *)lbl->cluster_name, "this is an ocfs2 volume"); do_pwrite(s, buf, size, 0); free(buf); } static void open_device(State *s) { s->fd = open64(s->device_name, O_RDWR | O_DIRECT); if (s->fd == -1) { com_err(s->progname, 0, "Could not open device %s: %s", s->device_name, strerror (errno)); exit(1); } } static void close_device(State *s) { fsync(s->fd); close(s->fd); s->fd = -1; } static int initial_slots_for_volume(uint64_t size) { size >>= ONE_GB_SHIFT; if (size < 2) return 2; else if (size < 10) return 4; else if (size < 1024) return 8; else return 16; } static void generate_uuid(State *s) { s->uuid = do_malloc(s, OCFS2_VOL_UUID_LEN); uuid_generate(s->uuid); } static void create_generation(State *s) { int randfd = 0; int readlen = sizeof(s->vol_generation); if ((randfd = open("/dev/urandom", O_RDONLY)) == -1) { com_err(s->progname, 0, "Error opening /dev/urandom: %s", strerror(errno)); exit(1); } if (read(randfd, &s->vol_generation, readlen) != readlen) { com_err(s->progname, 0, "Error reading from /dev/urandom: %s", strerror(errno)); exit(1); } close(randfd); } static void init_record(State *s, SystemFileDiskRecord *rec, int type, int mode) { memset(rec, 0, sizeof(SystemFileDiskRecord)); rec->flags = OCFS2_VALID_FL | OCFS2_SYSTEM_FL; rec->mode = mode; rec->links = S_ISDIR(mode) ? 0 : 1; rec->bi.used_bits = rec->bi.total_bits = 0; rec->flags = (OCFS2_VALID_FL | OCFS2_SYSTEM_FL); switch (type) { case SFI_JOURNAL: rec->flags |= OCFS2_JOURNAL_FL; break; case SFI_LOCAL_ALLOC: rec->flags |= (OCFS2_BITMAP_FL|OCFS2_LOCAL_ALLOC_FL); break; case SFI_HEARTBEAT: rec->flags |= OCFS2_HEARTBEAT_FL; break; case SFI_CLUSTER: rec->cluster_bitmap = 1; case SFI_CHAIN: rec->flags |= (OCFS2_BITMAP_FL|OCFS2_CHAIN_FL); break; case SFI_TRUNCATE_LOG: rec->flags |= OCFS2_DEALLOC_FL; break; case SFI_QUOTA: rec->flags |= OCFS2_QUOTA_FL; break; case SFI_OTHER: break; } } static void print_state(State *s) { int i; char buf[PATH_MAX] = "\0"; uint64_t extsize = 0; uint32_t numgrps = 0; if (s->quiet) return; if (s->extent_alloc_size_in_clusters) { numgrps = s->extent_alloc_size_in_clusters / ocfs2_clusters_per_group(s->blocksize, s->cluster_size_bits); extsize = (uint64_t)s->extent_alloc_size_in_clusters * s->cluster_size; } ocfs2_snprint_feature_flags(buf, PATH_MAX, &s->feature_flags); if (s->fs_type != OCFS2_MKFSTYPE_DEFAULT) { for(i = 0; ocfs2_mkfs_types_table[i].ft_str; i++) { if (ocfs2_mkfs_types_table[i].ft_type == s->fs_type) { printf("Filesystem Type of %s\n", ocfs2_mkfs_types_table[i].ft_str); break; } } } printf("Label: %s\n", s->vol_label); printf("Features: %s\n", buf); printf("Block size: %u (%u bits)\n", s->blocksize, s->blocksize_bits); printf("Cluster size: %u (%u bits)\n", s->cluster_size, s->cluster_size_bits); printf("Volume size: %"PRIu64" (%u clusters) (%"PRIu64" blocks)\n", s->volume_size_in_bytes, s->volume_size_in_clusters, s->volume_size_in_blocks); printf("Cluster groups: %u (tail covers %u clusters, rest cover %u " "clusters)\n", s->nr_cluster_groups, s->tail_group_bits, s->global_cpg); printf("Extent allocator size: %"PRIu64" (%u groups)\n", extsize, numgrps); if (s->hb_dev) printf("Heartbeat device\n"); else printf("Journal size: %"PRIu64"\n", s->journal_size_in_bytes); printf("Node slots: %u\n", s->initial_slots); } static void clear_both_ends(State *s) { char *buf = NULL; buf = do_malloc(s, CLEAR_CHUNK); memset(buf, 0, CLEAR_CHUNK); /* start of volume */ do_pwrite(s, buf, CLEAR_CHUNK, 0); /* end of volume */ do_pwrite(s, buf, CLEAR_CHUNK, (s->volume_size_in_bytes - CLEAR_CHUNK)); free(buf); return ; } static void index_system_dirs(State *s, ocfs2_filesys *fs) { errcode_t ret; int i, num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; uint64_t orphan_dir_blkno; /* Start with the root directory */ ret = ocfs2_dx_dir_build(fs, fs->fs_root_blkno); if (ret) { com_err(s->progname, ret, "while indexing root directory"); goto bail; } for (i = 0; i < num_slots; i++) { ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE, i, &orphan_dir_blkno); if (ret) { com_err(s->progname, ret, "while looking up orphan dir %d for indexing", i); goto bail; } ret = ocfs2_dx_dir_build(fs, orphan_dir_blkno); if (ret) { com_err(s->progname, ret, "while indexing root directory"); goto bail; } } return; bail: clear_both_ends(s); exit(1); } static void create_lost_found_dir(State *s, ocfs2_filesys *fs) { errcode_t ret; uint64_t lost_found_blkno; ret = ocfs2_new_inode(fs, &lost_found_blkno, S_IFDIR | 0755); if (ret) { com_err(s->progname, ret, "while creating lost+found"); goto bail; } ret = ocfs2_init_dir(fs, lost_found_blkno, fs->fs_root_blkno); if (ret) { com_err(s->progname, ret, "while adding lost+found dir data"); goto bail; } ret = ocfs2_link(fs, fs->fs_root_blkno, "lost+found", lost_found_blkno, OCFS2_FT_DIR); if (ret) { com_err(s->progname, ret, "while linking lost+found to the " "root directory"); goto bail; } return ; bail: clear_both_ends(s); exit(1); } static void format_journals(State *s, ocfs2_filesys *fs) { errcode_t ret; int i; uint32_t journal_size_in_clusters; uint64_t blkno; char jrnl_file[40]; ocfs2_fs_options features = { .opt_incompat = s->journal64 ? JBD2_FEATURE_INCOMPAT_64BIT : 0, }; journal_size_in_clusters = s->journal_size_in_bytes >> OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; for(i = 0; i < OCFS2_RAW_SB(fs->fs_super)->s_max_slots; i++) { snprintf (jrnl_file, sizeof(jrnl_file), ocfs2_system_inodes[JOURNAL_SYSTEM_INODE].si_name, i); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, jrnl_file, strlen(jrnl_file), NULL, &blkno); if (ret) { com_err(s->progname, ret, "while looking up journal filename \"%.*s\"", (int)strlen(jrnl_file), jrnl_file); goto error; } ret = ocfs2_make_journal(fs, blkno, journal_size_in_clusters, &features); if (ret) { com_err(s->progname, ret, "while formatting journal \"%.*s\"", (int)strlen(jrnl_file), jrnl_file); goto error; } } return; error: clear_both_ends(s); exit(1); } static void format_slotmap(State *s, ocfs2_filesys *fs) { errcode_t ret; ret = ocfs2_format_slot_map(fs); if (ret) { com_err(s->progname, ret, "while formatting the slot map"); clear_both_ends(s); exit(1); } } static int format_backup_super(State *s, ocfs2_filesys *fs) { errcode_t ret; size_t len; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; len = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); ret = ocfs2_set_backup_super_list(fs, blocks, len); if (ret) { com_err(s->progname, ret, "while backing up superblock."); goto error; } OCFS2_SET_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB); /* ocfs2_set_backup_super_list() wrote the backups */ ret = ocfs2_write_primary_super(fs); if (ret) { com_err(s->progname, ret, "while updating superblock."); goto error; } return len; error: clear_both_ends(s); exit(1); } static void mkfs_compute_meta_ecc(State *s, void *data, struct ocfs2_block_check *bc) { if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_META_ECC) ocfs2_block_check_compute(data, s->blocksize, bc); } ./ocfs2-tools-1.6.4/mkfs.ocfs2/check.c0000664000176100017610000002103211506552637014164 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * check.c * * OCFS2 format check utility * * Copyright (C) 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #include "mkfs.h" #define WHOAMI "mkfs.ocfs2" /* For ocfs2_fill_cluster_information(). Errors are to be ignored */ static void cluster_fill(char **stack_name, char **cluster_name) { errcode_t err; struct o2cb_cluster_desc cluster; err = o2cb_init(); if (err) return; err = o2cb_running_cluster_desc(&cluster); if (err) return; if (cluster.c_stack) { /* * These were allocated by o2cb_running_cluster_desc(), * the caller will free them. */ *stack_name = cluster.c_stack; *cluster_name = cluster.c_cluster; } else *stack_name = strdup("o2cb"); } /* For ocfs2_fill_cluster_information(). Errors are to be ignored */ static void disk_fill(const char *device, char **stack_name, char **cluster_name) { errcode_t err; ocfs2_filesys *fs = NULL; struct o2cb_cluster_desc desc; err = ocfs2_open(device, OCFS2_FLAG_RO, 0, 0, &fs); if (err) return; if (!ocfs2_userspace_stack(OCFS2_RAW_SB(fs->fs_super))) { *stack_name = strdup("o2cb"); goto close; } err = ocfs2_fill_cluster_desc(fs, &desc); if (err) goto close; *stack_name = strdup(desc.c_stack); *cluster_name = strdup(desc.c_cluster); close: ocfs2_close(fs); } static int pick_one(State *s, const char *what_is_it, const char *user_value, const char *o2cb_value, const char *disk_value, char **ret_value) { int rc = -1; /* * First, compare o2cb and disk values. If we get past this * block (via match or override), the o2cb value takes precedence. */ if (disk_value && o2cb_value && strcmp(o2cb_value, disk_value)) { fprintf(stderr, "%s is configured to use %s \"%s\", but \"%s\" is currently running.\n" "%s will not be able to determine if the filesystem is in use.\n", s->device_name, what_is_it, disk_value, o2cb_value, s->progname); if (!s->force) { fprintf(stderr, "To skip this check, use --force or -F\n"); goto out; } fprintf(stdout, "Overwrite of disk information forced\n"); } if (user_value) { if (o2cb_value) { if (strcmp(o2cb_value, user_value)) { fprintf(stderr, "%s \"%s\" was requested, but \"%s\" is running.\n", what_is_it, user_value, o2cb_value); if (!s->force) { fprintf(stderr, "To skip this check, use --force or -F\n"); goto out; } fprintf(stdout, "%s forced\n", what_is_it); } } else if (disk_value) { if (strcmp(disk_value, user_value)) { fprintf(stderr, "%s \"%s\" was requested, but %s is configured for \"%s\".\n", what_is_it, user_value, s->device_name, disk_value); if (!s->force) { fprintf(stderr, "To skip this check, use --force or -F\n"); goto out; } fprintf(stderr, "%s forced\n", what_is_it); } } *ret_value = strdup(user_value); } else if (o2cb_value) *ret_value = strdup(o2cb_value); else if (disk_value) *ret_value = strdup(disk_value); rc = 0; out: return rc;; } /* * Try to connect to the cluster and look at the disk to fill in default * cluster values. If we can't connect, that's OK for now. The only errors * are when values are missing or conflict with option arguments. */ int ocfs2_fill_cluster_information(State *s) { int rc = -1; char *user_cluster_name = NULL; char *user_stack_name = NULL; char *o2cb_cluster_name = NULL; char *o2cb_stack_name = NULL; char *disk_cluster_name = NULL; char *disk_stack_name = NULL; if (s->mount == MOUNT_LOCAL) return 0; cluster_fill(&o2cb_stack_name, &o2cb_cluster_name); disk_fill(s->device_name, &disk_stack_name, &disk_cluster_name); user_stack_name = s->cluster_stack; user_cluster_name = s->cluster_name; if (pick_one(s, "cluster stack", user_stack_name, o2cb_stack_name, disk_stack_name, &s->cluster_stack)) return -1; if (pick_one(s, "cluster name", user_cluster_name, o2cb_cluster_name, disk_cluster_name, &s->cluster_name)) return -1; if (s->cluster_stack) { if (!strcmp(s->cluster_stack, "o2cb")) { /* * We've already checked for conflicts above. Now * clear out the stack so that fill_super knows * it's a classic filesystem. */ free(s->cluster_stack); s->cluster_stack = NULL; } else if (!s->cluster_name) { fprintf(stderr, "Cluster name required for stack \"%s\".\n", s->cluster_stack); goto out; } } if (!s->cluster_stack && s->cluster_name) { /* The classic stack doesn't write a name */ free(s->cluster_name); s->cluster_name = NULL; } if (s->cluster_stack) { fprintf(stdout, "Cluster stack: %s\n" "Cluster name: %s\n" "NOTE: Selecting extended slot map for userspace " "cluster stack\n", s->cluster_stack, s->cluster_name); } else fprintf(stdout, "Cluster stack: classic o2cb\n"); rc = 0; out: if (user_stack_name) free(user_stack_name); if (user_cluster_name) free(user_cluster_name); if (o2cb_stack_name) free(o2cb_stack_name); if (o2cb_cluster_name) free(o2cb_cluster_name); if (disk_stack_name) free(disk_stack_name); if (disk_cluster_name) free(disk_cluster_name); return rc; } int ocfs2_check_volume(State *s) { ocfs2_filesys *fs = NULL; errcode_t ret; int mount_flags; if (s->dry_run) { fprintf(stdout, "Dry run\n"); return 0; } if (ocfs2_fill_cluster_information(s)) return -1; ret = ocfs2_check_if_mounted(s->device_name, &mount_flags); if (ret) { com_err(s->progname, ret, "while determining whether %s is mounted.", s->device_name); return -1; } if (mount_flags & OCFS2_MF_MOUNTED) { fprintf(stderr, "%s is mounted; ", s->device_name); if (s->force) { fputs("overwriting anyway. Hope /etc/mtab is " "incorrect.\n", stderr); return 1; } fputs("will not make a ocfs2 volume here!\n", stderr); return -1; } if (mount_flags & OCFS2_MF_BUSY) { fprintf(stderr, "%s is apparently in use by the system; ", s->device_name); if (s->force) { fputs("format forced anyway.\n", stderr); return 1; } fputs("will not make a ocfs2 volume here!\n", stderr); return -1; } ret = ocfs2_open(s->device_name, OCFS2_FLAG_RW, 0, 0, &fs); if ((ret == OCFS2_ET_UNSUPP_FEATURE) || (ret == OCFS2_ET_RO_UNSUPP_FEATURE)) { com_err(s->progname, ret, "while opening device \"%s\"", s->device_name); if (!s->force) { fprintf(stderr, "As this is an existing OCFS2 volume, it could be mounted on an another node in the cluster.\n" "However, as %s is unable to read the superblock, it cannot detect if the volume is in use or not.\n" "To skip this check, use --force or -F.\n", s->progname); return -1; } else { fprintf(stderr, "WARNING: Cluster check disabled.\n"); return 1; } } else if (ret) { if (ret == OCFS2_ET_OCFS_REV) fprintf(stdout, "Overwriting existing ocfs partition.\n"); return 0; } else fprintf(stdout, "Overwriting existing ocfs2 partition.\n"); if (ocfs2_mount_local(fs)) goto nolock; if (!s->force) { ret = o2cb_init(); if (ret) { com_err(s->progname, ret, "while initializing the cluster"); return -1; } ret = ocfs2_initialize_dlm(fs, WHOAMI); if (ret) { ocfs2_close(fs); com_err(s->progname, ret, "while initializing the dlm"); fprintf(stderr, "As this is an existing OCFS2 volume, it could be mounted on an another node in the cluster.\n" "However, as %s is unable to initialize the dlm, it cannot detect if the volume is in use or not.\n" "To skip this check, use --force or -F.\n", s->progname); return -1; } ret = ocfs2_lock_down_cluster(fs); if (ret) { ocfs2_shutdown_dlm(fs, WHOAMI); ocfs2_close(fs); com_err(s->progname, ret, "while locking the cluster"); fprintf(stderr, "This volume appears to be in use in the cluster.\n"); return -1; } ocfs2_release_cluster(fs); ocfs2_shutdown_dlm(fs, WHOAMI); } else { fprintf(stderr, "WARNING: Cluster check disabled.\n"); } nolock: ocfs2_close(fs); return 1; } ./ocfs2-tools-1.6.4/mkfs.ocfs2/mkfs.h0000664000176100017610000001127711506552637014066 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * mkfs2.h * * Definitions, function prototypes, etc. * * Copyright (C) 2004, 2005 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * 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 021110-1307, USA. * */ #define _LARGEFILE64_SOURCE #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "ocfs2-kernel/ocfs1_fs_compat.h" #include #include #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #define MOUNT_LOCAL 1 #define MOUNT_CLUSTER 2 #define MOUNT_LOCAL_STR "local" #define MOUNT_CLUSTER_STR "cluster" #define MIN_RESERVED_TAIL_BLOCKS 8 #define SUPERBLOCK_BLOCKS 3 #define ROOTDIR_BLOCKS 1 #define SYSDIR_BLOCKS 1 #define LOSTDIR_BLOCKS 1 #define CLEAR_CHUNK 1048576 #define OCFS2_OS_LINUX 0 #define OCFS2_OS_HURD 1 #define OCFS2_OS_MASIX 2 #define OCFS2_OS_FREEBSD 3 #define OCFS2_OS_LITES 4 #define OCFS2_DFL_MAX_MNT_COUNT 20 #define OCFS2_DFL_CHECKINTERVAL 0 #define SYSTEM_FILE_NAME_MAX 40 #define ONE_MB_SHIFT 20 #define ONE_GB_SHIFT 30 #define BITMAP_AUTO_MAX 786432 #define AUTO_CLUSTERSIZE 65536 #define CLUSTERS_MAX (UINT32_MAX - 1) #define MAX_EXTALLOC_RESERVE_PERCENT 5 enum { SFI_JOURNAL, SFI_CLUSTER, SFI_LOCAL_ALLOC, SFI_HEARTBEAT, SFI_CHAIN, SFI_TRUNCATE_LOG, SFI_QUOTA, SFI_OTHER }; typedef struct _SystemFileInfo SystemFileInfo; struct _SystemFileInfo { char *name; int type; int global; int mode; }; struct BitInfo { uint32_t used_bits; uint32_t total_bits; }; typedef struct _AllocGroup AllocGroup; typedef struct _SystemFileDiskRecord SystemFileDiskRecord; typedef struct _DirData DirData; struct _AllocGroup { char *name; struct ocfs2_group_desc *gd; SystemFileDiskRecord *alloc_inode; uint32_t chain_free; uint32_t chain_total; struct _AllocGroup *next; }; struct _SystemFileDiskRecord { uint64_t fe_off; uint16_t suballoc_bit; uint64_t extent_off; uint64_t extent_len; uint64_t file_size; uint64_t chain_off; AllocGroup *group; struct BitInfo bi; struct _AllocBitmap *bitmap; int flags; int links; int mode; int cluster_bitmap; /* record the dir entry so that inline dir can be stored with file. */ DirData *dir_data; }; typedef struct _AllocBitmap AllocBitmap; struct _AllocBitmap { AllocGroup **groups; uint32_t valid_bits; uint32_t unit; uint32_t unit_bits; char *name; uint64_t fe_disk_off; SystemFileDiskRecord *bm_record; SystemFileDiskRecord *alloc_record; int num_chains; }; struct _DirData { void *buf; int last_off; SystemFileDiskRecord *record; }; typedef struct _State State; struct _State { char *progname; int verbose; int quiet; int force; int prompt; int hb_dev; int mount; int no_backup_super; int inline_data; int dx_dirs; int dry_run; uint32_t blocksize; uint32_t blocksize_bits; uint32_t cluster_size; uint32_t cluster_size_bits; uint64_t specified_size_in_blocks; uint64_t volume_size_in_bytes; uint32_t volume_size_in_clusters; uint64_t volume_size_in_blocks; uint32_t pagesize_bits; uint64_t reserved_tail_size; unsigned int initial_slots; uint64_t journal_size_in_bytes; int journal64; uint32_t extent_alloc_size_in_clusters; char *vol_label; char *device_name; unsigned char *uuid; char *cluster_stack; char *cluster_name; uint32_t vol_generation; int fd; time_t format_time; AllocBitmap *global_bm; AllocGroup *system_group; uint32_t nr_cluster_groups; uint16_t global_cpg; uint16_t tail_group_bits; uint32_t first_cluster_group; uint64_t first_cluster_group_blkno; ocfs2_fs_options feature_flags; enum ocfs2_mkfs_types fs_type; }; int ocfs2_fill_cluster_information(State *s); int ocfs2_check_volume(State *s); ./ocfs2-tools-1.6.4/mkfs.ocfs2/mkfs.ocfs2.8.in0000664000176100017610000003420111506552637015416 00000000000000.TH "mkfs.ocfs2" "8" "September 2010" "Version @VERSION@" "OCFS2 Manual Pages" .SH "NAME" mkfs.ocfs2 \- Creates an \fIOCFS2\fR file system. .SH "SYNOPSIS" \fBmkfs.ocfs2\fR [\fB\-b\fR \fIblock\-size\fR] [\fB\-C\fR \fIcluster\-size\fR] [\fB\-L\fR \fIvolume\-label\fR] [\fB\-M\fR \fImount-type\fR] [\fB\-N\fR \fInumber\-of\-nodes\fR] [\fB\-J\fR \fIjournal\-options\fR] [\fB\-\-fs\-features=\fR\fI[no]sparse...\fR] [\fB\-\-fs\-feature\-level=\fR\fIfeature\-level\fR] [\fB\-T\fR \fIfilesystem\-type\fR] [\fB\-FqvV\fR] \fIdevice\fR [\fIblocks-count\fI] .SH "DESCRIPTION" .PP \fBmkfs.ocfs2\fR is used to create an \fIOCFS2\fR file system on a \fIdevice\fR, usually a partition on a shared disk. In order to prevent data loss, \fBmkfs.ocfs2\fR will not format an existing \fIOCFS2\fR volume if it detects that it is mounted on another node in the cluster. This tool requires the cluster service to be online. .SH "OPTIONS" .TP \fB\-b, \-\-block\-size\fR \fIblock\-size\fR Valid block size values are 512, 1K, 2K and 4K bytes per block. If omitted, a value will be heuristically determined based on the expected usage of the file system (see the \fB\-T\fR option). A block size of 512 bytes is never recommended. Choose 1K, 2K or 4K. .TP \fB\-C, \-\-cluster\-size\fR \fIcluster\-size\fR Valid cluster size values are 4K, 8K, 16K, 32K, 64K, 128K, 256K, 512K and 1M. If omitted, a value will be heuristically determined based on the expected usage of the file system (see the \fB\-T\fR option). For volumes expected to store large files, like database files, while a cluster size of 128K or more is recommended, one can opt for a smaller size as long as that value is not smaller than the database block size. For others, use 4K. .TP \fB\-F, \-\-force\fR For existing \fIOCFS2\fR volumes, \fImkfs.ocfs2\fR ensures the volume is not mounted on any node in the cluster before formatting. For that to work, \fImkfs.ocfs2\fR expects the cluster service to be online. Specify this option to disable this check. .TP \fB\-J, \-\-journal-options\fR \fIoptions\fR Create the journal using options specified on the command\-line. Journal options are comma separated, and may take an argument using the equals ('=') sign. The following options are supported: .RS 1.2i .TP \fBsize\fR=\fIjournal\-size\fR Create a journal of size \fIjournal\-size\fR. Minimum size is 4M. If omitted, a value is heuristically determined based upon the file system size. .RE .RS 1.2i .TP \fBblock32\fR Use a standard 32bit journal. The journal will be able to access up to 2^32-1 blocks. This is the default. It has been the journal format for \fIOCFS2\fR volumes since the beginning. The journal is compatible with all versions of \fIOCFS2\fR. Prepending \fBno\fR is equivalent to the \fBblock64\fR journal option. .RE .RS 1.2i .TP \fBblock64\fR Use a 64bit journal. The journal will be able to access up to 2^64-1 blocks. This allows large filesystems that can extend to the theoretical limits of \fIOCFS2\fR. It requires a new-enough filesystem driver that uses the new journalled block device, \fBJBD2\fR. Prepending \fBno\fR is equivalent to the \fBblock32\fR journal option. .RE .TP \fB\-L, \-\-label\fR \fIvolume\-label\fR Set the volume label for the file system. This is useful for mounting\-by\-label. Limit the label to under 64 bytes. .TP \fB\-M, \-\-mount\fR \fImount\-type\fR Valid types are \fIlocal\fR and \fIcluster\fR. Local mount allows users to mount the volume without the cluster overhead and works only with \fIOCFS2\fR bundled with Linux kernels 2.6.20 or later. Defaults to \fIcluster\fR. .TP \fB\-N, \-\-node\-slots\fR \fInumber\-of\-node\-slots\fR Valid number ranges from 1 to 255. This number specifies the maximum number of nodes that can concurrently mount the partition. If omitted, the number defaults to 8. The number of slots can be later tuned up or down using \fItunefs.ocfs2\fR. .TP \fB\-T\fR \fIfilesystem\-type\fR Specify how the filesystem is going to be used, so that \fImkfs.ocfs2\fR can chose optimal filesystem parameters for that use. The supported filesystem types are: .RS 1.2i .TP \fBmail\fR Appropriate for file systems that will host lots of small files. .RE .RS 1.2i .TP \fBdatafiles\fR Appropriate for file systems that will host a relatively small number of very large files. .RE .RS 1.2i .TP \fBvmstore\fR Appropriate for file systems that will host Virtual machine images. .RE .TP \fB\-\-fs\-features=\fR\fR\fI[no]sparse...\fR Turn specific file system features on or off. A comma separated list of feature flags can be provided, and \fImkfs.ocfs2\fR will try to create the file system with those features set according to the list. To turn a feature on, include it in the list. To turn a feature off, prepend \fBno\fR to the name. Choices here will override individual features set via the \fB\-\-fs\-feature\-level\fR option. \fBRefer to the section titled feature compatibility before selecting specific features.\fR The following flags are supported: .RS 1.2i .TP \fBbackup-super\fR \fImkfs.ocfs2\fR, by default, makes up to 6 backup copies of the super block at offsets 1G, 4G, 16G, 64G, 256G and 1T depending on the size of the volume. This can be useful in disaster recovery. This feature is fully compatible with all versions of the file system and generally should not be disabled. .RE .RS 1.2i .TP \fBlocal\fR Create the file system as a local mount, so that it can be mounted without a cluster stack. .RE .RS 1.2i .TP \fBsparse\fR Enable support for sparse files. With this, \fIOCFS2\fR can avoid allocating (and zeroing) data to fill holes. Turn this feature on if you can, otherwise extends and some writes might be less performant. .RE .RS 1.2i .TP \fBunwritten\fR Enable unwritten extents support. With this turned on, an application can request that a range of clusters be pre-allocated within a file. \fIOCFS2\fR will mark those extents with a special flag so that expensive data zeroing doesn't have to be performed. Reads and writes to a pre-allocated region act as reads and writes to a hole, except a write will not fail due to lack of data allocation. This feature requires \fBsparse\fR file support to be turned on. .RE .RS 1.2i .TP \fBinline-data\fR Enable inline-data support. If this feature is turned on, \fIOCFS2\fR will store small files and directories inside the inode block. Data is transparently moved out to an extent when it no longer fits inside the inode block. In some cases, this can also make a positive impact on cold-cache directory and file operations. .RE .RS 1.2i .TP \fBextended-slotmap\fR The slot-map is a hidden file on an \fIOCFS2\fR fs which is used to map mounted nodes to system file resources. The extended slot map allows a larger range of possible node numbers, which is useful for userspace cluster stacks. This feature is automatically turned on when needed, thus users have no need to turn this on manually. .RE .RS 1.2i .TP \fBmetaecc\fR Enables metadata checksums. With this enabled, the file system computes and stores the checksums in all metadata blocks. It also computes and stores an error correction code capable of fixing single bit errors. .RE .RS 1.2i .TP \fBrefcount\fR Enables creation of reference counted trees. With this enabled, the file system allows users to create inode-based snapshots and clones known as \fBreflinks\fR. .RE .RS 1.2i .TP \fBxattr\fR Enable extended attributes support. With this enabled, users can attach name:value pairs to objects within the file system. In \fIOCFS2\fR, the names can be upto 255 bytes in length, terminated by the first NUL byte. While it is not required, printable names (ASCII) are recommended. The values can be upto 64KB of arbitrary binary data. Attributes can be attached to all types of inodes: regular files, directories, symbolic links, device nodes, etc. This feature is required for users wanting to use extended security facilities like POSIX ACLs or SELinux. .RE .RS 1.2i .TP \fBusrquota\fR Enable user quota support. With this feature enabled, filesystem will track amount of space and number of inodes (files, directories, symbolic links) each user owns. It is then possible to limit the maximum amount of space or inodes user can have. See a documentation of quota-tools package for more details. .RE .RS 1.2i .TP \fBgrpquota\fR Enable group quota support. With this feature enabled, filesystem will track amount of space and number of inodes (files, directories, symbolic links) each group owns. It is then possible to limit the maximum amount of space or inodes user can have. See a documentation of quota-tools package for more details. .RE .RS 1.2i .TP \fBindexed-dirs\fR Enable directory indexing support. With this feature enabled, the file system creates indexed tree for non-inline directory entries. For large scale directories, directory entry lookup perfromance from the indexed tree is faster then from the legacy directory blocks. .RE .RS 1.2i .TP \fBdiscontig-bg\fR Enables discontiguous block groups. With this feature enabled, the file system is able to grow the inode and the extent allocators even when there is no contiguous free chunk available. It allows the file system to grow the allocators in smaller (discontiguous) chunks. .RE .TP \fB\-\-fs\-feature\-level=\fR\fR\fIfeature\-level\fR Choose from a set of pre-determined file-system features. This option is designed to allow users to conveniently choose a set of file system features which fits their needs. There is no downside to trying a set of features which your module might not support - if it won't mount the new file system simply reformat at a lower level. Feature levels can be fine-tuned via the \fB\-\-fs\-features\fR option. Currently, there are 3 types of feature levels: .RS 1.2i .TP \fBmax-compat\fR Chooses fewer features but ensures that the file system can be mounted from older versions of the \fIOCFS2\fR module. .RE .RS 1.2i .TP \fBdefault\fR The default feature set tries to strike a balance between providing new features and maintaining compatibility with relatively recent versions of \fIOCFS2\fR. It currently enables \fBsparse\fR, \fBunwritten\fR \fBinline-data\fR and \fBxattr\fR. It also enables \fBrefcount\fR for the \fIvmstore\fR volumes. .RE .RS 1.2i .TP \fBmax-features\fR Choose the maximum amount of features available. This will typically provide the best performance from \fIOCFS2\fR at the expense of creating a file system that is only compatible with very recent versions of the \fIOCFS2\fR kernel module. .RE .TP \fB\-\-no-backup-super\fR This option is deprecated, please use \fB--fs-features=nobackup-super\fR instead. .TP \fB\-n, --dry-run\fR Display the heuristically determined values without overwriting the existing file system. .TP \fB\-q, \-\-quiet\fR Quiet mode. .TP \fB\-v, \-\-verbose\fR Verbose mode. .TP \fB\-V, \-\-version\fR Print version and exit. .TP \fIblocks-count\fR Usually \fBmkfs.ocfs2\fR automatically determines the size of the given device and creates a file system that uses all of the available space on the device. This optional argument specifies that the file system should only consume the given number of file system blocks (see \fB-b\fR) on the device. .SH "FEATURE COMPATIBILITY" This section lists the file system features that have been added to the \fIOCFS2\fR file system and the version that it first appeared in. The table below lists the versions of the mainline Linux kernel and that of the file system for the Enterprise Linux Distributions. Users should use this information to enable only those features that are available in the file system that they are using. Before enabling new features, users are advised to review to the section titled \fBfeature values\fR. .TS CENTER ALLBOX; LI LI LI LB C C. Feature Mainline Kernel Version Enterprise OCFS2 Version local Linux 2.6.20 OCFS2 1.2 sparse Linux 2.6.22 OCFS2 1.4 unwritten Linux 2.6.23 OCFS2 1.4 inline-data Linux 2.6.24 OCFS2 1.4 extended-slotmap Linux 2.6.27 OCFS2 1.6 metaecc Linux 2.6.29 OCFS2 1.6 grpquota Linux 2.6.29 OCFS2 1.6 usrquota Linux 2.6.29 OCFS2 1.6 xattr Linux 2.6.29 OCFS2 1.6 indexed-dirs Linux 2.6.30 OCFS2 1.6 refcount Linux 2.6.32 OCFS2 1.6 discontig-bg Linux 2.6.35 OCFS2 1.6 .TE .TS ; L. Users can query the features enabled in the file system as follows: .TE .TS ; L. [root@node1 ~]# tunefs.ocfs2 -Q "Label: %V\\nFeatures: %H %O\\n" /dev/sdg1 Label: apache_files_10 Features: sparse inline-data unwritten .TE .SH "FEATURE VALUES" This section lists the hex values that are associated with the file system features. This information is useful when debugging mount failures that are due to feature incompatibility. When a user attempts to mount an \fBOCFS2\fR volume that has features enabled that are not supported by the running file system software, it will fail with an error like: \fBERROR: couldn't mount because of unsupported optional features (200).\fR By referring to the table below, it becomes apparent that the user attempted to mount a volume with the \fIxattr\fR (extended attributes) feature enabled with a version of the file system software that did not support it. At this stage, the user has the option of either upgrading the file system software, or, disabling that on-disk feature using \fBtunefs.ocfs2\fR. Some features allow the file system to be mounted with an older version of the software provided the mount is read-only. If a user attempts to mount such a volume in a read-write mode, it will fail with an error like: \fBERROR: couldn't mount RDWR because of unsupported optional features (1).\fR This error indicates that the volume had the \fIunwritten\fR RO compat feature enabled. This volume can be mounted by an older file system software only in the read-only mode. In this case, the user has the option of either mounting the volume with the \fIro\fR mount option, or, disabling that on-disk feature using \fBtunefs.ocfs2\fR. .TS CENTER ALLBOX; LI LI LI LB C C. Feature Category Hex value local Incompat 8 sparse Incompat 10 inline-data Incompat 40 extended-slotmap Incompat 100 xattr Incompat 200 indexed-dirs Incompat 400 metaecc Incompat 800 refcount Incompat 1000 discontig-bg Incompat 2000 unwritten RO Compat 1 usrquota RO Compat 2 grpquota RO Compat 4 .TE .SH "SEE ALSO" .BR debugfs.ocfs2(8) .BR fsck.ocfs2(8) .BR tunefs.ocfs2(8) .BR mounted.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/mounted.ocfs2/0000775000176100017610000000000011515641641013532 500000000000000./ocfs2-tools-1.6.4/mounted.ocfs2/Makefile0000644000176100017610000000133311115551036015102 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2 LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm $(DL_LIBS) LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a sbindir = $(root_sbindir) SBIN_PROGRAMS = mounted.ocfs2 INCLUDES = -I$(TOPDIR)/include CFILES = mounted.c OBJS = $(subst .c,.o,$(CFILES)) MANS = mounted.ocfs2.8 DIST_FILES = $(CFILES) mounted.ocfs2.8.in mounted.ocfs2: $(OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LINK) $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) $(COM_ERR_LIBS) $(UUID_LIBS) include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/mounted.ocfs2/mounted.ocfs2.80000664000176100017610000000272311515641632016235 00000000000000.TH "mounted.ocfs2" "8" "September 2010" "Version 1.6.4" "OCFS2 Manual Pages" .SH "NAME" mounted.ocfs2 \- Detects all \fIOCFS2\fR volumes on a system. .SH "SYNOPSIS" \fBmounted.ocfs2\fR [\fB\-d\fR] [\fB\-f\fR] [\fIdevice\fR] .SH "DESCRIPTION" .PP \fBmounted.ocfs2\fR is used to detect \fIOCFS2\fR volume(s) on a system. This tool assumes that the nodes detected on the system are part of the same cluster as the one specified in \fI/etc/ocfs2/cluster.conf\fR. .SH "OPTIONS" .TP \fB\-d\fR Lists the \fIOCFS2\fR volumes along with their labels and uuids. If a device is not specified, it scans all the devices in /proc/partitions. .TP \fB\-f\fR Lists the \fIOCFS2\fR volumes along with the list of nodes that have mounted the volume. The node names are listed if the \fIO2CB\fR cluster is online. \fBNote:\fR As this information is gathered using dirty-read, the information may be stale. .SH "EXAMPLES" [root@node1 ~]# mounted.ocfs2 -d .br Device FS Stack UUID Label .br /dev/sdb1 ocfs2 local 2D1C9636FE38462DB43A75D1DA592207 vmvol .br /dev/sdj1 ocfs2 o2cb FF2E239B02D941FEAF25BDAE8DD553B9 dbstore .br [root@node1 ~]# mounted.ocfs2 -f .br Device FS Nodes .br /dev/sdb1 ocfs2 node15, node1 .br .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR fsck.ocfs2(8) .BR tunefs.ocfs2(8) .BR debugfs.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/mounted.ocfs2/mounted.c0000664000176100017610000001674411506552637015313 00000000000000/* * mounted.c * * ocfs2 mount detect utility * * Copyright (C) 2004, 2005 Oracle. All rights reserved. * * 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 021110-1307, USA. * */ #define _LARGEFILE64_SOURCE #define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */ #include #include #include #include #include #include #include #include #include #include #include #include "ocfs2-kernel/kernel-list.h" #include "ocfs2/ocfs2.h" static int quick_detect = 0; static char *device = NULL; static char *progname = NULL; static char *usage_string = "usage: %s [-d] [-f] [device]\n" " -d quick detect\n" " -f full detect\n"; static void ocfs2_print_nodes(ocfs2_devices *dev, char **names, unsigned int length_of_names) { int i, start = 1; unsigned int node_num; struct ocfs2_slot_map_data *map = dev->map; for (i = 0; i < map->md_num_slots; i++) { if (!map->md_slots[i].sd_valid) continue; if (start) start = 0; else printf(", "); node_num = map->md_slots[i].sd_node_num; if (node_num >= length_of_names) printf("Unknown"); else if (names && names[node_num] && *(names[node_num])) printf("%s", names[node_num]); else printf("%d", node_num); } } static void ocfs2_print_full_detect(struct list_head *dev_list) { ocfs2_devices *dev; struct list_head *pos; char **node_names = NULL; char **cluster_names = NULL; char *nodes[O2NM_MAX_NODES]; int i = 0; uint16_t num; memset(nodes, 0, sizeof(nodes)); o2cb_list_clusters(&cluster_names); if (cluster_names && *cluster_names) { o2cb_list_nodes(*cluster_names, &node_names); /* sort the names according to the node number */ while(node_names && node_names[i] && *(node_names[i])) { if (o2cb_get_node_num(*cluster_names, node_names[i], &num)) break; if (num >= O2NM_MAX_NODES) break; nodes[num] = node_names[i]; ++i; } } printf("%-20s %-5s %s\n", "Device", "FS", "Nodes"); list_for_each(pos, dev_list) { dev = list_entry(pos, ocfs2_devices, list); if (dev->fs_type == 0) continue; printf("%-20s %-5s ", dev->dev_name, "ocfs2"); if (dev->errcode) { fflush(stdout); com_err("Unknown", dev->errcode, " "); } else { if (dev->hb_dev) printf("Heartbeat device"); else if (dev->mount_flags & OCFS2_MF_MOUNTED_CLUSTER) ocfs2_print_nodes(dev, nodes, O2NM_MAX_NODES); else printf("Not mounted"); printf("\n"); } } if (node_names) o2cb_free_nodes_list(node_names); if (cluster_names) o2cb_free_cluster_list(cluster_names); } static void ocfs2_print_quick_detect(struct list_head *dev_list) { ocfs2_devices *dev; struct list_head *pos; char uuid[OCFS2_VOL_UUID_LEN * 2 + 1]; int i; char *p; printf("%-20s %-5s %-5s %-32s %-s\n", "Device", "FS", "Stack", "UUID", "Label"); list_for_each(pos, dev_list) { dev = list_entry(pos, ocfs2_devices, list); if (dev->fs_type == 0) continue; for (i = 0, p = uuid; i < OCFS2_VOL_UUID_LEN; i++) { snprintf(p, 3, "%02X", dev->uuid[i]); p += 2; } printf("%-20s %-5s %-5s %-32s %-s\n", dev->dev_name, (dev->fs_type == 2 ? "ocfs2" : "ocfs"), dev->stack, uuid, dev->label); } } static void scan_dir_for_dev(char *dirname, dev_t devno, char **devname) { DIR *dir; struct dirent *dp; char path[PATH_MAX]; int dirlen; struct stat st; dir = opendir(dirname); if (dir == NULL) return; dirlen = strlen(dirname) + 2; while ((dp = readdir(dir)) != 0) { if (dirlen + strlen(dp->d_name) >= sizeof(path)) continue; if (dp->d_name[0] == '.' && ((dp->d_name[1] == 0) || ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) continue; sprintf(path, "%s/%s", dirname, dp->d_name); if (stat(path, &st) < 0) continue; if (S_ISBLK(st.st_mode) && st.st_rdev == devno) { *devname = strdup(path); break; } } closedir(dir); return; } static errcode_t ocfs2_partition_list (struct list_head *dev_list) { errcode_t ret = 0; FILE *proc; char line[256]; char name[256]; char *devname = NULL; int major, minor; ocfs2_devices *dev; proc = fopen ("/proc/partitions", "r"); if (proc == NULL) { ret = OCFS2_ET_IO; goto bail; } while (fgets (line, sizeof(line), proc) != NULL) { if (sscanf(line, "%d %d %*d %99[^ \t\n]", &major, &minor, name) != 3) continue; ret = ocfs2_malloc0(sizeof(ocfs2_devices), &dev); if (ret) goto bail; /* Try to translate private device-mapper dm- names * to standard /dev/mapper/. */ if (!strncmp(name, "dm-", 3) && isdigit(name[3])) { devname = NULL; scan_dir_for_dev("/dev/mapper", makedev(major, minor), &devname); if (devname) { snprintf(dev->dev_name, sizeof(dev->dev_name), "%s", devname); free(devname); } else snprintf(dev->dev_name, sizeof(dev->dev_name), "/dev/%s", name); } else { snprintf(dev->dev_name, sizeof(dev->dev_name), "/dev/%s", name); } list_add_tail(&(dev->list), dev_list); } bail: if (proc) fclose(proc); return ret; } static void usage(char *progname) { printf(usage_string, progname); } static int read_options(int argc, char **argv) { int ret = 0; int c; progname = argv[0]; if (argc < 2) { usage(progname); ret = 1; goto bail; } while(1) { c = getopt(argc, argv, "df"); if (c == -1) break; switch (c) { case 'd': /* quick detect*/ quick_detect = 1; break; case 'f': /* full detect*/ quick_detect = 0; break; default: break; } } if (!ret && optind < argc && argv[optind]) device = argv[optind]; bail: return ret; } static errcode_t ocfs2_detect(char *device, int quick_detect) { errcode_t ret = 0; struct list_head dev_list; struct list_head *pos1, *pos2; ocfs2_devices *dev; INIT_LIST_HEAD(&(dev_list)); if (device) { ret = ocfs2_malloc0(sizeof(ocfs2_devices), &dev); if (ret) goto bail; strncpy(dev->dev_name, device, sizeof(dev->dev_name)); list_add(&(dev->list), &dev_list); } else { ret = ocfs2_partition_list(&dev_list); if (ret) { com_err(progname, ret, "while reading /proc/partitions"); goto bail; } } ret = ocfs2_check_heartbeats(&dev_list, 1); if (ret) { com_err(progname, ret, "while detecting heartbeat"); goto bail; } if (quick_detect) ocfs2_print_quick_detect(&dev_list); else ocfs2_print_full_detect(&dev_list); bail: list_for_each_safe(pos1, pos2, &(dev_list)) { dev = list_entry(pos1, ocfs2_devices, list); if (dev->map) ocfs2_free(&dev->map); list_del(&(dev->list)); ocfs2_free(&dev); } return ret; } int main(int argc, char **argv) { errcode_t ret = 0; initialize_ocfs_error_table(); initialize_o2dl_error_table(); initialize_o2cb_error_table(); ret = read_options(argc, argv); if (ret) goto bail; o2cb_init(); ret = ocfs2_detect(device, quick_detect); bail: return ret; } ./ocfs2-tools-1.6.4/mounted.ocfs2/mounted.ocfs2.8.in0000644000176100017610000000272711500500544016632 00000000000000.TH "mounted.ocfs2" "8" "September 2010" "Version @VERSION@" "OCFS2 Manual Pages" .SH "NAME" mounted.ocfs2 \- Detects all \fIOCFS2\fR volumes on a system. .SH "SYNOPSIS" \fBmounted.ocfs2\fR [\fB\-d\fR] [\fB\-f\fR] [\fIdevice\fR] .SH "DESCRIPTION" .PP \fBmounted.ocfs2\fR is used to detect \fIOCFS2\fR volume(s) on a system. This tool assumes that the nodes detected on the system are part of the same cluster as the one specified in \fI/etc/ocfs2/cluster.conf\fR. .SH "OPTIONS" .TP \fB\-d\fR Lists the \fIOCFS2\fR volumes along with their labels and uuids. If a device is not specified, it scans all the devices in /proc/partitions. .TP \fB\-f\fR Lists the \fIOCFS2\fR volumes along with the list of nodes that have mounted the volume. The node names are listed if the \fIO2CB\fR cluster is online. \fBNote:\fR As this information is gathered using dirty-read, the information may be stale. .SH "EXAMPLES" [root@node1 ~]# mounted.ocfs2 -d .br Device FS Stack UUID Label .br /dev/sdb1 ocfs2 local 2D1C9636FE38462DB43A75D1DA592207 vmvol .br /dev/sdj1 ocfs2 o2cb FF2E239B02D941FEAF25BDAE8DD553B9 dbstore .br [root@node1 ~]# mounted.ocfs2 -f .br Device FS Nodes .br /dev/sdb1 ocfs2 node15, node1 .br .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR fsck.ocfs2(8) .BR tunefs.ocfs2(8) .BR debugfs.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/tunefs.ocfs2/0000775000176100017610000000000011515641641013363 500000000000000./ocfs2-tools-1.6.4/tunefs.ocfs2/Makefile0000664000176100017610000000641011506552637014752 00000000000000TOPDIR = .. include $(TOPDIR)/Preamble.make LIBTOOLS_INTERNAL_LIBS = -L$(TOPDIR)/libtools-internal -ltools-internal LIBTOOLS_INTERNAL_DEPS = $(TOPDIR)/libtools-internal/libtools-internal.a LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2 LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm $(DL_LIBS) LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a UNINST_LIBRARIES = libocfs2ne.a OCFS2NE_FEATURES = \ feature_backup_super \ feature_discontig_bg \ feature_extended_slotmap \ feature_inline_data \ feature_local \ feature_metaecc \ feature_refcount \ feature_sparse_files \ feature_unwritten_extents \ feature_xattr \ feature_indexed_dirs \ feature_quota OCFS2NE_OPERATIONS = \ op_cloned_volume \ op_features \ op_list_sparse_files \ op_query \ op_reset_uuid \ op_resize_volume \ op_set_label \ op_set_journal_size \ op_set_slot_count \ op_update_cluster_stack \ op_set_quota_sync_interval \ sbindir = $(root_sbindir) SBIN_PROGRAMS = tunefs.ocfs2 INCLUDES = -I$(TOPDIR)/include -I. DEFINES = -DVERSION=\"$(VERSION)\" MANS = tunefs.ocfs2.8 ifneq ($(OCFS2_DEBUG_EXE),) DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES)) DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES))) .SECONDARY: UNINST_PROGRAMS += $(filter-out debug_op_features,$(DEBUG_EXE_PROGRAMS)) debug_%.o : %.c $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) \ $(INCLUDES) $(DEFINES) \ -DDEBUG_EXE -o $@ -c $< debug_op_features: debug_op_features.o $(OCFS2NE_FEATURE_OBJS) libocfs2ne.a $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LIBTOOLS_INTERNAL_DEPS) $(LINK) $(LIBOCFS2_LIBS) $(UUID_LIBS) $(LIBO2DLM_LIBS) \ $(LIBO2CB_LIBS) $(LIBTOOLS_INTERNAL_LIBS) $(COM_ERR_LIBS) debug_%: debug_%.o libocfs2ne.a $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LIBTOOLS_INTERNAL_DEPS) $(LINK) $(LIBOCFS2_LIBS) $(UUID_LIBS) $(LIBO2DLM_LIBS) \ $(LIBO2CB_LIBS) $(LIBTOOLS_INTERNAL_LIBS) $(COM_ERR_LIBS) endif LIBOCFS2NE_CFILES = libocfs2ne.c HFILES_GEN = o2ne_err.h o2ne_err.c o2ne_err.h: o2ne_err.et compile_et o2ne_err.et OCFS2NE_OPERATION_CFILES = $(patsubst %,%.c,$(OCFS2NE_OPERATIONS)) OCFS2NE_FEATURE_CFILES = $(patsubst %,%.c,$(OCFS2NE_FEATURES)) OCFS2NE_CFILES = \ ocfs2ne.c \ $(OCFS2NE_OPERATION_CFILES) \ $(OCFS2NE_FEATURE_CFILES) CFILES = $(LIBOCFS2NE_CFILES) $(OCFS2NE_CFILES) HFILES = libocfs2ne.h LIBOCFS2NE_OBJS = $(subst .c,.o,$(LIBOCFS2NE_CFILES)) o2ne_err.o OCFS2NE_OBJS = $(subst .c,.o,$(OCFS2NE_CFILES)) $(LIBOCFS2NE_OBJS): $(HFILES_GEN) $(OCFS2NE_OBJS): $(HFILES_GEN) DIST_FILES = $(CFILES) $(HFILES) tunefs.ocfs2.8.in o2ne_err.et libocfs2ne.a: $(LIBOCFS2NE_OBJS) rm -f $@ $(AR) r $@ $^ $(RANLIB) $@ ocfs2ne: $(OCFS2NE_OBJS) libocfs2ne.a $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(LIBTOOLS_INTERNAL_DEPS) $(LINK) $(LIBOCFS2_LIBS) $(UUID_LIBS) $(LIBO2DLM_LIBS) \ $(LIBO2CB_LIBS) $(LIBTOOLS_INTERNAL_LIBS) $(COM_ERR_LIBS) tunefs.ocfs2: ocfs2ne ln -f ocfs2ne tunefs.ocfs2 CLEAN_RULES += clean-err CLEAN_RULES += ocfs2ne-clean ocfs2ne-clean: rm -f ocfs2ne clean-err: rm -f o2ne_err.c o2ne_err.h include $(TOPDIR)/Postamble.make ./ocfs2-tools-1.6.4/tunefs.ocfs2/tunefs.ocfs2.80000664000176100017610000001150611515641632015716 00000000000000.TH "tunefs.ocfs2" "8" "September 2010" "Version 1.6.4" "OCFS2 Manual Pages" .SH "NAME" tunefs.ocfs2 \- Change \fIOCFS2\fR file system parameters. .SH "SYNOPSIS" \fBtunefs.ocfs2\fR [\fB\-\-cloned\-volume\fR[=\fInew-label\fR] [\fB\-\-fs\-features=\fR\fIlist\-of\-features\fR] [\fB\-J\fR \fIjournal-options\fR] [\fB\-L\fR \fIvolume-label\fR] [\fB\-N\fR \fInumber-of-node-slots\fR] [\fB\-Q\fR \fIquery-format\fR] [\fB\-ipqnSUvVy\fR] [\fB\-\-backup-super\fR] [\fB\-\-list\-sparse\fR] \fIdevice\fR [\fIblocks-count\fR] .SH "DESCRIPTION" .PP \fBtunefs.ocfs2\fR is used to adjust \fIOCFS2\fR file system parameters on disk. The tool expects the cluster to be online as it needs to take the appropriate cluster locks to write safely to disk. .SH "OPTIONS" .TP \fB\-\-cloned\-volume\fR[=\fInew-label]\fR Change the volume UUID (auto-generated) and the label, if provided, of a cloned \fIOCFS2\fR volume. This option does \fBnot\fR perform volume cloning. It only changes the UUID and label on a cloned volume so that it can be mounted on the node that has the original volume mounted. .TP \fB\-\-fs\-features=\fR\fI[no]sparse...\fR Turn specific file system features on or off. \fItunefs.ocfs2\fR will attempt to enable or disable the feature list provided. To enable a feature, include it in the list. To disable a feature, prepend \fBno\fR to the name. For a list of feature names, see the man page for \fBmkfs.ocfs2\fR. .TP \fB\-J, \-\-journal\-options\fR \fIoptions\fR Modify the journal using options specified on the command\-line. Journal options are comma separated, and may take an argument using the equals ('=') sign. For a list of possible options, see the man page for \fBmkfs.ocfs2\fR. .TP \fB\-L, \-\-label\fR \fIvolume\-label\fR Change the volume label of the file system. Limit the label to under 64 bytes. .TP \fB\-N, \-\-node\-slots\fR \fInumber\-of\-node\-slots\fR Valid number ranges from 1 to 255. This number specifies the maximum number of nodes that can concurrently mount the partition. Use this to increase or decrease the number of node slots. One reason to decrease could be to release the space consumed by the journals for those slots. .TP \fB\-S, \-\-volume\-size\fR Grow the size of the \fIOCFS2\fR file system. If \fIblocks-count\fR is not specified, \fItunefs.ocfs2\fR extends the volume to the current size of the device. .TP \fB\-Q, \-\-query\fR \fIquery\-format\fR Query the file system for its attributes like block size, label, etc. Query formats are modified versions of the standard printf(3) formatting. The format is made up of static strings (which may include standard C character escapes for newlines, tabs, and other special characters) and printf(3) type formatters. The list of type specifiers is as follows: .RS 1.2i .TP \fBB\fR Block size in bytes .TP \fBT\fR Cluster size in bytes .TP \fBN\fR Number of node slots .TP \fBR\fR Root directory block number .TP \fBY\fR System directory block number .TP \fBP\fR First cluster group block number .TP \fBV\fR Volume label .TP \fBU\fR Volume uuid .TP \fBM\fR Compat flags .TP \fBH\fR Incompat flags .TP \fBO\fR RO Compat flags .RE .TP \fB\-q, \-\-quiet\fR Quiet mode. .TP \fB\-U, \-\-uuid\-reset\fR[=\fInew-uuid]\fR Set the volume UUID for the file system. If not provided, will auto generate a new UUID. The format of the provided UUID should be 178BDC83D50241EF94EB474A677D498B or 178BDC83-D502-41EF-94EB-474A677D498B. .TP \fB\-v, \-\-verbose\fR Verbose mode. .TP \fB\-V, \-\-version\fR Show version and exit. .TP \fB\-y, \-\-yes\fR Always answer Yes in interactive command line. .TP \fB\-n, \-\-no\fR Always answer No in interactive command line. .TP \fB\-\-backup\-super\fR Backs up the superblock to fixed offsets (1G, 4G, 16G, 64G, 256G and 1T) on disk. This option is useful for users to backup the superblock on volumes that the user either explicitly disallowed while formatting, or, used a version of \fImkfs.ocfs2\fR (1.2.2 or older) that did not provide this facility. .TP \fB\-\-list-sparse\fR Lists the files having holes. This option is useful when disabling the \fIsparse\fR feature. .TP \fB\-\-update-cluster-stack\fR Updating on-disk cluster information to match the running cluster. .TP \fIblocks-count\fR During resize, \fItunefs.ocfs2\fR automatically determines the size of the given device and grows the file system such that it uses all of the available space on the device. This optional argument specifies that the file system should be extended to consume only the given number of file system blocks on the device. .SH "EXAMPLES" [root@node1 ~]# tunefs.ocfs2 -Q "UUID = %U\\nNumSlots = %N\\n" /dev/sda1 .br UUID = CBB8D5E0C169497C8B52A0FD555C7A3E .br NumSlots = 4 .br .SH "SEE ALSO" .BR mkfs.ocfs2(8) .BR fsck.ocfs2(8) .BR debugfs.ocfs2(8) .BR mounted.ocfs2(8) .BR ocfs2console(8) .BR o2cb(7) .SH "AUTHORS" Oracle Corporation .SH "COPYRIGHT" Copyright \(co 2004, 2010 Oracle. All rights reserved. ./ocfs2-tools-1.6.4/tunefs.ocfs2/libocfs2ne.c0000644000176100017610000016436511515637016015513 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * libocfs2ne.c * * Shared routines for the ocfs2 tunefs utility * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #define _LARGEFILE64_SOURCE #define _GNU_SOURCE /* for getopt_long and O_DIRECT */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "ocfs2/bitops.h" #include "libocfs2ne.h" #define WHOAMI "tunefs.ocfs2" /* * Keeps track of how ocfs2ne sees the filesystem. This structure is * filled in by the master ocfs2_filesys (the first caller to * tunefs_open()). Every other ocfs2_filesys refers to it. */ struct tunefs_filesystem_state { /* The master ocfs2_filesys (first tunefs_open()) */ ocfs2_filesys *ts_master; /* * When a single-node (local) filesystem is opened, we prevent * concurrent mount(2) by opening the device O_EXCL. This is the * fd we used. The value is -1 for cluster-aware filesystems. */ int ts_local_fd; /* * Already-mounted filesystems can only do online operations. * This is the fd we send ioctl(2)s to. If the filesystem isn't * in use, this is -1. */ int ts_online_fd; /* * Do we have the cluster locked? This can be zero if we're a * local filesystem. If it is non-zero, ts_master->fs_dlm_ctxt * must be valid. */ int ts_cluster_locked; /* Non-zero if we've ever mucked with the allocator */ int ts_allocation; /* * Number of clusters in the filesystem. If changed by a * resized filesystem, it is tracked here and used at final * close. */ uint32_t ts_fs_clusters; /* Size of the largest journal seen in tunefs_journal_check() */ uint32_t ts_journal_clusters; /* Journal feature bits found during tunefs_journal_check() */ ocfs2_fs_options ts_journal_features; }; struct tunefs_private { struct list_head tp_list; ocfs2_filesys *tp_fs; /* All tunefs_privates point to the master state. */ struct tunefs_filesystem_state *tp_state; /* Flags passed to tunefs_open() for this ocfs2_filesys */ int tp_open_flags; }; /* List of all ocfs2_filesys objects opened by tunefs_open() */ static LIST_HEAD(fs_list); /* Refcount for calls to tunefs_[un]block_signals() */ static unsigned int blocked_signals_count; /* For DEBUG_EXE programs */ static const char *usage_string; /* * Code to manage the fs_private state. */ static inline struct tunefs_private *to_private(ocfs2_filesys *fs) { return fs->fs_private; } static struct tunefs_filesystem_state *tunefs_get_master_state(void) { struct tunefs_filesystem_state *s = NULL; struct tunefs_private *tp; if (!list_empty(&fs_list)) { tp = list_entry(fs_list.prev, struct tunefs_private, tp_list); s = tp->tp_state; } return s; } static struct tunefs_filesystem_state *tunefs_get_state(ocfs2_filesys *fs) { struct tunefs_private *tp = to_private(fs); return tp->tp_state; } static errcode_t tunefs_set_state(ocfs2_filesys *fs) { errcode_t err = 0; struct tunefs_private *tp = to_private(fs); struct tunefs_filesystem_state *s = tunefs_get_master_state(); if (!s) { err = ocfs2_malloc0(sizeof(struct tunefs_filesystem_state), &s); if (!err) { s->ts_local_fd = -1; s->ts_online_fd = -1; s->ts_master = fs; s->ts_fs_clusters = fs->fs_clusters; } else s = NULL; } tp->tp_state = s; return err; } /* * Functions for use by operations. */ /* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock */ static void block_signals(int how) { sigset_t sigs; sigfillset(&sigs); sigdelset(&sigs, SIGTRAP); sigdelset(&sigs, SIGSEGV); sigprocmask(how, &sigs, NULL); } void tunefs_block_signals(void) { if (!blocked_signals_count) block_signals(SIG_BLOCK); blocked_signals_count++; } void tunefs_unblock_signals(void) { if (blocked_signals_count) { blocked_signals_count--; if (!blocked_signals_count) block_signals(SIG_UNBLOCK); } else errorf("Trying to unblock signals, but signals were not " "blocked\n"); } errcode_t tunefs_dlm_lock(ocfs2_filesys *fs, const char *lockid, int flags, enum o2dlm_lock_level level) { struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (ocfs2_mount_local(fs)) return 0; return o2dlm_lock(state->ts_master->fs_dlm_ctxt, lockid, flags, level); } errcode_t tunefs_dlm_unlock(ocfs2_filesys *fs, char *lockid) { struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (ocfs2_mount_local(fs)) return 0; return o2dlm_unlock(state->ts_master->fs_dlm_ctxt, lockid); } errcode_t tunefs_online_ioctl(ocfs2_filesys *fs, int op, void *arg) { int rc; struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (state->ts_online_fd < 0) return TUNEFS_ET_INTERNAL_FAILURE; rc = ioctl(state->ts_online_fd, op, arg); if (rc) { switch (errno) { case EBADF: case EFAULT: return TUNEFS_ET_INTERNAL_FAILURE; break; case ENOTTY: return TUNEFS_ET_ONLINE_NOT_SUPPORTED; break; default: return TUNEFS_ET_ONLINE_FAILED; break; } } return 0; } errcode_t tunefs_get_number(char *arg, uint64_t *res) { char *ptr = NULL; uint64_t num; num = strtoull(arg, &ptr, 0); if ((ptr == arg) || (num == UINT64_MAX)) return TUNEFS_ET_INVALID_NUMBER; switch (*ptr) { case '\0': break; case 'p': case 'P': num *= 1024; /* FALL THROUGH */ case 't': case 'T': num *= 1024; /* FALL THROUGH */ case 'g': case 'G': num *= 1024; /* FALL THROUGH */ case 'm': case 'M': num *= 1024; /* FALL THROUGH */ case 'k': case 'K': num *= 1024; /* FALL THROUGH */ case 'b': case 'B': break; default: return TUNEFS_ET_INVALID_NUMBER; } *res = num; return 0; } errcode_t tunefs_set_in_progress(ocfs2_filesys *fs, int flag) { /* RESIZE is a special case due for historical reasons */ if (flag == OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG) { OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat |= OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG; } else { OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat |= OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG; OCFS2_RAW_SB(fs->fs_super)->s_tunefs_flag |= flag; } return ocfs2_write_primary_super(fs); } errcode_t tunefs_clear_in_progress(ocfs2_filesys *fs, int flag) { /* RESIZE is a special case due for historical reasons */ if (flag == OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG) { OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat &= ~OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG; } else { OCFS2_RAW_SB(fs->fs_super)->s_tunefs_flag &= ~flag; if (OCFS2_RAW_SB(fs->fs_super)->s_tunefs_flag == 0) OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat &= ~OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG; } return ocfs2_write_primary_super(fs); } errcode_t tunefs_set_journal_size(ocfs2_filesys *fs, uint64_t new_size) { errcode_t ret = 0; char jrnl_file[OCFS2_MAX_FILENAME_LEN]; uint64_t blkno; int i; int max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; uint32_t num_clusters; char *buf = NULL; struct ocfs2_dinode *di; struct tunefs_filesystem_state *state = tunefs_get_state(fs); struct tools_progress *prog; num_clusters = ocfs2_clusters_in_blocks(fs, ocfs2_blocks_in_bytes(fs, new_size)); /* If no size was passed in, use the size we found at open() */ if (!num_clusters) num_clusters = state->ts_journal_clusters; /* * This can't come from a NOCLUSTER operation, so we'd better * have a size in ts_journal_clusters */ assert(num_clusters); ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { verbosef(VL_LIB, "%s while allocating inode buffer for journal " "resize\n", error_message(ret)); return ret; } prog = tools_progress_start("Setting journal size", "jsize", max_slots); if (!prog) { ret = TUNEFS_ET_NO_MEMORY; verbosef(VL_LIB, "%s while initializing progress display for " "journal resize\n", error_message(ret)); return ret; } for (i = 0; i < max_slots; ++i) { ocfs2_sprintf_system_inode_name(jrnl_file, OCFS2_MAX_FILENAME_LEN, JOURNAL_SYSTEM_INODE, i); ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i, &blkno); if (ret) { verbosef(VL_LIB, "%s while looking up \"%s\" during " "journal resize\n", error_message(ret), jrnl_file); goto bail; } ret = ocfs2_read_inode(fs, blkno, buf); if (ret) { verbosef(VL_LIB, "%s while reading journal inode " "%"PRIu64" for resizing\n", error_message(ret), blkno); goto bail; } di = (struct ocfs2_dinode *)buf; if (num_clusters == di->i_clusters) { tools_progress_step(prog, 1); continue; } verbosef(VL_LIB, "Resizing journal \"%s\" to %"PRIu32" clusters\n", jrnl_file, num_clusters); ret = ocfs2_make_journal(fs, blkno, num_clusters, &state->ts_journal_features); if (ret) { verbosef(VL_LIB, "%s while resizing \"%s\" at block " "%"PRIu64" to %"PRIu32" clusters\n", error_message(ret), jrnl_file, blkno, num_clusters); goto bail; } verbosef(VL_LIB, "Successfully resized journal \"%s\"\n", jrnl_file); tools_progress_step(prog, 1); } bail: tools_progress_stop(prog); if (buf) ocfs2_free(&buf); return ret; } errcode_t tunefs_empty_clusters(ocfs2_filesys *fs, uint64_t start_blk, uint32_t num_clusters) { errcode_t ret; char *buf = NULL; uint64_t bpc = ocfs2_clusters_to_blocks(fs, 1); uint64_t total_blocks = ocfs2_clusters_to_blocks(fs, num_clusters); uint64_t io_blocks = total_blocks; ret = ocfs2_malloc_blocks(fs->fs_io, io_blocks, &buf); if (ret == OCFS2_ET_NO_MEMORY) { io_blocks = bpc; ret = ocfs2_malloc_blocks(fs->fs_io, io_blocks, &buf); } if (ret) goto bail; memset(buf, 0, io_blocks * fs->fs_blocksize); while (total_blocks) { ret = io_write_block_nocache(fs->fs_io, start_blk, io_blocks, buf); if (ret) goto bail; total_blocks -= io_blocks; start_blk += io_blocks; } bail: if (buf) ocfs2_free(&buf); return ret; } errcode_t tunefs_get_free_clusters(ocfs2_filesys *fs, uint32_t *clusters) { errcode_t ret; uint64_t blkno; char *buf = NULL; struct ocfs2_dinode *di = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &blkno); if (ret) goto bail; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto bail; di = (struct ocfs2_dinode *)buf; if (clusters) *clusters = di->id1.bitmap1.i_total - di->id1.bitmap1.i_used; bail: if (buf) ocfs2_free(&buf); return ret; } static errcode_t tunefs_validate_inode(ocfs2_filesys *fs, struct ocfs2_dinode *di) { if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE, strlen(OCFS2_INODE_SIGNATURE))) return OCFS2_ET_BAD_INODE_MAGIC; ocfs2_swap_inode_to_cpu(fs, di); if (di->i_fs_generation != fs->fs_super->i_fs_generation) return OCFS2_ET_INODE_NOT_VALID; if (!(di->i_flags & OCFS2_VALID_FL)) return OCFS2_ET_INODE_NOT_VALID; return 0; } errcode_t tunefs_foreach_inode(ocfs2_filesys *fs, errcode_t (*func)(ocfs2_filesys *fs, struct ocfs2_dinode *di, void *user_data), void *user_data) { errcode_t ret; uint64_t blkno; char *buf; struct ocfs2_dinode *di; ocfs2_inode_scan *scan; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { verbosef(VL_LIB, "%s while allocating a buffer for inode scanning\n", error_message(ret)); goto out; } di = (struct ocfs2_dinode *)buf; ret = ocfs2_open_inode_scan(fs, &scan); if (ret) { verbosef(VL_LIB, "%s while opening inode scan\n", error_message(ret)); goto out_free; } for(;;) { ret = ocfs2_get_next_inode(scan, &blkno, buf); if (ret) { verbosef(VL_LIB, "%s while getting next inode\n", error_message(ret)); break; } if (blkno == 0) break; ret = tunefs_validate_inode(fs, di); if (ret) continue; if (func) { ret = func(fs, di, user_data); if (ret) break; } } ocfs2_close_inode_scan(scan); out_free: ocfs2_free(&buf); out: return ret; } /* A dirblock we have to add a trailer to */ struct tunefs_trailer_dirblock { struct list_head db_list; uint64_t db_blkno; char *db_buf; /* * These require a little explanation. They point to * ocfs2_dir_entry structures inside db_buf. * * db_last is the entry we're going to *keep*. If the last * entry in the dirblock has enough extra rec_len to allow the * trailer, db_last points to it. We will shorten its rec_len * and insert the trailer. * * However, if the last entry in the dirblock cannot be * truncated, db_last points to the entry before that - the * last entry we're keeping in this dirblock. * * Examples: * * - The last entry in the dirblock has a name_len of 1 and a * rec_len of 128. We can easily change the rec_len to 64 and * insert the trailer. db_last points to this entry. * * - The last entry in the dirblock has a name_len of 1 and a * rec_len of 48. The previous entry has a name_len of 1 and a * rec_len of 32. We have to move the last entry out. The * second-to-last entry can have its rec_len truncated to 16, so * we put it in db_last. */ struct ocfs2_dir_entry *db_last; }; void tunefs_trailer_context_free(struct tunefs_trailer_context *tc) { struct tunefs_trailer_dirblock *db; struct list_head *n, *pos; if (!list_empty(&tc->d_list)) list_del(&tc->d_list); list_for_each_safe(pos, n, &tc->d_dirblocks) { db = list_entry(pos, struct tunefs_trailer_dirblock, db_list); list_del(&db->db_list); ocfs2_free(&db->db_buf); ocfs2_free(&db); } ocfs2_free(&tc); } /* * We're calculating how many bytes we need to add to make space for * the dir trailers. But we need to make sure that the added directory * blocks also have room for a trailer. */ static void add_bytes_needed(ocfs2_filesys *fs, struct tunefs_trailer_context *tc, unsigned int rec_len) { unsigned int toff = ocfs2_dir_trailer_blk_off(fs); unsigned int block_offset = tc->d_bytes_needed % fs->fs_blocksize; /* * If the current byte offset would put us into a trailer, push * it out to the start of the next block. Remember, dirents have * to be at least 16 bytes, which is why we check against the * smallest rec_len. */ if ((block_offset + rec_len) > (toff - OCFS2_DIR_REC_LEN(1))) tc->d_bytes_needed += fs->fs_blocksize - block_offset; tc->d_bytes_needed += rec_len; tc->d_blocks_needed = ocfs2_blocks_in_bytes(fs, tc->d_bytes_needed); } static errcode_t walk_dirblock(ocfs2_filesys *fs, struct tunefs_trailer_context *tc, struct tunefs_trailer_dirblock *db) { errcode_t ret = 0; struct ocfs2_dir_entry *dirent, *prev = NULL; unsigned int real_rec_len; unsigned int offset = 0; unsigned int toff = ocfs2_dir_trailer_blk_off(fs); while (offset < fs->fs_blocksize) { dirent = (struct ocfs2_dir_entry *) (db->db_buf + offset); if (((offset + dirent->rec_len) > fs->fs_blocksize) || (dirent->rec_len < 8) || ((dirent->rec_len % 4) != 0) || (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { ret = OCFS2_ET_DIR_CORRUPTED; break; } real_rec_len = dirent->inode ? OCFS2_DIR_REC_LEN(dirent->name_len) : OCFS2_DIR_REC_LEN(1); if ((offset + real_rec_len) <= toff) goto next; /* * The first time through, we store off the last dirent * before the trailer. */ if (!db->db_last) db->db_last = prev; /* Only live dirents need to be moved */ if (dirent->inode) { verbosef(VL_DEBUG, "Will move dirent %.*s out of " "directory block %"PRIu64" to make way " "for the trailer\n", dirent->name_len, dirent->name, db->db_blkno); add_bytes_needed(fs, tc, real_rec_len); } next: prev = dirent; offset += dirent->rec_len; } /* There were no dirents across the boundary */ if (!db->db_last) db->db_last = prev; return ret; } static int dirblock_scan_iterate(ocfs2_filesys *fs, uint64_t blkno, uint64_t bcount, uint16_t ext_flags, void *priv_data) { errcode_t ret = 0; struct tunefs_trailer_dirblock *db = NULL; struct tunefs_trailer_context *tc = priv_data; ret = ocfs2_malloc0(sizeof(struct tunefs_trailer_dirblock), &db); if (ret) goto out; ret = ocfs2_malloc_block(fs->fs_io, &db->db_buf); if (ret) goto out; db->db_blkno = blkno; verbosef(VL_DEBUG, "Reading dinode %"PRIu64" dirblock %"PRIu64" at block " "%"PRIu64"\n", tc->d_di->i_blkno, bcount, blkno); ret = ocfs2_read_dir_block(fs, tc->d_di, blkno, db->db_buf); if (ret) goto out; ret = walk_dirblock(fs, tc, db); if (ret) goto out; list_add_tail(&db->db_list, &tc->d_dirblocks); db = NULL; out: if (db) { if (db->db_buf) ocfs2_free(&db->db_buf); ocfs2_free(&db); } if (ret) { tc->d_err = ret; return OCFS2_BLOCK_ABORT; } return 0; } errcode_t tunefs_prepare_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct tunefs_trailer_context **tc_ret) { errcode_t ret = 0; struct tunefs_trailer_context *tc = NULL; if (ocfs2_dir_has_trailer(fs, di)) goto out; ret = ocfs2_malloc0(sizeof(struct tunefs_trailer_context), &tc); if (ret) goto out; tc->d_blkno = di->i_blkno; tc->d_di = di; INIT_LIST_HEAD(&tc->d_list); INIT_LIST_HEAD(&tc->d_dirblocks); ret = ocfs2_block_iterate_inode(fs, tc->d_di, 0, dirblock_scan_iterate, tc); if (!ret) ret = tc->d_err; if (ret) goto out; *tc_ret = tc; tc = NULL; out: if (tc) tunefs_trailer_context_free(tc); return ret; } /* * We are hand-coding the directory expansion because we're going to * build the new directory blocks ourselves. We can't just use * ocfs2_expand_dir() and ocfs2_link(), because we're moving around * entries. */ static errcode_t expand_dir_if_needed(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t blocks_needed) { errcode_t ret = 0; uint64_t used_blocks, total_blocks; uint32_t clusters_needed; /* This relies on the fact that i_size of a directory is a * multiple of blocksize */ used_blocks = ocfs2_blocks_in_bytes(fs, di->i_size); total_blocks = ocfs2_clusters_to_blocks(fs, di->i_clusters); if ((used_blocks + blocks_needed) <= total_blocks) goto out; clusters_needed = ocfs2_clusters_in_blocks(fs, (used_blocks + blocks_needed) - total_blocks); ret = ocfs2_extend_allocation(fs, di->i_blkno, clusters_needed); if (ret) goto out; /* Pick up changes to the inode */ ret = ocfs2_read_inode(fs, di->i_blkno, (char *)di); out: return ret; } static void shift_dirent(ocfs2_filesys *fs, struct tunefs_trailer_context *tc, struct ocfs2_dir_entry *dirent) { /* Using the real rec_len */ unsigned int rec_len = OCFS2_DIR_REC_LEN(dirent->name_len); unsigned int offset, remain; /* * If the current byte offset would put us into a trailer, push * it out to the start of the next block. Remember, dirents have * to be at least 16 bytes, which is why we check against the * smallest rec_len. */ if (rec_len > (tc->d_next_dirent->rec_len - OCFS2_DIR_REC_LEN(1))) { tc->d_cur_block += fs->fs_blocksize; tc->d_next_dirent = (struct ocfs2_dir_entry *)tc->d_cur_block; } assert(ocfs2_blocks_in_bytes(fs, tc->d_cur_block - tc->d_new_blocks) < tc->d_blocks_needed); offset = (char *)(tc->d_next_dirent) - tc->d_cur_block; remain = tc->d_next_dirent->rec_len - rec_len; memcpy(tc->d_cur_block + offset, dirent, rec_len); tc->d_next_dirent->rec_len = rec_len; verbosef(VL_DEBUG, "Installed dirent %.*s at offset %u of new block " "%"PRIu64", rec_len %u\n", tc->d_next_dirent->name_len, tc->d_next_dirent->name, offset, ocfs2_blocks_in_bytes(fs, tc->d_cur_block - tc->d_new_blocks), rec_len); offset += rec_len; tc->d_next_dirent = (struct ocfs2_dir_entry *)(tc->d_cur_block + offset); tc->d_next_dirent->rec_len = remain; verbosef(VL_DEBUG, "New block %"PRIu64" has its last dirent at %u, with %u " "bytes left\n", ocfs2_blocks_in_bytes(fs, tc->d_cur_block - tc->d_new_blocks), offset, remain); } static errcode_t fixup_dirblock(ocfs2_filesys *fs, struct tunefs_trailer_context *tc, struct tunefs_trailer_dirblock *db) { errcode_t ret = 0; struct ocfs2_dir_entry *dirent; unsigned int real_rec_len; unsigned int offset; unsigned int toff = ocfs2_dir_trailer_blk_off(fs); /* * db_last is the last dirent we're *keeping*. So we need to * move out every valid dirent *after* db_last. * * tunefs_prepare_dir_trailer() should have calculated this * correctly. */ offset = ((char *)db->db_last) - db->db_buf; offset += db->db_last->rec_len; while (offset < fs->fs_blocksize) { dirent = (struct ocfs2_dir_entry *) (db->db_buf + offset); if (((offset + dirent->rec_len) > fs->fs_blocksize) || (dirent->rec_len < 8) || ((dirent->rec_len % 4) != 0) || (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { ret = OCFS2_ET_DIR_CORRUPTED; break; } real_rec_len = dirent->inode ? OCFS2_DIR_REC_LEN(dirent->name_len) : OCFS2_DIR_REC_LEN(1); assert((offset + real_rec_len) > toff); /* Only live dirents need to be moved */ if (dirent->inode) { verbosef(VL_DEBUG, "Moving dirent %.*s out of directory " "block %"PRIu64" to make way for the " "trailer\n", dirent->name_len, dirent->name, db->db_blkno); shift_dirent(fs, tc, dirent); } offset += dirent->rec_len; } /* * Now that we've moved any dirents out of the way, we need to * fix up db_last and install the trailer. */ offset = ((char *)db->db_last) - db->db_buf; verbosef(VL_DEBUG, "Last valid dirent of directory block %"PRIu64" " "(\"%.*s\") is %u bytes in. Setting rec_len to %u and " "installing the trailer\n", db->db_blkno, db->db_last->name_len, db->db_last->name, offset, toff - offset); db->db_last->rec_len = toff - offset; ocfs2_init_dir_trailer(fs, tc->d_di, db->db_blkno, db->db_buf); return ret; } static errcode_t run_dirblocks(ocfs2_filesys *fs, struct tunefs_trailer_context *tc) { errcode_t ret = 0; struct list_head *pos; struct tunefs_trailer_dirblock *db; list_for_each(pos, &tc->d_dirblocks) { db = list_entry(pos, struct tunefs_trailer_dirblock, db_list); ret = fixup_dirblock(fs, tc, db); if (ret) break; } return ret; } static errcode_t write_dirblocks(ocfs2_filesys *fs, struct tunefs_trailer_context *tc) { errcode_t ret = 0; struct list_head *pos; struct tunefs_trailer_dirblock *db; list_for_each(pos, &tc->d_dirblocks) { db = list_entry(pos, struct tunefs_trailer_dirblock, db_list); ret = ocfs2_write_dir_block(fs, tc->d_di, db->db_blkno, db->db_buf); if (ret) { verbosef(VL_DEBUG, "Error writing dirblock %"PRIu64"\n", db->db_blkno); break; } } return ret; } static errcode_t init_new_dirblocks(ocfs2_filesys *fs, struct tunefs_trailer_context *tc) { int i; errcode_t ret; uint64_t blkno; uint64_t orig_block = ocfs2_blocks_in_bytes(fs, tc->d_di->i_size); ocfs2_cached_inode *cinode; char *blockptr; struct ocfs2_dir_entry *first; ret = ocfs2_read_cached_inode(fs, tc->d_blkno, &cinode); if (ret) goto out; assert(!memcmp(tc->d_di, cinode->ci_inode, fs->fs_blocksize)); for (i = 0; i < tc->d_blocks_needed; i++) { ret = ocfs2_extent_map_get_blocks(cinode, orig_block + i, 1, &blkno, NULL, NULL); if (ret) goto out; blockptr = tc->d_new_blocks + (i * fs->fs_blocksize); memset(blockptr, 0, fs->fs_blocksize); first = (struct ocfs2_dir_entry *)blockptr; first->rec_len = ocfs2_dir_trailer_blk_off(fs); ocfs2_init_dir_trailer(fs, tc->d_di, blkno, blockptr); } out: return ret; } static errcode_t write_new_dirblocks(ocfs2_filesys *fs, struct tunefs_trailer_context *tc) { int i; errcode_t ret; uint64_t blkno; uint64_t orig_block = ocfs2_blocks_in_bytes(fs, tc->d_di->i_size); ocfs2_cached_inode *cinode; char *blockptr; ret = ocfs2_read_cached_inode(fs, tc->d_blkno, &cinode); if (ret) goto out; assert(!memcmp(tc->d_di, cinode->ci_inode, fs->fs_blocksize)); for (i = 0; i < tc->d_blocks_needed; i++) { ret = ocfs2_extent_map_get_blocks(cinode, orig_block + i, 1, &blkno, NULL, NULL); if (ret) goto out; blockptr = tc->d_new_blocks + (i * fs->fs_blocksize); ret = ocfs2_write_dir_block(fs, tc->d_di, blkno, blockptr); if (ret) { verbosef(VL_DEBUG, "Error writing dirblock %"PRIu64"\n", blkno); goto out; } } out: return ret; } errcode_t tunefs_install_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, struct tunefs_trailer_context *tc) { errcode_t ret = 0; struct tunefs_trailer_context *our_tc = NULL; if ((di->i_dyn_features & OCFS2_INLINE_DATA_FL) || ocfs2_dir_has_trailer(fs, di)) goto out; if (!tc) { ret = tunefs_prepare_dir_trailer(fs, di, &our_tc); if (ret) goto out; tc = our_tc; } if (tc->d_di != di) { ret = OCFS2_ET_INVALID_ARGUMENT; goto out; } if (tc->d_blocks_needed) { ret = ocfs2_malloc_blocks(fs->fs_io, tc->d_blocks_needed, &tc->d_new_blocks); if (ret) goto out; tc->d_cur_block = tc->d_new_blocks; ret = expand_dir_if_needed(fs, di, tc->d_blocks_needed); if (ret) goto out; ret = init_new_dirblocks(fs, tc); if (ret) goto out; tc->d_next_dirent = (struct ocfs2_dir_entry *)tc->d_cur_block; verbosef(VL_DEBUG, "t_next_dirent has rec_len of %u\n", tc->d_next_dirent->rec_len); } ret = run_dirblocks(fs, tc); if (ret) goto out; /* * We write in a specific order. We write any new dirblocks first * so that they are on disk. Then we write the new i_size in the * inode. If we crash at this point, the directory has duplicate * entries but no lost entries. fsck can clean it up. Finally, we * write the modified dirblocks with trailers. */ if (tc->d_blocks_needed) { ret = write_new_dirblocks(fs, tc); if (ret) goto out; di->i_size += ocfs2_blocks_to_bytes(fs, tc->d_blocks_needed); ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (ret) goto out; } ret = write_dirblocks(fs, tc); out: if (our_tc) tunefs_trailer_context_free(our_tc); return ret; } /* * Starting, opening, closing, and exiting. */ static void tunefs_close_all(void) { struct list_head *pos, *n; struct tunefs_private *tp; list_for_each_safe(pos, n, &fs_list) { tp = list_entry(pos, struct tunefs_private, tp_list); tunefs_close(tp->tp_fs); } } static void handle_signal(int caught_sig) { int exitp = 0, abortp = 0; static int segv_already = 0; switch (caught_sig) { case SIGQUIT: abortp = 1; /* FALL THROUGH */ case SIGTERM: case SIGINT: case SIGHUP: errorf("Caught signal %d, exiting\n", caught_sig); exitp = 1; break; case SIGSEGV: errorf("Segmentation fault, exiting\n"); exitp = 1; if (segv_already) { errorf("Segmentation fault loop detected\n"); abortp = 1; } else segv_already = 1; break; default: errorf("Caught signal %d, ignoring\n", caught_sig); break; } if (!exitp) return; if (abortp) abort(); tunefs_close_all(); exit(1); } static int setup_signals(void) { int rc = 0; struct sigaction act; act.sa_sigaction = NULL; sigemptyset(&act.sa_mask); act.sa_handler = handle_signal; #ifdef SA_INTERRUPT act.sa_flags = SA_INTERRUPT; #endif rc += sigaction(SIGTERM, &act, NULL); rc += sigaction(SIGINT, &act, NULL); rc += sigaction(SIGHUP, &act, NULL); rc += sigaction(SIGQUIT, &act, NULL); rc += sigaction(SIGSEGV, &act, NULL); act.sa_handler = SIG_IGN; rc += sigaction(SIGPIPE, &act, NULL); /* Get EPIPE instead */ return rc; } void tunefs_init(const char *argv0) { initialize_o2ne_error_table(); initialize_ocfs_error_table(); initialize_o2dl_error_table(); initialize_o2cb_error_table(); tools_setup_argv0(argv0); setbuf(stdout, NULL); setbuf(stderr, NULL); if (setup_signals()) { errorf("%s\n", error_message(TUNEFS_ET_SIGNALS_FAILED)); exit(1); } } /* * Single-node filesystems need to prevent mount(8) from happening * while tunefs.ocfs2 is running. bd_claim does this for us when we * open O_EXCL. */ static errcode_t tunefs_lock_local(ocfs2_filesys *fs, int flags) { errcode_t err = 0; int mount_flags; int rc; struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (state->ts_local_fd > -1) return 0; rc = open64(fs->fs_devname, O_RDWR | O_EXCL); if (rc < 0) { if (errno == EBUSY) { /* bd_claim has a hold, let's see if it's ocfs2 */ err = ocfs2_check_if_mounted(fs->fs_devname, &mount_flags); if (!err) { if (!(mount_flags & OCFS2_MF_MOUNTED) || (mount_flags & OCFS2_MF_READONLY) || (mount_flags & OCFS2_MF_SWAP) || !(flags & TUNEFS_FLAG_ONLINE)) err = TUNEFS_ET_DEVICE_BUSY; else err = TUNEFS_ET_PERFORM_ONLINE; } } else if (errno == ENOENT) err = OCFS2_ET_NAMED_DEVICE_NOT_FOUND; else err = OCFS2_ET_IO; } else state->ts_local_fd = rc; return err; } static void tunefs_unlock_local(ocfs2_filesys *fs) { struct tunefs_filesystem_state *state = tunefs_get_state(fs); assert(state->ts_master == fs); if (state->ts_local_fd > -1) { close(state->ts_local_fd); /* Don't care about errors */ state->ts_local_fd = -1; } } static errcode_t tunefs_unlock_cluster(ocfs2_filesys *fs) { errcode_t tmp, err = 0; struct tunefs_filesystem_state *state = tunefs_get_state(fs); struct tools_progress *prog = NULL; if (fs->fs_dlm_ctxt) prog = tools_progress_start("Unlocking filesystem", "unlocking", 2); /* * We continue even with no progress, because we're unlocking * and probably exiting. */ assert(state->ts_master == fs); if (state->ts_cluster_locked) { assert(fs->fs_dlm_ctxt); tunefs_block_signals(); err = ocfs2_release_cluster(fs); tunefs_unblock_signals(); state->ts_cluster_locked = 0; } if (prog) tools_progress_step(prog, 1); /* We shut down the dlm regardless of err */ if (fs->fs_dlm_ctxt) { tmp = ocfs2_shutdown_dlm(fs, WHOAMI); if (!err) err = tmp; } if (prog) { tools_progress_step(prog, 1); tools_progress_stop(prog); } return err; } /* * We only unlock if we're closing the master filesystem. We unlock * both local and cluster locks, because we may have started as a local * filesystem, then switched to a cluster filesystem in the middle. */ static errcode_t tunefs_unlock_filesystem(ocfs2_filesys *fs) { errcode_t err = 0; struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (state->ts_master == fs) { tunefs_unlock_local(fs); err = tunefs_unlock_cluster(fs); } return err; } static errcode_t tunefs_lock_cluster(ocfs2_filesys *fs, int flags) { errcode_t err = 0; struct tunefs_filesystem_state *state = tunefs_get_state(fs); ocfs2_filesys *master_fs = state->ts_master; struct tools_progress *prog = NULL; if (state->ts_cluster_locked) goto out; if (flags & TUNEFS_FLAG_SKIPCLUSTER) { err = TUNEFS_ET_CLUSTER_SKIPPED; goto out; } prog = tools_progress_start("Locking filesystem", "locking", 2); if (!prog) { err = TUNEFS_ET_NO_MEMORY; goto out; } if (!master_fs->fs_dlm_ctxt) { err = o2cb_init(); if (err) goto out; err = ocfs2_initialize_dlm(master_fs, WHOAMI); if (flags & TUNEFS_FLAG_NOCLUSTER) { if (err == O2CB_ET_INVALID_STACK_NAME) { /* * We expected this - why else ask for * TUNEFS_FLAG_NOCLUSTER? * * Note that this is distinct from the O2CB * error, as that is a real error when * TUNEFS_FLAG_NOCLUSTER is not specified. */ err = TUNEFS_ET_INVALID_STACK_NAME; } /* * Success means do nothing, any other error * propagates up. */ goto out; } else if (err) goto out; } tools_progress_step(prog, 1); tunefs_block_signals(); err = ocfs2_lock_down_cluster(master_fs); tunefs_unblock_signals(); if (!err) state->ts_cluster_locked = 1; else if ((err == O2DLM_ET_TRYLOCK_FAILED) && (flags & TUNEFS_FLAG_ONLINE)) err = TUNEFS_ET_PERFORM_ONLINE; else ocfs2_shutdown_dlm(fs, WHOAMI); tools_progress_step(prog, 1); out: if (prog) tools_progress_stop(prog); return err; } /* * We try to lock the filesystem in *this* ocfs2_filesys. We get the * state off of the master, but the filesystem may have changed since * the master opened its ocfs2_filesys. It might have been switched to * LOCAL or something. We trust the current status in order to make our * decision. * * Inside the underlying lock functions, they check the state to see if * they actually need to do anything. If they don't have it locked, they * will always retry the lock. The filesystem may have gotten unmounted * right after we ran our latest online operation. */ static errcode_t tunefs_lock_filesystem(ocfs2_filesys *fs, int flags) { errcode_t err = 0; if (ocfs2_mount_local(fs)) err = tunefs_lock_local(fs, flags); else err = tunefs_lock_cluster(fs, flags); return err; } static int tunefs_count_free_bits(struct ocfs2_group_desc *gd) { int end = 0; int start; int bits = 0; while (end < gd->bg_bits) { start = ocfs2_find_next_bit_clear(gd->bg_bitmap, gd->bg_bits, end); if (start >= gd->bg_bits) break; end = ocfs2_find_next_bit_set(gd->bg_bitmap, gd->bg_bits, start); bits += (end - start); } return bits; } static errcode_t tunefs_validate_chain_group(ocfs2_filesys *fs, struct ocfs2_dinode *di, int chain) { errcode_t ret = 0; uint64_t blkno; char *buf = NULL; struct ocfs2_group_desc *gd; struct ocfs2_chain_list *cl; struct ocfs2_chain_rec *cr; uint32_t total = 0; uint32_t free = 0; uint16_t bits; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { verbosef(VL_LIB, "%s while allocating a buffer for chain group " "validation\n", error_message(ret)); goto bail; } total = 0; free = 0; cl = &(di->id2.i_chain); cr = &(cl->cl_recs[chain]); blkno = cr->c_blkno; while (blkno) { ret = ocfs2_read_group_desc(fs, blkno, buf); if (ret) { verbosef(VL_LIB, "%s while reading chain group descriptor " "at block %"PRIu64"\n", error_message(ret), blkno); goto bail; } gd = (struct ocfs2_group_desc *)buf; if (gd->bg_parent_dinode != di->i_blkno) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is " "corrupt. It contains group descriptor " "at %"PRIu64", but that descriptor says " "it belongs to allocator %"PRIu64"\n", (uint64_t)di->i_blkno, blkno, (uint64_t)gd->bg_parent_dinode); goto bail; } if (gd->bg_chain != chain) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is " "corrupt. Group descriptor at %"PRIu64" " "was found on chain %u, but it says it " "belongs to chain %u\n", (uint64_t)di->i_blkno, blkno, chain, gd->bg_chain); goto bail; } bits = tunefs_count_free_bits(gd); if (bits != gd->bg_free_bits_count) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is " "corrupt. Group descriptor at %"PRIu64" " "has %u free bits but says it has %u\n", (uint64_t)di->i_blkno, (uint64_t)blkno, bits, gd->bg_free_bits_count); goto bail; } if (gd->bg_bits > gd->bg_size * 8) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is " "corrupt. Group descriptor at %"PRIu64" " "can only hold %u bits, but it claims to " "have %u\n", (uint64_t)di->i_blkno, (uint64_t)blkno, gd->bg_size * 8, gd->bg_bits); goto bail; } if (gd->bg_free_bits_count >= gd->bg_bits) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is " "corrupt. Group descriptor at %"PRIu64" " "claims to have more free bits than " "total bits\n", (uint64_t)di->i_blkno, (uint64_t)blkno); goto bail; } total += gd->bg_bits; free += gd->bg_free_bits_count; blkno = gd->bg_next_group; } if (cr->c_total != total) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is corrupt. " "It contains %u total bits, but it says it has " "%u\n", (uint64_t)di->i_blkno, total, cr->c_total); goto bail; } if (cr->c_free != free) { ret = OCFS2_ET_CORRUPT_CHAIN; verbosef(VL_LIB, "Chain allocator at block %"PRIu64" is corrupt. " "It contains %u free bits, but it says it has " "%u\n", (uint64_t)di->i_blkno, free, cr->c_free); goto bail; } bail: if (buf) ocfs2_free(&buf); return ret; } static errcode_t tunefs_global_bitmap_check(ocfs2_filesys *fs) { errcode_t ret = 0; uint64_t bm_blkno = 0; char *buf = NULL; struct ocfs2_chain_list *cl; struct ocfs2_dinode *di; int i; verbosef(VL_LIB, "Verifying the global allocator\n"); ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { verbosef(VL_LIB, "%s while allocating an inode buffer to validate " "the global bitmap\n", error_message(ret)); goto bail; } ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &bm_blkno); if (ret) { verbosef(VL_LIB, "%s while looking up the global bitmap inode\n", error_message(ret)); goto bail; } ret = ocfs2_read_inode(fs, bm_blkno, buf); if (ret) { verbosef(VL_LIB, "%s while reading the global bitmap inode at " "block %"PRIu64"", error_message(ret), bm_blkno); goto bail; } di = (struct ocfs2_dinode *)buf; cl = &(di->id2.i_chain); for (i = 0; i < cl->cl_next_free_rec; ++i) { ret = tunefs_validate_chain_group(fs, di, i); if (ret) goto bail; } bail: if (buf) ocfs2_free(&buf); return ret; } static errcode_t tunefs_open_bitmap_check(ocfs2_filesys *fs) { struct tunefs_private *tp = to_private(fs); struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (!(tp->tp_open_flags & TUNEFS_FLAG_ALLOCATION)) return 0; state->ts_allocation = 1; return tunefs_global_bitmap_check(fs); } void tunefs_update_fs_clusters(ocfs2_filesys *fs) { struct tunefs_private *tp = to_private(fs); struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (!(tp->tp_open_flags & TUNEFS_FLAG_ALLOCATION)) { verbosef(VL_LIB, "Operation that claimed it would do no allocation " "just attempted to update the filesystem size\n"); return; } state->ts_fs_clusters = fs->fs_clusters; } static errcode_t tunefs_close_bitmap_check(ocfs2_filesys *fs) { errcode_t ret; uint32_t old_clusters; struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (!state->ts_allocation) return 0; if (state->ts_master != fs) return 0; /* * An operation that resized the filesystem will have called * tunefs_update_fs_clusters(). The bitmap check needs this * new value, so we swap it in for the call. */ old_clusters = fs->fs_clusters; fs->fs_clusters = state->ts_fs_clusters; fs->fs_blocks = ocfs2_clusters_to_blocks(fs, fs->fs_clusters); ret = tunefs_global_bitmap_check(fs); fs->fs_clusters = old_clusters; fs->fs_blocks = ocfs2_clusters_to_blocks(fs, fs->fs_clusters); return ret; } static errcode_t tunefs_journal_check(ocfs2_filesys *fs) { errcode_t ret; char *jsb_buf = NULL; ocfs2_cached_inode *ci = NULL; uint64_t blkno, contig; journal_superblock_t *jsb; int i, dirty = 0; uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; struct tunefs_private *tp = to_private(fs); struct tunefs_filesystem_state *state = tunefs_get_state(fs); /* We only need to check the journal once */ if (state->ts_journal_clusters) return 0; verbosef(VL_LIB, "Checking for dirty journals\n"); ret = ocfs2_malloc_block(fs->fs_io, &jsb_buf); if (ret) { verbosef(VL_LIB, "%s while allocating a block during journal " "check\n", error_message(ret)); goto bail; } for (i = 0; i < max_slots; ++i) { ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i, &blkno); if (ret) { verbosef(VL_LIB, "%s while looking up journal inode for " "slot %u during journal check\n", error_message(ret), i); goto bail; } ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) { verbosef(VL_LIB, "%s while reading inode %"PRIu64" during " " journal check", error_message(ret), blkno); goto bail; } state->ts_journal_clusters = ocfs2_max(state->ts_journal_clusters, ci->ci_inode->i_clusters); dirty = (ci->ci_inode->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL); if (dirty) { ret = TUNEFS_ET_JOURNAL_DIRTY; verbosef(VL_LIB, "Node slot %d's journal is dirty. Run " "fsck.ocfs2 to replay all dirty journals.", i); break; } ret = ocfs2_extent_map_get_blocks(ci, 0, 1, &blkno, &contig, NULL); if (!ret) ret = ocfs2_read_journal_superblock(fs, blkno, jsb_buf); if (ret) { verbosef(VL_LIB, "%s while reading journal superblock " "for inode %"PRIu64" during journal " "check", error_message(ret), ci->ci_blkno); goto bail; } jsb = (journal_superblock_t *)jsb_buf; state->ts_journal_features.opt_compat |= jsb->s_feature_compat; state->ts_journal_features.opt_ro_compat |= jsb->s_feature_ro_compat; state->ts_journal_features.opt_incompat |= jsb->s_feature_incompat; } /* * If anything follows a NOCLUSTER operation, it will have * closed and reopened the filesystem. It must recheck the * journals. */ if (tp->tp_open_flags & TUNEFS_FLAG_NOCLUSTER) state->ts_journal_clusters = 0; bail: if (ci) ocfs2_free_cached_inode(fs, ci); if (jsb_buf) ocfs2_free(&jsb_buf); return ret; } static errcode_t tunefs_open_online_descriptor(ocfs2_filesys *fs) { int rc, flags = 0; errcode_t ret = 0; char mnt_dir[PATH_MAX]; struct tunefs_filesystem_state *state = tunefs_get_state(fs); if (state->ts_online_fd > -1) goto out; memset(mnt_dir, 0, sizeof(mnt_dir)); ret = ocfs2_check_mount_point(fs->fs_devname, &flags, mnt_dir, sizeof(mnt_dir)); if (ret) goto out; if (!(flags & OCFS2_MF_MOUNTED) || (flags & OCFS2_MF_READONLY) || (flags & OCFS2_MF_SWAP)) { ret = TUNEFS_ET_NOT_MOUNTED; goto out; } rc = open64(mnt_dir, O_RDONLY); if (rc < 0) { if (errno == EBUSY) ret = TUNEFS_ET_DEVICE_BUSY; else if (errno == ENOENT) ret = TUNEFS_ET_NOT_MOUNTED; else ret = OCFS2_ET_IO; } else state->ts_online_fd = rc; out: return ret; } static void tunefs_close_online_descriptor(ocfs2_filesys *fs) { struct tunefs_filesystem_state *state = tunefs_get_state(fs); if ((state->ts_master == fs) && (state->ts_online_fd > -1)) { close(state->ts_online_fd); /* Don't care about errors */ state->ts_online_fd = -1; } } /* * If io_init_cache fails, we will go do the work without the * io_cache, so there is no check for failure here. */ static void tunefs_init_cache(ocfs2_filesys *fs) { errcode_t err; struct tunefs_private *tp = to_private(fs); struct tunefs_filesystem_state *state = tunefs_get_state(fs); uint64_t blocks_wanted; int scale_down; /* * We have one I/O cache for all ocfs2_filesys structures. This * guarantees a consistent view of the disk. The master filesys * allocates it, child filesyses just use it. */ if (state->ts_master != fs) { io_share_cache(state->ts_master->fs_io, fs->fs_io); return; } /* * Operations needing a large cache really want enough to * hold the whole filesystem in memory. The rest of the * operations don't need much at all. A cache big enough to * hold a chain allocator group should be enough. Our largest * chain allocator is 4MB, so let's do 8MB and allow for * incidental blocks. */ if (tp->tp_open_flags & TUNEFS_FLAG_LARGECACHE) blocks_wanted = fs->fs_blocks; else blocks_wanted = ocfs2_blocks_in_bytes(fs, 8 * 1024 * 1024); /* * We don't want to exhaust memory, so we start with twice our * actual need. When we find out how much we can get, we actually * get half that. */ blocks_wanted <<= 1; scale_down = 1; while (blocks_wanted > 0) { io_destroy_cache(fs->fs_io); verbosef(VL_LIB, "Asking for %"PRIu64" blocks of I/O cache\n", blocks_wanted); err = io_init_cache(fs->fs_io, blocks_wanted); if (!err) { /* * We want to pin our cache; there's no point in * having a large cache if half of it is in swap. * However, some callers may not be privileged * enough, so once we get down to a small enough * number (512 blocks), we'll stop caring. */ err = io_mlock_cache(fs->fs_io); if (err && (blocks_wanted <= 512)) err = 0; } if (!err) { verbosef(VL_LIB, "Got %"PRIu64" blocks\n", blocks_wanted); /* If we've already scaled down, we're done. */ if (!scale_down) break; scale_down = 0; } blocks_wanted >>= 1; } } static errcode_t tunefs_add_fs(ocfs2_filesys *fs, int flags) { errcode_t err; struct tunefs_private *tp; err = ocfs2_malloc0(sizeof(struct tunefs_private), &tp); if (err) goto out; tp->tp_open_flags = flags; fs->fs_private = tp; tp->tp_fs = fs; err = tunefs_set_state(fs); if (err) { fs->fs_private = NULL; ocfs2_free(&tp); goto out; } /* * This is purposely a push. The first open of the filesystem * will be the one holding the locks, so we want it to be the last * close (a FILO stack). When signals happen, tunefs_close_all() * pops each off in turn, finishing with the lock holder. */ list_add(&tp->tp_list, &fs_list); out: return err; } static void tunefs_remove_fs(ocfs2_filesys *fs) { struct tunefs_private *tp = to_private(fs); struct tunefs_filesystem_state *s = NULL; if (tp) { s = tp->tp_state; list_del(&tp->tp_list); tp->tp_fs = NULL; fs->fs_private = NULL; ocfs2_free(&tp); } if (s && (s->ts_master == fs)) { assert(list_empty(&fs_list)); ocfs2_free(&s); } } /* * Return true if this error code is a special (non-fatal) ocfs2ne * error code. */ static int tunefs_special_errorp(errcode_t err) { if (err == TUNEFS_ET_CLUSTER_SKIPPED) return 1; if (err == TUNEFS_ET_INVALID_STACK_NAME) return 1; if (err == TUNEFS_ET_PERFORM_ONLINE) return 1; return 0; } errcode_t tunefs_open(const char *device, int flags, ocfs2_filesys **ret_fs) { int rw = flags & TUNEFS_FLAG_RW; errcode_t err, tmp; int open_flags; ocfs2_filesys *fs = NULL; verbosef(VL_LIB, "Opening device \"%s\"\n", device); open_flags = OCFS2_FLAG_HEARTBEAT_DEV_OK; if (rw) open_flags |= OCFS2_FLAG_RW | OCFS2_FLAG_STRICT_COMPAT_CHECK; else open_flags |= OCFS2_FLAG_RO; err = ocfs2_open(device, open_flags, 0, 0, &fs); if (err) goto out; err = tunefs_add_fs(fs, flags); if (err) goto out; if (!rw) goto out; if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV) { err = TUNEFS_ET_HEARTBEAT_DEV; goto out; } if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG) { err = TUNEFS_ET_RESIZE_IN_PROGRESS; goto out; } if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG) { err = TUNEFS_ET_TUNEFS_IN_PROGRESS; goto out; } err = tunefs_lock_filesystem(fs, flags); if (err && !tunefs_special_errorp(err)) goto out; /* * We will use block cache in io. Now, whether the cluster is * locked or the volume is mount local, in both situation we can * safely use cache. If we're not locked * (tunefs_special_errorp(err) != 0), we can't safely use it. * If this tunefs run has both special and regular operations, * ocfs2ne will retry with the regular arguments and will get * the cache for the regular operations. */ if (!err) tunefs_init_cache(fs); /* * SKIPCLUSTER operations don't check the journals - they couldn't * replay them anyway. */ if (err == TUNEFS_ET_CLUSTER_SKIPPED) goto out; /* Offline operations need clean journals */ if (err != TUNEFS_ET_PERFORM_ONLINE) { tmp = tunefs_journal_check(fs); if (!tmp) tmp = tunefs_open_bitmap_check(fs); if (tmp) { err = tmp; tunefs_unlock_filesystem(fs); } } else { tmp = tunefs_open_online_descriptor(fs); if (tmp) { err = tmp; tunefs_unlock_filesystem(fs); } } out: if (err && !tunefs_special_errorp(err)) { if (fs) { tunefs_remove_fs(fs); ocfs2_close(fs); fs = NULL; } verbosef(VL_LIB, "Open of device \"%s\" failed\n", device); } else { verbosef(VL_LIB, "Device \"%s\" opened\n", device); *ret_fs = fs; } return err; } errcode_t tunefs_close(ocfs2_filesys *fs) { errcode_t tmp, err = 0; /* * We want to clean up everything we can even if there * are errors, but we preserve the first error we get. */ if (fs) { verbosef(VL_LIB, "Closing device \"%s\"\n", fs->fs_devname); tunefs_close_online_descriptor(fs); err = tunefs_close_bitmap_check(fs); tmp = tunefs_unlock_filesystem(fs); if (!err) err = tmp; tunefs_remove_fs(fs); tmp = ocfs2_close(fs); if (!err) err = tmp; if (!err) verbosef(VL_LIB, "Device closed\n"); else verbosef(VL_LIB, "Close of device failed\n"); fs = NULL; } return err; } /* * Helper functions for the main code. */ errcode_t tunefs_feature_run(ocfs2_filesys *master_fs, struct tunefs_feature *feat) { int rc = 0; errcode_t err, tmp; ocfs2_filesys *fs; int flags; verbosef(VL_DEBUG, "Running feature \"%s\"\n", feat->tf_name); flags = feat->tf_open_flags & ~(TUNEFS_FLAG_ONLINE | TUNEFS_FLAG_NOCLUSTER); err = tunefs_open(master_fs->fs_devname, feat->tf_open_flags, &fs); if (err == TUNEFS_ET_PERFORM_ONLINE) flags |= TUNEFS_FLAG_ONLINE; else if (err == TUNEFS_ET_INVALID_STACK_NAME) flags |= TUNEFS_FLAG_NOCLUSTER; else if (err) goto out; err = 0; switch (feat->tf_action) { case FEATURE_ENABLE: rc = feat->tf_enable(fs, flags); break; case FEATURE_DISABLE: rc = feat->tf_disable(fs, flags); break; case FEATURE_NOOP: verbosef(VL_APP, "Ran NOOP for feature \"%s\" - how'd " "that happen?\n", feat->tf_name); break; default: errorf("Unknown action %d called against feature " "\"%s\"\n", feat->tf_action, feat->tf_name); err = TUNEFS_ET_INTERNAL_FAILURE; break; } if (rc) err = TUNEFS_ET_OPERATION_FAILED; tmp = tunefs_close(fs); if (!err) err = tmp; out: return err; } errcode_t tunefs_op_run(ocfs2_filesys *master_fs, struct tunefs_operation *op) { errcode_t err, tmp; ocfs2_filesys *fs; int flags; verbosef(VL_DEBUG, "Running operation \"%s\"\n", op->to_name); flags = op->to_open_flags & ~(TUNEFS_FLAG_ONLINE | TUNEFS_FLAG_NOCLUSTER); err = tunefs_open(master_fs->fs_devname, op->to_open_flags, &fs); if (err == TUNEFS_ET_PERFORM_ONLINE) flags |= TUNEFS_FLAG_ONLINE; else if (err == TUNEFS_ET_INVALID_STACK_NAME) flags |= TUNEFS_FLAG_NOCLUSTER; else if (err == TUNEFS_ET_CLUSTER_SKIPPED) flags |= TUNEFS_FLAG_SKIPCLUSTER; else if (err) goto out; err = 0; if (op->to_run(op, fs, flags)) err = TUNEFS_ET_OPERATION_FAILED; tmp = tunefs_close(fs); if (!err) err = tmp; out: return err; } /* * Helper calls for operation and feature DEBUG_EXE code */ static errcode_t copy_argv(char **argv, char ***new_argv) { int i; char **t_argv; for (i = 0; argv[i]; i++) ; /* Count argv */ /* This is intentionally leaked */ t_argv = malloc(sizeof(char *) * (i + 1)); if (!t_argv) return TUNEFS_ET_NO_MEMORY; for (i = 0; argv[i]; i++) t_argv[i] = (char *)argv[i]; t_argv[i] = NULL; *new_argv = t_argv; return 0; } /* All the +1 are to leave argv[0] in place */ static void shuffle_argv(int *argc, int optind, char **argv) { int src, dst; int new_argc = *argc - optind + 1; for (src = optind, dst = 1; src < *argc; src++, dst++) argv[dst] = argv[src]; if (dst != new_argc) verbosef(VL_DEBUG, "dst is not new_argc %d %d\n", dst, new_argc); argv[dst] = NULL; *argc = new_argc; } static void tunefs_debug_usage(int error) { enum tools_verbosity_level level = VL_ERR; if (!error) level = VL_OUT; verbosef(level, "%s", usage_string ? usage_string : "(null)"); verbosef(level, "[opts] can be any mix of:\n" "\t-i|--interactive\n" "\t-v|--verbose (more than one increases verbosity)\n" "\t-q|--quiet (more than one decreases verbosity)\n" "\t-h|--help\n" "\t-V|--version\n"); } extern int optind, opterr, optopt; extern char *optarg; static void tunefs_parse_core_options(int *argc, char ***argv, char *usage) { errcode_t err; int c; char **new_argv; int print_usage = 0, print_version = 0; char error[PATH_MAX]; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "verbose", 0, NULL, 'v' }, { "quiet", 0, NULL, 'q' }, { "interactive", 0, NULL, 'i'}, { 0, 0, 0, 0} }; usage_string = usage; err = copy_argv(*argv, &new_argv); if (err) { tcom_err(err, "while processing command-line arguments"); exit(1); } opterr = 0; error[0] = '\0'; while ((c = getopt_long(*argc, new_argv, ":hVvqi", long_options, NULL)) != EOF) { switch (c) { case 'h': print_usage = 1; break; case 'V': print_version = 1; break; case 'v': tools_verbose(); break; case 'q': tools_quiet(); break; case 'i': tools_interactive(); break; case '?': snprintf(error, PATH_MAX, "Invalid option: \'-%c\'", optopt); print_usage = 1; break; case ':': snprintf(error, PATH_MAX, "Option \'-%c\' requires an argument", optopt); print_usage = 1; break; default: snprintf(error, PATH_MAX, "Shouldn't get here %c %c", optopt, c); break; } if (*error) break; } if (*error) errorf("%s\n", error); if (print_version) tools_version(); if (print_usage) tunefs_debug_usage(*error != '\0'); if (print_usage || print_version) exit(0); if (*error) exit(1); shuffle_argv(argc, optind, new_argv); *argv = new_argv; } static int single_feature_parse_option(struct tunefs_operation *op, char *arg) { int rc = 0; struct tunefs_feature *feat = op->to_private; if (!arg) { errorf("No action specified\n"); rc = 1; } else if (!strcmp(arg, "enable")) feat->tf_action = FEATURE_ENABLE; else if (!strcmp(arg, "disable")) feat->tf_action = FEATURE_DISABLE; else { errorf("Invalid action: \"%s\"\n", arg); rc = 1; } return rc; } static int single_feature_run(struct tunefs_operation *op, ocfs2_filesys *fs, int flags) { errcode_t err; struct tunefs_feature *feat = op->to_private; err = tunefs_feature_run(fs, feat); if (err && (err != TUNEFS_ET_OPERATION_FAILED)) tcom_err(err, "while toggling feature \"%s\"", feat->tf_name); return err; } DEFINE_TUNEFS_OP(single_feature, NULL, 0, single_feature_parse_option, single_feature_run); int tunefs_feature_main(int argc, char *argv[], struct tunefs_feature *feat) { char usage[PATH_MAX]; snprintf(usage, PATH_MAX, "Usage: ocfs2ne_feature_%s [opts] " "{enable|disable}\n", feat->tf_name); single_feature_op.to_debug_usage = usage; single_feature_op.to_open_flags = feat->tf_open_flags; single_feature_op.to_private = feat; return tunefs_op_main(argc, argv, &single_feature_op); } int tunefs_op_main(int argc, char *argv[], struct tunefs_operation *op) { errcode_t err; int rc = 1; ocfs2_filesys *fs; char *arg = NULL; tunefs_init(argv[0]); tunefs_parse_core_options(&argc, &argv, op->to_debug_usage); if (argc < 2) { errorf("No device specified\n"); tunefs_debug_usage(1); goto out; } if (op->to_parse_option) { if (argc > 3) { errorf("Too many arguments\n"); tunefs_debug_usage(1); goto out; } if (argc == 3) arg = argv[2]; rc = op->to_parse_option(op, arg); if (rc) { tunefs_debug_usage(1); goto out; } } else if (argc > 2) { errorf("Too many arguments\n"); tunefs_debug_usage(1); goto out; } err = tunefs_open(argv[1], op->to_open_flags, &fs); if (err && !tunefs_special_errorp(err)) { tcom_err(err, "- Unable to open device \"%s\" read-write.", argv[1]); goto out; } err = tunefs_op_run(fs, op); if (!err) rc = 0; else if (err != TUNEFS_ET_OPERATION_FAILED) tcom_err(err, "while running operation \"%s\"", op->to_name); err = tunefs_close(fs); if (err) { tcom_err(err, "while closing device \"%s\"", argv[1]); rc = 1; } out: return rc; } #ifdef DEBUG_EXE int parent = 0; static void closeup(ocfs2_filesys *fs, const char *device) { errcode_t err; verbosef(VL_OUT, "success\n"); err = tunefs_close(fs); if (err) { tcom_err(err, "- Unable to close device \"%s\".", device); } } int main(int argc, char *argv[]) { errcode_t err; const char *device; ocfs2_filesys *fs; tunefs_init(argv[0]); tunefs_parse_core_options(&argc, &argv, "Usage: debug_libocfs2ne [-p] \n"); if (argc > 3) { errorf("Too many arguments\n"); tunefs_debug_usage(1); return 1; } if (argc == 3) { if (strcmp(argv[1], "-p")) { errorf("Invalid argument: \'%s\'\n", argv[1]); tunefs_debug_usage(1); return 1; } parent = 1; device = argv[2]; } else if ((argc == 2) && strcmp(argv[1], "-p")) { device = argv[1]; } else { errorf("Device must be specified\n"); tunefs_debug_usage(1); return 1; } verbosef(VL_OUT, "Opening device \"%s\" read-only... ", device); err = tunefs_open(device, TUNEFS_FLAG_RO, &fs); if (err) { verbosef(VL_OUT, "failed\n"); tcom_err(err, "- Unable to open device \"%s\" read-only.", device); } else closeup(fs, device); verbosef(VL_OUT, "Opening device \"%s\" read-write... ", device); err = tunefs_open(device, TUNEFS_FLAG_RW, &fs); if (err) { verbosef(VL_OUT, "failed\n"); tcom_err(err, "- Unable to open device \"%s\" read-write.", device); } else closeup(fs, device); verbosef(VL_OUT, "Opening device \"%s\" for an online operation... ", device); err = tunefs_open(device, TUNEFS_FLAG_RW | TUNEFS_FLAG_ONLINE, &fs); if (err == TUNEFS_ET_PERFORM_ONLINE) { closeup(fs, device); verbosef(VL_OUT, "Operation would have been online\n"); } else if (!err) { closeup(fs, device); verbosef(VL_OUT, "Operation would have been offline\n"); } else { verbosef(VL_OUT, "failed\n"); tcom_err(err, "- Unable to open device \"%s\" read-write.", device); } verbosef(VL_OUT, "Opening device \"%s\" for a stackless operation... ", device); err = tunefs_open(device, TUNEFS_FLAG_RW | TUNEFS_FLAG_NOCLUSTER, &fs); if (err == TUNEFS_ET_INVALID_STACK_NAME) { closeup(fs, device); verbosef(VL_OUT, "Expected cluster stack mismatch found\n"); } else if (!err) { closeup(fs, device); verbosef(VL_OUT, "Cluster stacks already match\n"); } else { verbosef(VL_OUT, "failed\n"); tcom_err(err, "- Unable to open device \"%s\" read-write.", device); } return 0; } #endif /* DEBUG_EXE */ ./ocfs2-tools-1.6.4/tunefs.ocfs2/ocfs2ne.c0000644000176100017610000006221311500500545014777 00000000000000/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * ocfs2ne.c * * ocfs2 tune utility. * * Copyright (C) 2004, 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #define _GNU_SOURCE /* for getopt_long and O_DIRECT */ #include #include #include #include #include #include #include "ocfs2/ocfs2.h" #include "libocfs2ne.h" /* * Why do we have a list of option structures will callbacks instead of * a simple switch() statement? Because the ocfs2ne option set has grown * over time, and there are a few operations that can be triggered by * more than one option. For example, -M {cluster|local} is really just * clearing or setting the fs feature 'local'. * * For most argument-free operations, they'll just specify their name and * val. Options with arguments will mostly use generic_handle_arg() as * their ->opt_handle(). * * If you are adding a new feature flag, do not add an option here. It * should be handled by --fs-features. Just write a tunefs_feature in * ocfs2ne_feature_.c and add it to the list ocfs2ne_features.c. * If you are adding an operation, make its option something that stands on * its own and can use generic_handle_arg() if it needs an argument. */ struct tunefs_option { struct option opt_option; /* For getopt_long(). If there is no short option, set .val to CHAR_MAX. A unique value will be inserted by the code. */ struct tunefs_operation *opt_op; /* Operation associated with this option. This needs to be set if the option has no ->opt_handle() or is using generic_handle_arg(). If set, opt_op will be added to the run_list when this option is seen. */ char *opt_help; /* Help string */ int opt_set; /* Was this option seen */ int (*opt_handle)(struct tunefs_option *opt, char *arg); void *opt_private; }; /* * ocfs2ne lumps all journal options as name[=value] arguments underneath * '-J'. They end up being tunefs_operations, and we link them up here. */ struct tunefs_journal_option { char *jo_name; char *jo_help; struct tunefs_operation *jo_op; }; /* Things to run */ struct tunefs_run { struct list_head tr_list; struct tunefs_operation *tr_op; }; extern struct tunefs_operation list_sparse_op; extern struct tunefs_operation query_op; extern struct tunefs_operation reset_uuid_op; extern struct tunefs_operation features_op; extern struct tunefs_operation resize_volume_op; extern struct tunefs_operation set_journal_size_op; extern struct tunefs_operation set_label_op; extern struct tunefs_operation set_slot_count_op; extern struct tunefs_operation update_cluster_stack_op; extern struct tunefs_operation cloned_volume_op; extern struct tunefs_operation set_usrquota_sync_interval_op; extern struct tunefs_operation set_grpquota_sync_interval_op; /* List of operations we're going to run */ static LIST_HEAD(tunefs_run_list); /* Number of operations we're going to run */ static int tunefs_op_count; /* Progress display for tunefs operations */ static struct tools_progress *tunefs_op_progress; static struct tunefs_journal_option set_journal_size_option = { .jo_name = "size", .jo_help = "size=", .jo_op = &set_journal_size_op, }; /* The list of all supported journal options */ static struct tunefs_journal_option *tunefs_journal_options[] = { &set_journal_size_option, NULL, }; /* * Operations are intended to run in the order we see them in the * command-line arguments. As each option is seen, the operation is * added with tunefs_append_operation(). * * There are two exceptions. First, special-cased options (pretty much * the feature) will end up at the end because we can't process them * until we've seen all command-line arguments. * * Second, resize is the only user of tunefs_prepend_operation(). We want * to grow the filesystem *before* we do anything that might require space! */ static errcode_t tunefs_append_operation(struct tunefs_operation *op) { errcode_t err; struct tunefs_run *run; err = ocfs2_malloc0(sizeof(struct tunefs_run), &run); if (!err) { run->tr_op = op; list_add_tail(&run->tr_list, &tunefs_run_list); tunefs_op_count++; } return err; } static errcode_t tunefs_prepend_operation(struct tunefs_operation *op) { errcode_t err; struct tunefs_run *run; err = ocfs2_malloc0(sizeof(struct tunefs_run), &run); if (!err) { run->tr_op = op; list_add(&run->tr_list, &tunefs_run_list); tunefs_op_count++; } return err; } static void print_usage(int rc); static int handle_help(struct tunefs_option *opt, char *arg) { print_usage(0); return 1; } static int handle_version(struct tunefs_option *opt, char *arg) { tools_version(); exit(0); return 1; } static int handle_verbosity(struct tunefs_option *opt, char *arg) { int rc = 0; switch (opt->opt_option.val) { case 'v': tools_verbose(); break; case 'q': tools_quiet(); break; default: errorf("Invalid option to handle_verbosity: %c\n", opt->opt_option.val); rc = 1; break; } /* More than one -v or -q is valid */ opt->opt_set = 0; return rc; } static int handle_interactive(struct tunefs_option *opt, char *arg) { tools_interactive(); return 0; } static int handle_progress(struct tunefs_option *opt, char *arg) { tools_progress_enable(); return 0; } static int handle_answer(struct tunefs_option *opt, char *arg) { int rc = 0; switch (opt->opt_option.val) { case 'y': tools_interactive_yes(); break; case 'n': tools_interactive_no(); break; default: errorf("Invalid option to handle_answer: %c\n", opt->opt_option.val); rc = 1; break; } return rc; } /* * Plain operations just want to have their ->to_parse_option() called. * Their tunefs_option can use this function if they set opt_op to the * tunefs_operation. */ static int generic_handle_arg(struct tunefs_option *opt, char *arg) { struct tunefs_operation *op = opt->opt_op; if (!op->to_parse_option) { errorf("Option \"%s\" claims it has an argument, but " "operation \"%s\" isn't expecting one\n", opt->opt_option.name, op->to_name); return 1; } return op->to_parse_option(op, arg); } /* * Store a copy of the argument on opt_private. * * For example, the multiple options setting fs_features want to save off * their feature string. They use this function directly or indirectly. */ static int strdup_handle_arg(struct tunefs_option *opt, char *arg) { char *ptr = NULL; if (arg) { ptr = strdup(arg); if (!ptr) { errorf("Unable to allocate memory while processing " "options\n"); return 1; } } opt->opt_private = ptr; return 0; } static int mount_type_handle_arg(struct tunefs_option *opt, char *arg) { int rc = 0; if (!arg) { errorf("No mount type specified\n"); rc = 1; } else if (!strcmp(arg, "local")) rc = strdup_handle_arg(opt, "local"); else if (!strcmp(arg, "cluster")) rc = strdup_handle_arg(opt, "nolocal"); else { errorf("Invalid mount type: \"%s\"\n", arg); rc = 1; } return rc; } static int backup_super_handle_arg(struct tunefs_option *opt, char *arg) { return strdup_handle_arg(opt, "backup-super"); } static struct tunefs_journal_option *find_journal_option(char *name) { int i; struct tunefs_journal_option *jopt; for (i = 0; tunefs_journal_options[i]; i++) { jopt = tunefs_journal_options[i]; if (!strcmp(name, jopt->jo_name)) return jopt; } return NULL; } /* derived from e2fsprogs */ static int handle_journal_arg(struct tunefs_option *opt, char *arg) { errcode_t err; int i, rc = 0; char *options, *token, *next, *p, *val; int journal_usage = 0; struct tunefs_journal_option *jopt; if (arg) { options = strdup(arg); if (!options) { tcom_err(TUNEFS_ET_NO_MEMORY, "while processing journal options"); return 1; } } else options = NULL; for (token = options; token && *token; token = next) { p = strchr(token, ','); next = NULL; if (p) { *p = '\0'; next = p + 1; } val = strchr(token, '='); if (val) { *val = '\0'; val++; } jopt = find_journal_option(token); if (!jopt) { errorf("Unknown journal option: \"%s\"\n", token); journal_usage++; continue; } if (jopt->jo_op->to_parse_option) { if (jopt->jo_op->to_parse_option(jopt->jo_op, val)) { journal_usage++; continue; } } else if (val) { errorf("Journal option \"%s\" does not accept " "arguments\n", token); journal_usage++; continue; } err = tunefs_append_operation(jopt->jo_op); if (err) { tcom_err(err, "while processing journal options"); rc = 1; break; } } if (journal_usage) { verbosef(VL_ERR, "Valid journal options are:\n"); for (i = 0; tunefs_journal_options[i]; i++) verbosef(VL_ERR, "\t%s\n", tunefs_journal_options[i]->jo_help); rc = 1; } free(options); return rc; } static struct tunefs_option help_option = { .opt_option = { .name = "help", .val = 'h', }, .opt_handle = handle_help, }; static struct tunefs_option version_option = { .opt_option = { .name = "version", .val = 'V', }, .opt_handle = handle_version, }; static struct tunefs_option verbose_option = { .opt_option = { .name = "verbose", .val = 'v', }, .opt_help = "-v|--verbose (increases verbosity; more than one permitted)", .opt_handle = handle_verbosity, }; static struct tunefs_option quiet_option = { .opt_option = { .name = "quiet", .val = 'q', }, .opt_help = "-q|--quiet (decreases verbosity; more than one permitted)", .opt_handle = handle_verbosity, }; static struct tunefs_option interactive_option = { .opt_option = { .name = "interactive", .val = 'i', }, .opt_help = "-i|--interactive", .opt_handle = handle_interactive, }; static struct tunefs_option progress_option = { .opt_option = { .name = "progress", .val = 'p', }, .opt_help = "-p|--progress", .opt_handle = handle_progress, }; static struct tunefs_option yes_option = { .opt_option = { .name = "yes", .val = 'y', }, .opt_help = "-y|--yes", .opt_handle = handle_answer, }; static struct tunefs_option no_option = { .opt_option = { .name = "no", .val = 'n', }, .opt_help = "-n|--no", .opt_handle = handle_answer, }; static struct tunefs_option query_option = { .opt_option = { .name = "query", .val = 'Q', .has_arg = 1, }, .opt_help = "-Q|--query ", .opt_handle = &generic_handle_arg, .opt_op = &query_op, }; static struct tunefs_option list_sparse_option = { .opt_option = { .name = "list-sparse", .val = CHAR_MAX, }, .opt_help = " --list-sparse", .opt_op = &list_sparse_op, }; static struct tunefs_option reset_uuid_option = { .opt_option = { .name = "uuid-reset", .val = 'U', .has_arg = 2, }, .opt_help = "-U|--uuid-reset[=new-uuid]", .opt_handle = &generic_handle_arg, .opt_op = &reset_uuid_op, }; static struct tunefs_option update_cluster_stack_option = { .opt_option = { .name = "update-cluster-stack", .val = CHAR_MAX, }, .opt_help = " --update-cluster-stack", .opt_op = &update_cluster_stack_op, }; static struct tunefs_option cloned_volume_option = { .opt_option = { .name = "cloned-volume", .val = CHAR_MAX, .has_arg = 2, }, .opt_help = " --cloned-volume[=new-label]", .opt_op = &cloned_volume_op, }; static struct tunefs_option set_slot_count_option = { .opt_option = { .name = "node-slots", .val = 'N', .has_arg = 1, }, .opt_help = "-N|--node-slots ", .opt_handle = generic_handle_arg, .opt_op = &set_slot_count_op, }; static struct tunefs_option set_label_option = { .opt_option = { .name = "label", .val = 'L', .has_arg = 1, }, .opt_help = "-L|--label