1 (* 'df' command for virtual domains.
2 (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 Support for EXT2/EXT3 filesystems.
29 let ( +* ) = Int32.add
30 let ( -* ) = Int32.sub
31 let ( ** ) = Int32.mul
32 let ( /* ) = Int32.div
34 (* The fields in an ext2/3 superblock. *)
36 s_inodes_count : int32;
37 s_blocks_count : int32;
38 s_r_blocks_count : int32;
39 s_free_blocks_count : int32;
40 s_free_inodes_count : int32;
41 s_first_data_block : int32;
42 s_log_block_size : int32;
43 s_log_frag_size : int32;
44 s_blocks_per_group : int32;
45 s_frags_per_group : int32;
46 s_inodes_per_group : int32;
50 s_max_mnt_count : int;
53 s_minor_rev_level : int;
55 s_checkinterval : int32;
62 s_block_group_nr : int;
63 s_feature_compat : int32;
64 s_feature_incompat : int32;
65 s_feature_ro_compat : int32;
67 s_volume_name : string;
68 s_last_mounted : string;
69 s_algorithm_usage_bitmap : int32;
70 s_prealloc_blocks : int;
71 s_prealloc_dir_blocks : int;
72 s_reserved_gdt_blocks : int;
73 s_journal_uuid : string;
74 s_journal_inum : int32;
75 s_journal_dev : int32;
76 s_last_orphan : int32;
81 s_def_hash_version : int;
82 s_reserved_char_pad : int;
83 s_reserved_word_pad : int;
84 s_default_mount_opts : int32;
85 s_first_meta_bg : int32;
87 (* Computed fields, don't appear in superblock: *)
92 (* Private data functions. *)
93 let attach_private_data, get_private_data =
94 private_data_functions (fun {fs_cb = {fs_cb_uq = u}} -> u)
97 let superblock_offset = ~^1024
98 let superblock_len = ~^1024
100 (* Parse ext2/3 superblock and return a big structure containing
101 * all the fields. Also there are some extra fields which don't
102 * appear in the superblock itself, but are computed from other fields.
104 * If the device doesn't contain a superblock, raises Not_found.
106 let parse_ext2_sb dev =
107 (* Load the superblock. *)
108 let bits = dev#read_bitstring superblock_offset superblock_len in
110 (* The structure is straight from /usr/include/linux/ext3_fs.h *)
112 | { s_inodes_count : 32 : littleendian; (* Inodes count *)
113 s_blocks_count : 32 : littleendian; (* Blocks count *)
114 s_r_blocks_count : 32 : littleendian; (* Reserved blocks count *)
115 s_free_blocks_count : 32 : littleendian; (* Free blocks count *)
116 s_free_inodes_count : 32 : littleendian; (* Free inodes count *)
117 s_first_data_block : 32 : littleendian; (* First Data Block *)
118 s_log_block_size : 32 : littleendian; (* Block size *)
119 s_log_frag_size : 32 : littleendian; (* Fragment size *)
120 s_blocks_per_group : 32 : littleendian; (* # Blocks per group *)
121 s_frags_per_group : 32 : littleendian; (* # Fragments per group *)
122 s_inodes_per_group : 32 : littleendian; (* # Inodes per group *)
123 s_mtime : 32 : littleendian; (* Mount time *)
124 s_wtime : 32 : littleendian; (* Write time *)
125 s_mnt_count : 16 : littleendian; (* Mount count *)
126 s_max_mnt_count : 16 : littleendian; (* Maximal mount count *)
127 0xef53 : 16 : littleendian; (* Magic signature *)
128 s_state : 16 : littleendian; (* File system state *)
129 s_errors : 16 : littleendian; (* Behaviour when detecting errors *)
130 s_minor_rev_level : 16 : littleendian; (* minor revision level *)
131 s_lastcheck : 32 : littleendian; (* time of last check *)
132 s_checkinterval : 32 : littleendian; (* max. time between checks *)
133 s_creator_os : 32 : littleendian; (* OS *)
134 s_rev_level : 32 : littleendian; (* Revision level *)
135 s_def_resuid : 16 : littleendian; (* Default uid for reserved blocks *)
136 s_def_resgid : 16 : littleendian; (* Default gid for reserved blocks *)
137 s_first_ino : 32 : littleendian; (* First non-reserved inode *)
138 s_inode_size : 16 : littleendian; (* size of inode structure *)
139 s_block_group_nr : 16 : littleendian; (* block group # of this superblock *)
140 s_feature_compat : 32 : littleendian; (* compatible feature set *)
141 s_feature_incompat : 32 : littleendian; (* incompatible feature set *)
142 s_feature_ro_compat : 32 : littleendian; (* readonly-compatible feature set *)
143 s_uuid : 128 : string; (* 128-bit uuid for volume *)
144 s_volume_name : 128 : string; (* volume name *)
145 s_last_mounted : 512 : string; (* directory where last mounted *)
146 s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *)
147 s_prealloc_blocks : 8; (* Nr of blocks to try to preallocate*)
148 s_prealloc_dir_blocks : 8; (* Nr to preallocate for dirs *)
149 s_reserved_gdt_blocks : 16 : littleendian;(* Per group desc for online growth *)
150 s_journal_uuid : 128 : string; (* uuid of journal superblock *)
151 s_journal_inum : 32 : littleendian; (* inode number of journal file *)
152 s_journal_dev : 32 : littleendian; (* device number of journal file *)
153 s_last_orphan : 32 : littleendian; (* start of list of inodes to delete *)
154 s_hash_seed0 : 32 : littleendian; (* HTREE hash seed *)
155 s_hash_seed1 : 32 : littleendian;
156 s_hash_seed2 : 32 : littleendian;
157 s_hash_seed3 : 32 : littleendian;
158 s_def_hash_version : 8; (* Default hash version to use *)
159 s_reserved_char_pad : 8;
160 s_reserved_word_pad : 16 : littleendian;
161 s_default_mount_opts : 32 : littleendian;
162 s_first_meta_bg : 32 : littleendian } -> (* First metablock block group *)
164 (* Work out the block size in bytes. *)
165 let block_size = ~^1024 <^< Int32.to_int s_log_block_size in
167 (* Number of groups. *)
170 (s_blocks_count -* s_first_data_block -* 1l)
171 /* s_blocks_per_group +* 1l
174 { s_inodes_count = s_inodes_count;
175 s_blocks_count = s_blocks_count;
176 s_r_blocks_count = s_r_blocks_count;
177 s_free_blocks_count = s_free_blocks_count;
178 s_free_inodes_count = s_free_inodes_count;
179 s_first_data_block = s_first_data_block;
180 s_log_block_size = s_log_block_size;
181 s_log_frag_size = s_log_frag_size;
182 s_blocks_per_group = s_blocks_per_group;
183 s_frags_per_group = s_frags_per_group;
184 s_inodes_per_group = s_inodes_per_group;
187 s_mnt_count = s_mnt_count;
188 s_max_mnt_count = s_max_mnt_count;
191 s_minor_rev_level = s_minor_rev_level;
192 s_lastcheck = s_lastcheck;
193 s_checkinterval = s_checkinterval;
194 s_creator_os = s_creator_os;
195 s_rev_level = s_rev_level;
196 s_def_resuid = s_def_resuid;
197 s_def_resgid = s_def_resgid;
198 s_first_ino = s_first_ino;
199 s_inode_size = s_inode_size;
200 s_block_group_nr = s_block_group_nr;
201 s_feature_compat = s_feature_compat;
202 s_feature_incompat = s_feature_incompat;
203 s_feature_ro_compat = s_feature_ro_compat;
205 s_volume_name = s_volume_name;
206 s_last_mounted = s_last_mounted;
207 s_algorithm_usage_bitmap = s_algorithm_usage_bitmap;
208 s_prealloc_blocks = s_prealloc_blocks;
209 s_prealloc_dir_blocks = s_prealloc_dir_blocks;
210 s_reserved_gdt_blocks = s_reserved_gdt_blocks;
211 s_journal_uuid = s_journal_uuid;
212 s_journal_inum = s_journal_inum;
213 s_journal_dev = s_journal_dev;
214 s_last_orphan = s_last_orphan;
215 s_hash_seed0 = s_hash_seed0;
216 s_hash_seed1 = s_hash_seed1;
217 s_hash_seed2 = s_hash_seed2;
218 s_hash_seed3 = s_hash_seed3;
219 s_def_hash_version = s_def_hash_version;
220 s_reserved_char_pad = s_reserved_char_pad;
221 s_reserved_word_pad = s_reserved_word_pad;
222 s_default_mount_opts = s_default_mount_opts;
223 s_first_meta_bg = s_first_meta_bg;
224 block_size = block_size;
225 groups_count = groups_count }
228 raise Not_found (* Not an EXT2/3 superblock. *)
231 let sb = parse_ext2_sb dev in (* May raise Not_found. *)
234 (* Number of group descriptors per block. *)
235 let s_inodes_per_block = s_blocksize /
236 let s_desc_per_block = block_size / s_inodes_per_block in
238 (s_groups_count +^ s_desc_per_block -^ 1L)
242 (* Calculate the block overhead (used by superblocks, inodes, etc.)
243 * See fs/ext2/super.c.
245 let overhead = Int63.of_int32 sb.s_first_data_block in
246 let overhead = (* XXX *) overhead in
248 (* The blocksize of the filesystem is likely to be quite different
249 * from that of the underlying device, so create an overlay device
250 * with the natural filesystem blocksize.
252 let fs_dev = new blocksize_overlay sb.block_size dev in
255 fs_cb = callbacks ();
258 fs_blocksize = sb.block_size;
259 fs_blocks_total = Int63.of_int32 sb.s_blocks_count -^ overhead;
263 fs_blocks_reserved = Int63.of_int32 sb.s_r_blocks_count;
264 fs_blocks_avail = Int63.of_int32 sb.s_free_blocks_count;
266 Int63.of_int32 sb.s_blocks_count -^ overhead
267 -^ Int63.of_int32 sb.s_free_blocks_count;
268 fs_inodes_total = Int63.of_int32 sb.s_inodes_count;
269 fs_inodes_reserved = ~^0; (* XXX? *)
270 fs_inodes_avail = Int63.of_int32 sb.s_free_inodes_count;
271 fs_inodes_used = Int63.of_int32 sb.s_inodes_count
273 -^ Int63.of_int32 sb.s_free_inodes_count;
276 (* Attach the original superblock as private data so we can
277 * get to it quickly in other callbacks.
279 attach_private_data fs sb;
282 and offset_is_free _ _ = false
287 fs_cb_uq = (incr i; !i);
289 fs_cb_printable_name = "Linux ext2/3";
290 fs_cb_offset_is_free = offset_is_free;
293 (* Register the plugin. *)
294 let () = register_plugin ~filesystem:probe id