xref: /haiku/src/add-ons/kernel/file_systems/xfs/xfs.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
1 /*
2 * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5 
6 #include "xfs.h"
7 
8 #include "Inode.h"
9 
10 
11 uint8
12 XfsSuperBlock::Flags() const
13 {
14 	return sb_flags;
15 }
16 
17 
18 bool
19 XfsSuperBlock::IsValidVersion() const
20 {
21 	// Version 5 is supported
22 	if ((Version() & XFS_SB_VERSION_NUMBITS) == 5) {
23 		return true;
24 	}
25 
26 	// Version below 4 are not supported
27 	if ((Version() & XFS_SB_VERSION_NUMBITS) < 4) {
28 		ERROR("xfs version below 4 is not supported");
29 		return false;
30 	}
31 
32 	// V4 filesystems need v2 directories and unwritten extents
33 	if (!(Version() & XFS_SB_VERSION_DIRV2BIT)) {
34 		ERROR("xfs version 4 uses version 2 directories");
35 		return false;
36 	}
37 	if (!(Version() & XFS_SB_VERSION_EXTFLGBIT)) {
38 		ERROR("xfs version 4 uses unwritten extents");
39 		return false;
40 	}
41 
42 	// V4 should not have any unknown v4 feature bits set
43 	if ((Version()  & ~XFS_SB_VERSION_OKBITS) ||
44 	    ((Version()  & XFS_SB_VERSION_MOREBITSBIT) &&
45 	     (Features2() & ~XFS_SB_VERSION2_OKBITS))) {
46 		ERROR("xfs version 4 unknown feature bit detected");
47 		return false;
48 	}
49 
50 	// Valid V4 filesytem
51 	return true;
52 }
53 
54 
55 bool
56 XfsSuperBlock::IsValidFeatureMask() const
57 {
58 	// Version 5 superblock feature mask validation
59 	if(sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN) {
60 		ERROR("Superblock has unknown compatible features enabled");
61 		ERROR("Use more recent kernal");
62 	}
63 
64     // We cannot have write support if this is set
65 	if(sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN) {
66 		ERROR("Superblock has unknown read-only compatible features enabled");
67 		ERROR("Filesystem is read-only");
68 	}
69 
70 	// check for incompatible features
71 	if(sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN) {
72 		ERROR("Superblock has unknown incompatible features enabled");
73 		return false;
74 	}
75 
76 	return true;
77 }
78 
79 
80 bool
81 XfsSuperBlock::IsValid() const
82 {
83 	if (sb_magicnum != XFS_SB_MAGIC) {
84 		ERROR("Invalid Superblock");
85 		return false;
86 	}
87 
88 	// For version 4
89 	if (XFS_MIN_BLOCKSIZE > sb_blocksize) {
90 		ERROR("Basic block is less than 512 bytes!");
91 		return false;
92 	}
93 
94 	// Checking correct version of filesystem
95 	if(!(IsValidVersion())) {
96 		return false;
97 	}
98 
99 	if ((Version() & XFS_SB_VERSION_NUMBITS) == 4) {
100 
101 		if(sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
102 				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
103 			ERROR("V4 Superblock has XFS_{P|G}QUOTA_{ENFD|CHKD} bits");
104 			return false;
105 		}
106 
107 		return true;
108 	}
109 
110 	if(!(IsValidFeatureMask())) {
111 		return false;
112 	}
113 
114 	// For V5
115     if (XFS_MIN_CRC_BLOCKSIZE > sb_blocksize) {
116 		ERROR("Basic block is less than 1024 bytes!");
117 		return false;
118 	}
119 
120 	// V5 has a separate project quota inode
121 	if (sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
122 		ERROR("Version 5 of Super block has XFS_OQUOTA bits");
123 		return false;
124 	}
125 
126 	/*TODO: check if full Inode chunks are aligned to
127 			inode chunk size when sparse inodes are
128 			enabled to support the sparse chunk allocation
129 			algorithm and prevent overlapping inode record.
130 	*/
131 
132 	// Sanity Checking
133 	if(sb_agcount <= 0
134 		||	sb_sectsize < XFS_MIN_SECTORSIZE
135 	    ||	sb_sectsize > XFS_MAX_SECTORSIZE
136 	    ||	sb_sectlog < XFS_MIN_SECTORSIZE_LOG
137 	    ||	sb_sectlog > XFS_MAX_SECTORSIZE_LOG
138 	    ||	sb_sectsize != (1 << sb_sectlog)
139 	    ||	sb_blocksize < XFS_MIN_BLOCKSIZE
140 	    ||	sb_blocksize > XFS_MAX_BLOCKSIZE
141 	    ||	sb_blocklog < XFS_MIN_BLOCKSIZE_LOG
142 	    ||	sb_blocklog > XFS_MAX_BLOCKSIZE_LOG
143 	    ||	sb_blocksize != (uint32)(1 << sb_blocklog)
144 	    ||	sb_dirblklog + sb_blocklog > XFS_MAX_BLOCKSIZE_LOG
145 	    ||	sb_inodesize < INODE_MIN_SIZE
146 	    ||	sb_inodesize > INODE_MAX_SIZE
147 	    ||	sb_inodelog < INODE_MINSIZE_LOG
148 	    ||	sb_inodelog > INODE_MAXSIZE_LOG
149 	    ||	sb_inodesize != (1 << sb_inodelog)) {
150 
151 		ERROR("Sanity checking failed");
152 		return false;
153 	}
154 
155 	// Valid V5 Superblock
156 	return true;
157 }
158 
159 
160 bool
161 XfsSuperBlock::IsVersion5() const
162 {
163 	return (Version() & XFS_SB_VERSION_NUMBITS) == 5;
164 }
165 
166 
167 bool
168 XfsSuperBlock::XfsHasIncompatFeature() const
169 {
170 	return (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) != 0;
171 }
172 
173 
174 uint16
175 XfsSuperBlock::Version() const
176 {
177 	return sb_versionnum;
178 }
179 
180 
181 uint32
182 XfsSuperBlock::Features2() const
183 {
184 	return sb_features2;
185 }
186 
187 
188 uint32
189 XfsSuperBlock::BlockSize() const
190 {
191 	return sb_blocksize;
192 }
193 
194 
195 uint32
196 XfsSuperBlock::DirBlockLog() const
197 {
198 	return sb_dirblklog;
199 }
200 
201 
202 uint8
203 XfsSuperBlock::BlockLog() const
204 {
205 	return sb_blocklog;
206 }
207 
208 
209 uint32
210 XfsSuperBlock::DirBlockSize() const
211 {
212 	return BlockSize() * (1 << sb_dirblklog);
213 }
214 
215 
216 uint8
217 XfsSuperBlock::AgInodeBits() const
218 {
219 	return AgBlocksLog() + InodesPerBlkLog();
220 }
221 
222 
223 uint8
224 XfsSuperBlock::InodesPerBlkLog() const
225 {
226 	return sb_inopblog;
227 }
228 
229 
230 uint8
231 XfsSuperBlock::AgBlocksLog() const
232 {
233 	return sb_agblklog;
234 }
235 
236 
237 uint32
238 XfsSuperBlock::Size() const
239 {
240 	return XFS_SB_MAXSIZE;
241 }
242 
243 
244 uint16
245 XfsSuperBlock::InodeSize() const
246 {
247 	return sb_inodesize;
248 }
249 
250 
251 xfs_rfsblock_t
252 XfsSuperBlock::TotalBlocks() const
253 {
254 	return sb_dblocks;
255 }
256 
257 
258 xfs_rfsblock_t
259 XfsSuperBlock::TotalBlocksWithLog() const
260 {
261 	return TotalBlocks() + sb_logblocks;
262 }
263 
264 
265 uint64
266 XfsSuperBlock::FreeBlocks() const
267 {
268 	return sb_fdblocks;
269 }
270 
271 
272 uint64
273 XfsSuperBlock::UsedBlocks() const
274 {
275 	return TotalBlocks() - FreeBlocks();
276 }
277 
278 
279 const char*
280 XfsSuperBlock::Name() const
281 {
282 	return sb_fname;
283 }
284 
285 
286 xfs_ino_t
287 XfsSuperBlock::Root() const
288 {
289 	return sb_rootino;
290 }
291 
292 
293 xfs_agnumber_t
294 XfsSuperBlock::AgCount() const
295 {
296 	return sb_agcount;
297 }
298 
299 
300 xfs_agblock_t
301 XfsSuperBlock::AgBlocks() const
302 {
303 	return sb_agblocks;
304 }
305 
306 
307 uint32
308 XfsSuperBlock::Crc() const
309 {
310 	return sb_crc;
311 }
312 
313 
314 uint32
315 XfsSuperBlock::MagicNum() const
316 {
317 	return sb_magicnum;
318 }
319 
320 
321 bool
322 XfsSuperBlock::UuidEquals(const uuid_t& u1)
323 {
324 	if((sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID) != 0) {
325 		return memcmp(&u1, &sb_meta_uuid, sizeof(uuid_t)) == 0;
326 	} else {
327 		return memcmp(&u1, &sb_uuid, sizeof(uuid_t)) == 0;
328 	}
329 	return false;
330 }
331 
332 
333 void
334 XfsSuperBlock::SwapEndian()
335 {
336 	sb_magicnum				=	B_BENDIAN_TO_HOST_INT32(sb_magicnum);
337 	sb_blocksize			=	B_BENDIAN_TO_HOST_INT32(sb_blocksize);
338 	sb_dblocks				=	B_BENDIAN_TO_HOST_INT64(sb_dblocks);
339 	sb_rblocks				=	B_BENDIAN_TO_HOST_INT64(sb_rblocks);
340 	sb_rextents				=	B_BENDIAN_TO_HOST_INT64(sb_rextents);
341 	sb_logstart				=	B_BENDIAN_TO_HOST_INT64(sb_logstart);
342 	sb_rootino				=	B_BENDIAN_TO_HOST_INT64(sb_rootino);
343 	sb_rbmino				=	B_BENDIAN_TO_HOST_INT64(sb_rbmino);
344 	sb_rsumino				=	B_BENDIAN_TO_HOST_INT64(sb_rsumino);
345 	sb_rextsize				=	B_BENDIAN_TO_HOST_INT32(sb_rextsize);
346 	sb_agblocks				=	B_BENDIAN_TO_HOST_INT32(sb_agblocks);
347 	sb_agcount				=	B_BENDIAN_TO_HOST_INT32(sb_agcount);
348 	sb_rbmblocks			=	B_BENDIAN_TO_HOST_INT32(sb_rbmblocks);
349 	sb_logblocks			=	B_BENDIAN_TO_HOST_INT32(sb_logblocks);
350 	sb_versionnum			=	B_BENDIAN_TO_HOST_INT16(sb_versionnum);
351 	sb_sectsize				=	B_BENDIAN_TO_HOST_INT16(sb_sectsize);
352 	sb_inodesize			=	B_BENDIAN_TO_HOST_INT16(sb_inodesize);
353 	sb_inopblock			=	B_BENDIAN_TO_HOST_INT16(sb_inopblock);
354 	sb_icount				=	B_BENDIAN_TO_HOST_INT64(sb_icount);
355 	sb_ifree				=	B_BENDIAN_TO_HOST_INT64(sb_ifree);
356 	sb_fdblocks				=	B_BENDIAN_TO_HOST_INT64(sb_fdblocks);
357 	sb_frextents			=	B_BENDIAN_TO_HOST_INT64(sb_frextents);
358 	sb_uquotino				=	B_BENDIAN_TO_HOST_INT64(sb_uquotino);
359 	sb_gquotino				=	B_BENDIAN_TO_HOST_INT64(sb_gquotino);
360 	sb_qflags				=	B_BENDIAN_TO_HOST_INT16(sb_qflags);
361 	sb_inoalignmt			=	B_BENDIAN_TO_HOST_INT32(sb_inoalignmt);
362 	sb_unit					=	B_BENDIAN_TO_HOST_INT32(sb_unit);
363 	sb_width				=	B_BENDIAN_TO_HOST_INT32(sb_width);
364 	sb_logsectsize			=	B_BENDIAN_TO_HOST_INT16(sb_logsectsize);
365 	sb_logsunit				=	B_BENDIAN_TO_HOST_INT32(sb_logsunit);
366 	sb_features2			=	B_BENDIAN_TO_HOST_INT32(sb_features2);
367 	sb_bad_features2		=	B_BENDIAN_TO_HOST_INT32(sb_bad_features2);
368 	sb_features_compat		=	B_BENDIAN_TO_HOST_INT32(sb_features_compat);
369 	sb_features_ro_compat	=	B_BENDIAN_TO_HOST_INT32(sb_features_ro_compat);
370 	sb_features_incompat 	=	B_BENDIAN_TO_HOST_INT32(sb_features_incompat);
371 	sb_features_log_incompat =	B_BENDIAN_TO_HOST_INT32(sb_features_log_incompat);
372 	// crc is only used on disk, not in memory; just init to 0 here
373 	sb_crc					=	0;
374 	sb_spino_align			=	B_BENDIAN_TO_HOST_INT32(sb_spino_align);
375 	sb_pquotino				=	B_BENDIAN_TO_HOST_INT64(sb_pquotino);
376 	sb_lsn					=	B_BENDIAN_TO_HOST_INT64(sb_lsn);
377 }
378