1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: generic.c
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
7 * UPDATE HISTORY:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "ext2fs.h"
13 #ifdef __REACTOS__
14 #include "linux/ext4.h"
15 #else
16 #include "linux\ext4.h"
17 #endif
18
19 /* GLOBALS ***************************************************************/
20
21 extern PEXT2_GLOBAL Ext2Global;
22
23 /* DEFINITIONS *************************************************************/
24
25
26 /* FUNCTIONS ***************************************************************/
27
28 NTSTATUS
Ext2LoadSuper(IN PEXT2_VCB Vcb,IN BOOLEAN bVerify,OUT PEXT2_SUPER_BLOCK * Sb)29 Ext2LoadSuper(IN PEXT2_VCB Vcb,
30 IN BOOLEAN bVerify,
31 OUT PEXT2_SUPER_BLOCK * Sb)
32 {
33 NTSTATUS Status;
34 PEXT2_SUPER_BLOCK Ext2Sb = NULL;
35
36 Ext2Sb = (PEXT2_SUPER_BLOCK)
37 Ext2AllocatePool(
38 PagedPool,
39 SUPER_BLOCK_SIZE,
40 EXT2_SB_MAGIC
41 );
42 if (!Ext2Sb) {
43 Status = STATUS_INSUFFICIENT_RESOURCES;
44 goto errorout;
45 }
46
47 Status = Ext2ReadDisk(
48 Vcb,
49 (ULONGLONG) SUPER_BLOCK_OFFSET,
50 SUPER_BLOCK_SIZE,
51 (PVOID) Ext2Sb,
52 bVerify );
53
54 if (!NT_SUCCESS(Status)) {
55 Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
56 Ext2Sb = NULL;
57 }
58
59 errorout:
60
61 *Sb = Ext2Sb;
62 return Status;
63 }
64
65
66 BOOLEAN
Ext2SaveSuper(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb)67 Ext2SaveSuper(
68 IN PEXT2_IRP_CONTEXT IrpContext,
69 IN PEXT2_VCB Vcb
70 )
71 {
72 LONGLONG offset;
73 BOOLEAN rc;
74
75 offset = (LONGLONG) SUPER_BLOCK_OFFSET;
76 rc = Ext2SaveBuffer( IrpContext,
77 Vcb,
78 offset,
79 SUPER_BLOCK_SIZE,
80 Vcb->SuperBlock
81 );
82
83 if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
84 Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
85 }
86
87 return rc;
88 }
89
90
91 BOOLEAN
Ext2RefreshSuper(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb)92 Ext2RefreshSuper (
93 IN PEXT2_IRP_CONTEXT IrpContext,
94 IN PEXT2_VCB Vcb
95 )
96 {
97 LONGLONG offset;
98 IO_STATUS_BLOCK iosb;
99
100 offset = (LONGLONG) SUPER_BLOCK_OFFSET;
101 if (!CcCopyRead(
102 Vcb->Volume,
103 (PLARGE_INTEGER)&offset,
104 SUPER_BLOCK_SIZE,
105 TRUE,
106 (PVOID)Vcb->SuperBlock,
107 &iosb )) {
108 return FALSE;
109 }
110
111 if (!NT_SUCCESS(iosb.Status)) {
112 return FALSE;
113 }
114
115 /* reload root inode */
116 if (Vcb->McbTree) {
117
118 if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode))
119 return FALSE;
120
121 /* initializeroot node */
122 Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
123 Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
124 Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
125 Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
126 }
127
128 return TRUE;
129 }
130
131 VOID
Ext2DropGroupBH(IN PEXT2_VCB Vcb)132 Ext2DropGroupBH(IN PEXT2_VCB Vcb)
133 {
134 struct ext3_sb_info *sbi = &Vcb->sbi;
135 unsigned long i;
136
137 if (NULL == Vcb->sbi.s_gd) {
138 return;
139 }
140
141 for (i = 0; i < Vcb->sbi.s_gdb_count; i++) {
142 if (Vcb->sbi.s_gd[i].bh) {
143 fini_bh(&sbi->s_gd[i].bh);
144 Vcb->sbi.s_gd[i].bh = NULL;
145 }
146 }
147 }
148
149 VOID
Ext2PutGroup(IN PEXT2_VCB Vcb)150 Ext2PutGroup(IN PEXT2_VCB Vcb)
151 {
152 struct ext3_sb_info *sbi = &Vcb->sbi;
153 unsigned long i;
154
155
156 if (NULL == Vcb->sbi.s_gd) {
157 return;
158 }
159
160 Ext2DropGroupBH(Vcb);
161
162 kfree(Vcb->sbi.s_gd);
163 Vcb->sbi.s_gd = NULL;
164
165 ClearFlag(Vcb->Flags, VCB_GD_LOADED);
166 }
167
168
169 BOOLEAN
Ext2LoadGroupBH(IN PEXT2_VCB Vcb)170 Ext2LoadGroupBH(IN PEXT2_VCB Vcb)
171 {
172 struct super_block *sb = &Vcb->sb;
173 struct ext3_sb_info *sbi = &Vcb->sbi;
174 unsigned long i;
175 BOOLEAN rc = FALSE;
176
177 _SEH2_TRY {
178
179 ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
180 ASSERT (NULL != sbi->s_gd);
181
182 for (i = 0; i < sbi->s_gdb_count; i++) {
183 ASSERT (sbi->s_gd[i].block);
184 if (sbi->s_gd[i].bh)
185 continue;
186 sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
187 if (!sbi->s_gd[i].bh) {
188 DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i));
189 DbgBreak();
190 _SEH2_LEAVE;
191 }
192 sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
193 }
194
195 rc = TRUE;
196
197 } _SEH2_FINALLY {
198
199 ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
200 } _SEH2_END;
201
202 return rc;
203 }
204
205
206 BOOLEAN
Ext2LoadGroup(IN PEXT2_VCB Vcb)207 Ext2LoadGroup(IN PEXT2_VCB Vcb)
208 {
209 struct super_block *sb = &Vcb->sb;
210 struct ext3_sb_info *sbi = &Vcb->sbi;
211 ext3_fsblk_t sb_block = 1;
212 unsigned long i;
213 BOOLEAN rc = FALSE;
214
215 _SEH2_TRY {
216
217 ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
218
219 if (NULL == sbi->s_gd) {
220 sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd),
221 GFP_KERNEL);
222 }
223 if (sbi->s_gd == NULL) {
224 DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
225 _SEH2_LEAVE;
226 }
227
228 if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
229 sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
230 }
231
232 for (i = 0; i < sbi->s_gdb_count; i++) {
233 sbi->s_gd[i].block = descriptor_loc(sb, sb_block, i);
234 if (!sbi->s_gd[i].block) {
235 DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i));
236 _SEH2_LEAVE;
237 }
238 }
239
240 if (!Ext2LoadGroupBH(Vcb)) {
241 DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n"));
242 _SEH2_LEAVE;
243 }
244
245 if (!ext4_check_descriptors(sb)) {
246 DbgBreak();
247 DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n"));
248 _SEH2_LEAVE;
249 }
250
251 SetFlag(Vcb->Flags, VCB_GD_LOADED);
252 rc = TRUE;
253
254 } _SEH2_FINALLY {
255
256 if (!rc)
257 Ext2PutGroup(Vcb);
258
259 ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
260 } _SEH2_END;
261
262 return rc;
263 }
264
265 VOID
Ext2DropBH(IN PEXT2_VCB Vcb)266 Ext2DropBH(IN PEXT2_VCB Vcb)
267 {
268 struct ext3_sb_info *sbi = &Vcb->sbi;
269
270 /* do nothing if Vcb is not initialized yet */
271 if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
272 return;
273
274 _SEH2_TRY {
275
276 /* acquire bd lock to avoid bh creation */
277 ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
278
279 SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
280 Ext2DropGroupBH(Vcb);
281
282 while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
283 struct buffer_head *bh;
284 PLIST_ENTRY l;
285 l = RemoveHeadList(&Vcb->bd.bd_bh_free);
286 bh = CONTAINING_RECORD(l, struct buffer_head, b_link);
287 InitializeListHead(&bh->b_link);
288 if (0 == atomic_read(&bh->b_count)) {
289 buffer_head_remove(&Vcb->bd, bh);
290 free_buffer_head(bh);
291 }
292 }
293
294 } _SEH2_FINALLY {
295 ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
296 } _SEH2_END;
297
298 ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
299 }
300
301
302 VOID
Ext2FlushRange(IN PEXT2_VCB Vcb,LARGE_INTEGER s,LARGE_INTEGER e)303 Ext2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e)
304 {
305 ULONG len;
306
307 if (e.QuadPart <= s.QuadPart)
308 return;
309
310 /* loop per 2G */
311 while (s.QuadPart < e.QuadPart) {
312 if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) {
313 len = 1024 * 1024 * 1024;
314 } else {
315 len = (ULONG) (e.QuadPart - s.QuadPart);
316 }
317 CcFlushCache(&Vcb->SectionObject, &s, len, NULL);
318 s.QuadPart += len;
319 }
320 }
321
322 NTSTATUS
Ext2FlushVcb(IN PEXT2_VCB Vcb)323 Ext2FlushVcb(IN PEXT2_VCB Vcb)
324 {
325 LARGE_INTEGER s = {0}, o;
326 struct ext3_sb_info *sbi = &Vcb->sbi;
327 struct rb_node *node;
328 struct buffer_head *bh;
329
330 if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) {
331 CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
332 goto errorout;
333 }
334
335 ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource));
336
337 _SEH2_TRY {
338
339 /* acqurie gd block */
340 ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
341
342 /* acquire bd lock to avoid bh creation */
343 ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
344
345 /* drop unused bh */
346 Ext2DropBH(Vcb);
347
348 /* flush volume with all outstanding bh skipped */
349
350 node = rb_first(&Vcb->bd.bd_bh_root);
351 while (node) {
352
353 bh = container_of(node, struct buffer_head, b_rb_node);
354 node = rb_next(node);
355
356 o.QuadPart = bh->b_blocknr << BLOCK_BITS;
357 ASSERT(o.QuadPart >= s.QuadPart);
358
359 if (o.QuadPart == s.QuadPart) {
360 s.QuadPart = s.QuadPart + bh->b_size;
361 continue;
362 }
363
364 if (o.QuadPart > s.QuadPart) {
365 Ext2FlushRange(Vcb, s, o);
366 s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size;
367 continue;
368 }
369 }
370
371 o = Vcb->PartitionInformation.PartitionLength;
372 Ext2FlushRange(Vcb, s, o);
373
374 } _SEH2_FINALLY {
375
376 ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
377 ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
378 } _SEH2_END;
379
380 errorout:
381 return STATUS_SUCCESS;
382 }
383
384
385 BOOLEAN
Ext2SaveGroup(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG Group)386 Ext2SaveGroup(
387 IN PEXT2_IRP_CONTEXT IrpContext,
388 IN PEXT2_VCB Vcb,
389 IN ULONG Group
390 )
391 {
392 struct ext4_group_desc *gd;
393 struct buffer_head *gb = NULL;
394 unsigned long i;
395
396 gd = ext4_get_group_desc(&Vcb->sb, Group, &gb);
397 if (!gd)
398 return 0;
399
400 gd->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, gd);
401 mark_buffer_dirty(gb);
402 fini_bh(&gb);
403
404 return TRUE;
405 }
406
407
408 BOOLEAN
Ext2RefreshGroup(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb)409 Ext2RefreshGroup(
410 IN PEXT2_IRP_CONTEXT IrpContext,
411 IN PEXT2_VCB Vcb
412 )
413 {
414 return TRUE;
415 }
416
417 BOOLEAN
Ext2GetInodeLba(IN PEXT2_VCB Vcb,IN ULONG inode,OUT PLONGLONG offset)418 Ext2GetInodeLba (
419 IN PEXT2_VCB Vcb,
420 IN ULONG inode,
421 OUT PLONGLONG offset
422 )
423 {
424 PEXT2_GROUP_DESC gd;
425 struct buffer_head *bh = NULL;
426 ext4_fsblk_t loc;
427 int group;
428
429 if (inode < 1 || inode > INODES_COUNT) {
430 DEBUG(DL_ERR, ( "Ext2GetInodeLba: Inode value %xh is invalid.\n",inode));
431 *offset = 0;
432 return FALSE;
433 }
434
435 group = (inode - 1) / INODES_PER_GROUP ;
436 gd = ext4_get_group_desc(&Vcb->sb, group, &bh);
437 if (!bh) {
438 *offset = 0;
439 DbgBreak();
440 return FALSE;
441 }
442 loc = (LONGLONG)ext4_inode_table(&Vcb->sb, gd);
443 loc = loc << BLOCK_BITS;
444 loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
445
446 *offset = loc;
447 __brelse(bh);
448
449 return TRUE;
450 }
451
Ext2DecodeInode(struct inode * dst,struct ext3_inode * src)452 void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src)
453 {
454 dst->i_mode = src->i_mode;
455 dst->i_flags = src->i_flags;
456 dst->i_uid = src->i_uid;
457 dst->i_gid = src->i_gid;
458 dst->i_nlink = src->i_links_count;
459 dst->i_generation = src->i_generation;
460 dst->i_size = src->i_size;
461 if (S_ISREG(src->i_mode)) {
462 dst->i_size |= (loff_t)src->i_size_high << 32;
463 }
464 dst->i_file_acl = src->i_file_acl_lo;
465 dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32;
466 dst->i_atime = src->i_atime;
467 dst->i_ctime = src->i_ctime;
468 dst->i_mtime = src->i_mtime;
469 dst->i_dtime = src->i_dtime;
470 dst->i_blocks = ext3_inode_blocks(src, dst);
471 memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
472 if (EXT3_HAS_RO_COMPAT_FEATURE(dst->i_sb,
473 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
474 dst->i_extra_isize = src->i_extra_isize;
475 else
476 dst->i_extra_isize = 0;
477 }
478
Ext2EncodeInode(struct ext3_inode * dst,struct inode * src)479 void Ext2EncodeInode(struct ext3_inode *dst, struct inode *src)
480 {
481 dst->i_mode = src->i_mode;
482 dst->i_flags = src->i_flags;
483 dst->i_uid = src->i_uid;
484 dst->i_gid = src->i_gid;
485 dst->i_links_count = src->i_nlink;
486 dst->i_generation = src->i_generation;
487 dst->i_size = (__u32)src->i_size;
488 if (S_ISREG(src->i_mode)) {
489 dst->i_size_high = (__u32)(src->i_size >> 32);
490 }
491 dst->i_file_acl_lo = (__u32)src->i_file_acl;
492 dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32);
493 dst->i_atime = src->i_atime;
494 dst->i_ctime = src->i_ctime;
495 dst->i_mtime = src->i_mtime;
496 dst->i_dtime = src->i_dtime;
497 dst->i_extra_isize = src->i_extra_isize;
498 ASSERT(src->i_sb);
499 ext3_inode_blocks_set(dst, src);
500 memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
501 if (EXT3_HAS_RO_COMPAT_FEATURE(src->i_sb,
502 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
503 dst->i_extra_isize = src->i_extra_isize;
504 }
505
506
507 BOOLEAN
Ext2LoadInode(IN PEXT2_VCB Vcb,IN struct inode * Inode)508 Ext2LoadInode (IN PEXT2_VCB Vcb,
509 IN struct inode *Inode)
510 {
511 struct ext3_inode ext3i = {0};
512 LONGLONG offset;
513
514 if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset)) {
515 DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino));
516 return FALSE;
517 }
518
519 if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) {
520 return FALSE;
521 }
522
523 Ext2DecodeInode(Inode, &ext3i);
524
525 return TRUE;
526 }
527
528
529 BOOLEAN
Ext2ClearInode(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG Inode)530 Ext2ClearInode (
531 IN PEXT2_IRP_CONTEXT IrpContext,
532 IN PEXT2_VCB Vcb,
533 IN ULONG Inode)
534 {
535 LONGLONG Offset = 0;
536 BOOLEAN rc;
537
538 rc = Ext2GetInodeLba(Vcb, Inode, &Offset);
539 if (!rc) {
540 DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode));
541 goto errorout;
542 }
543
544 rc = Ext2ZeroBuffer(IrpContext, Vcb, Offset, Vcb->InodeSize);
545
546 errorout:
547
548 return rc;
549 }
550
551 BOOLEAN
Ext2SaveInode(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN struct inode * Inode)552 Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext,
553 IN PEXT2_VCB Vcb,
554 IN struct inode *Inode)
555 {
556 struct ext3_inode ext3i = {0};
557
558 LONGLONG Offset = 0;
559 ULONG InodeSize = sizeof(ext3i);
560 BOOLEAN rc = 0;
561
562 DEBUG(DL_INF, ( "Ext2SaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
563 Inode->i_ino, Inode->i_mode, Inode->i_size));
564 rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
565 if (!rc) {
566 DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino));
567 goto errorout;
568 }
569
570 rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext3i);
571 if (!rc) {
572 DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino));
573 goto errorout;;
574 }
575
576 Ext2EncodeInode(&ext3i, Inode);
577 if (InodeSize > Vcb->InodeSize)
578 InodeSize = Vcb->InodeSize;
579 rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, InodeSize, &ext3i);
580
581 if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
582 Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
583 }
584
585 errorout:
586 return rc;
587 }
588
589 BOOLEAN
Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,IN struct inode * Inode,IN PEXT2_INODE InodeXattr)590 Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,
591 IN struct inode *Inode,
592 IN PEXT2_INODE InodeXattr)
593 {
594 IO_STATUS_BLOCK IoStatus;
595 LONGLONG Offset;
596
597 if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) {
598 DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
599 return FALSE;
600 }
601
602 if (!CcCopyRead(
603 Vcb->Volume,
604 (PLARGE_INTEGER)&Offset,
605 Vcb->InodeSize,
606 PIN_WAIT,
607 (PVOID)InodeXattr,
608 &IoStatus)) {
609 return FALSE;
610 }
611
612 if (!NT_SUCCESS(IoStatus.Status)) {
613 return FALSE;
614 }
615
616 Ext2EncodeInode(InodeXattr, Inode);
617 return TRUE;
618 }
619
620 BOOLEAN
Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN struct inode * Inode,IN PEXT2_INODE InodeXattr)621 Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,
622 IN PEXT2_VCB Vcb,
623 IN struct inode *Inode,
624 IN PEXT2_INODE InodeXattr)
625 {
626 IO_STATUS_BLOCK IoStatus;
627 LONGLONG Offset = 0;
628 ULONG InodeSize = Vcb->InodeSize;
629 BOOLEAN rc = 0;
630
631 /* There is no way to put EA information in such a small inode */
632 if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE)
633 return FALSE;
634
635 DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n",
636 Inode->i_ino, Inode->i_mode, Inode->i_size));
637 rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
638 if (!rc) {
639 DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino));
640 goto errorout;
641 }
642
643 rc = Ext2SaveBuffer(IrpContext,
644 Vcb,
645 Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize,
646 InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize,
647 (char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize);
648
649 if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
650 Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
651 }
652
653 errorout:
654 return rc;
655 }
656
657
658 BOOLEAN
Ext2LoadBlock(IN PEXT2_VCB Vcb,IN ULONG Index,IN PVOID Buffer)659 Ext2LoadBlock (IN PEXT2_VCB Vcb,
660 IN ULONG Index,
661 IN PVOID Buffer )
662 {
663 struct buffer_head *bh = NULL;
664 BOOLEAN rc = 0;
665
666 _SEH2_TRY {
667
668 bh = sb_getblk(&Vcb->sb, (sector_t)Index);
669
670 if (!bh) {
671 DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index));
672 DbgBreak();
673 _SEH2_LEAVE;
674 }
675
676 if (!buffer_uptodate(bh)) {
677 int err = bh_submit_read(bh);
678 if (err < 0) {
679 DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err));
680 _SEH2_LEAVE;
681 }
682 }
683
684 RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE);
685 rc = TRUE;
686
687 } _SEH2_FINALLY {
688
689 if (bh)
690 fini_bh(&bh);
691 } _SEH2_END;
692
693 return rc;
694 }
695
696
697 BOOLEAN
Ext2SaveBlock(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG Index,IN PVOID Buf)698 Ext2SaveBlock ( IN PEXT2_IRP_CONTEXT IrpContext,
699 IN PEXT2_VCB Vcb,
700 IN ULONG Index,
701 IN PVOID Buf )
702 {
703 struct buffer_head *bh = NULL;
704 BOOLEAN rc = 0;
705
706 _SEH2_TRY {
707
708 bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index);
709
710 if (!bh) {
711 DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index));
712 DbgBreak();
713 _SEH2_LEAVE;
714 }
715
716 if (!buffer_uptodate(bh)) {
717 }
718
719 RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE);
720 mark_buffer_dirty(bh);
721 rc = TRUE;
722
723 } _SEH2_FINALLY {
724
725 if (bh)
726 fini_bh(&bh);
727 } _SEH2_END;
728
729 return rc;
730 }
731
732 BOOLEAN
Ext2LoadBuffer(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN LONGLONG offset,IN ULONG size,IN PVOID buf)733 Ext2LoadBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
734 IN PEXT2_VCB Vcb,
735 IN LONGLONG offset,
736 IN ULONG size,
737 IN PVOID buf )
738 {
739 struct buffer_head *bh = NULL;
740 BOOLEAN rc;
741
742 _SEH2_TRY {
743
744 while (size) {
745
746 sector_t block;
747 ULONG len = 0, delta = 0;
748
749 block = (sector_t) (offset >> BLOCK_BITS);
750 delta = (ULONG)offset & (BLOCK_SIZE - 1);
751 len = BLOCK_SIZE - delta;
752 if (size < len)
753 len = size;
754
755 bh = sb_getblk(&Vcb->sb, block);
756 if (!bh) {
757 DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
758 DbgBreak();
759 _SEH2_LEAVE;
760 }
761
762 if (!buffer_uptodate(bh)) {
763 int err = bh_submit_read(bh);
764 if (err < 0) {
765 DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
766 _SEH2_LEAVE;
767 }
768 }
769
770 _SEH2_TRY {
771 RtlCopyMemory(buf, bh->b_data + delta, len);
772 } _SEH2_FINALLY {
773 fini_bh(&bh);
774 } _SEH2_END;
775
776 buf = (PUCHAR)buf + len;
777 offset = offset + len;
778 size = size - len;
779 }
780
781 rc = TRUE;
782
783 } _SEH2_FINALLY {
784
785 if (bh)
786 fini_bh(&bh);
787
788 } _SEH2_END;
789
790 return rc;
791 }
792
793
794 BOOLEAN
Ext2ZeroBuffer(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN LONGLONG offset,IN ULONG size)795 Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
796 IN PEXT2_VCB Vcb,
797 IN LONGLONG offset,
798 IN ULONG size
799 )
800 {
801 struct buffer_head *bh = NULL;
802 BOOLEAN rc = 0;
803
804 _SEH2_TRY {
805
806 while (size) {
807
808 sector_t block;
809 ULONG len = 0, delta = 0;
810
811 block = (sector_t) (offset >> BLOCK_BITS);
812 delta = (ULONG)offset & (BLOCK_SIZE - 1);
813 len = BLOCK_SIZE - delta;
814 if (size < len)
815 len = size;
816
817 if (delta == 0 && len >= BLOCK_SIZE) {
818 bh = sb_getblk_zero(&Vcb->sb, block);
819 } else {
820 bh = sb_getblk(&Vcb->sb, block);
821 }
822
823 if (!bh) {
824 DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
825 DbgBreak();
826 _SEH2_LEAVE;
827 }
828
829 if (!buffer_uptodate(bh)) {
830 int err = bh_submit_read(bh);
831 if (err < 0) {
832 DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
833 _SEH2_LEAVE;
834 }
835 }
836
837 _SEH2_TRY {
838 if (delta == 0 && len >= BLOCK_SIZE) {
839 /* bh (cache) was already cleaned as zero */
840 } else {
841 RtlZeroMemory(bh->b_data + delta, len);
842 }
843 mark_buffer_dirty(bh);
844 } _SEH2_FINALLY {
845 fini_bh(&bh);
846 } _SEH2_END;
847
848 offset = offset + len;
849 size = size - len;
850 }
851
852 rc = TRUE;
853
854 } _SEH2_FINALLY {
855
856 if (bh)
857 fini_bh(&bh);
858
859 } _SEH2_END;
860
861 return rc;
862 }
863
864
865 #ifdef __REACTOS__
866 #define SIZE_256K 0x40000
867
868 BOOLEAN
Ext2SaveBuffer(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN LONGLONG Offset,IN ULONG Size,IN PVOID Buf)869 Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
870 IN PEXT2_VCB Vcb,
871 IN LONGLONG Offset,
872 IN ULONG Size,
873 IN PVOID Buf )
874 {
875 BOOLEAN rc;
876
877 while (Size) {
878
879 PBCB Bcb;
880 PVOID Buffer;
881 ULONG Length;
882
883 Length = (ULONG)Offset & (SIZE_256K - 1);
884 Length = SIZE_256K - Length;
885 if (Size < Length)
886 Length = Size;
887
888 if ( !CcPreparePinWrite(
889 Vcb->Volume,
890 (PLARGE_INTEGER) (&Offset),
891 Length,
892 FALSE,
893 PIN_WAIT | PIN_EXCLUSIVE,
894 &Bcb,
895 &Buffer )) {
896
897 DEBUG(DL_ERR, ( "Ext2SaveBuffer: failed to PinLock offset %I64xh ...\n", Offset));
898 return FALSE;
899 }
900
901 _SEH2_TRY {
902
903 RtlCopyMemory(Buffer, Buf, Length);
904 CcSetDirtyPinnedData(Bcb, NULL );
905 SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
906
907 rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length);
908 if (!rc) {
909 DbgBreak();
910 Ext2Sleep(100);
911 rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length);
912 }
913
914 } _SEH2_FINALLY {
915 CcUnpinData(Bcb);
916 } _SEH2_END;
917
918 Buf = (PUCHAR)Buf + Length;
919 Offset = Offset + Length;
920 Size = Size - Length;
921 }
922
923 return rc;
924 }
925 #else
926
927 BOOLEAN
Ext2SaveBuffer(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN LONGLONG offset,IN ULONG size,IN PVOID buf)928 Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
929 IN PEXT2_VCB Vcb,
930 IN LONGLONG offset,
931 IN ULONG size,
932 IN PVOID buf )
933 {
934 struct buffer_head *bh = NULL;
935 BOOLEAN rc = 0;
936
937 __try {
938
939 while (size) {
940
941 sector_t block;
942 ULONG len = 0, delta = 0;
943
944 block = (sector_t) (offset >> BLOCK_BITS);
945 delta = (ULONG)offset & (BLOCK_SIZE - 1);
946 len = BLOCK_SIZE - delta;
947 if (size < len)
948 len = size;
949
950 if (delta == 0 && len >= BLOCK_SIZE) {
951 bh = sb_getblk_zero(&Vcb->sb, block);
952 } else {
953 bh = sb_getblk(&Vcb->sb, block);
954 }
955
956 if (!bh) {
957 DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
958 DbgBreak();
959 __leave;
960 }
961
962 if (!buffer_uptodate(bh)) {
963 int err = bh_submit_read(bh);
964 if (err < 0) {
965 DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
966 __leave;
967 }
968 }
969
970 __try {
971 RtlCopyMemory(bh->b_data + delta, buf, len);
972 mark_buffer_dirty(bh);
973 } __finally {
974 fini_bh(&bh);
975 }
976
977 buf = (PUCHAR)buf + len;
978 offset = offset + len;
979 size = size - len;
980 }
981
982 rc = TRUE;
983
984 } __finally {
985
986 if (bh)
987 fini_bh(&bh);
988
989 }
990
991 return rc;
992 }
993 #endif
994
995
996 VOID
Ext2UpdateVcbStat(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb)997 Ext2UpdateVcbStat(
998 IN PEXT2_IRP_CONTEXT IrpContext,
999 IN PEXT2_VCB Vcb
1000 )
1001 {
1002 Vcb->SuperBlock->s_free_inodes_count = ext4_count_free_inodes(&Vcb->sb);
1003 ext3_free_blocks_count_set(SUPER_BLOCK, ext4_count_free_blocks(&Vcb->sb));
1004 Ext2SaveSuper(IrpContext, Vcb);
1005 }
1006
1007 NTSTATUS
Ext2NewBlock(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG GroupHint,IN ULONG BlockHint,OUT PULONG Block,IN OUT PULONG Number)1008 Ext2NewBlock(
1009 IN PEXT2_IRP_CONTEXT IrpContext,
1010 IN PEXT2_VCB Vcb,
1011 IN ULONG GroupHint,
1012 IN ULONG BlockHint,
1013 OUT PULONG Block,
1014 IN OUT PULONG Number
1015 )
1016 {
1017 struct super_block *sb = &Vcb->sb;
1018 PEXT2_GROUP_DESC gd;
1019 struct buffer_head *gb = NULL;
1020 struct buffer_head *bh = NULL;
1021 ext4_fsblk_t bitmap_blk;
1022
1023 RTL_BITMAP BlockBitmap;
1024
1025 ULONG Group = 0;
1026 ULONG Index = 0xFFFFFFFF;
1027 ULONG dwHint = 0;
1028 ULONG Count = 0;
1029 ULONG Length = 0;
1030
1031 NTSTATUS Status = STATUS_DISK_FULL;
1032
1033 *Block = 0;
1034
1035 ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
1036
1037 /* validate the hint group and hint block */
1038 if (GroupHint >= Vcb->sbi.s_groups_count) {
1039 DbgBreak();
1040 GroupHint = Vcb->sbi.s_groups_count - 1;
1041 }
1042
1043 if (BlockHint != 0) {
1044 GroupHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1045 dwHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1046 }
1047
1048 Group = GroupHint;
1049
1050 Again:
1051
1052 if (bh)
1053 fini_bh(&bh);
1054
1055 if (gb)
1056 fini_bh(&gb);
1057
1058 gd = ext4_get_group_desc(sb, Group, &gb);
1059 if (!gd) {
1060 DbgBreak();
1061 Status = STATUS_INSUFFICIENT_RESOURCES;
1062 goto errorout;
1063 }
1064
1065 bitmap_blk = ext4_block_bitmap(sb, gd);
1066
1067 if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
1068 bh = sb_getblk_zero(sb, bitmap_blk);
1069 if (!bh) {
1070 DbgBreak();
1071 Status = STATUS_INSUFFICIENT_RESOURCES;
1072 goto errorout;
1073 }
1074 gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
1075 ext4_init_block_bitmap(sb, bh, Group, gd);
1076 set_buffer_uptodate(bh);
1077 gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
1078 Ext2SaveGroup(IrpContext, Vcb, Group);
1079 } else {
1080 bh = sb_getblk(sb, bitmap_blk);
1081 if (!bh) {
1082 DbgBreak();
1083 Status = STATUS_INSUFFICIENT_RESOURCES;
1084 goto errorout;
1085 }
1086 }
1087
1088 if (!buffer_uptodate(bh)) {
1089 int err = bh_submit_read(bh);
1090 if (err < 0) {
1091 DbgPrint("bh_submit_read error! err: %d\n", err);
1092 Status = Ext2WinntError(err);
1093 goto errorout;
1094 }
1095 }
1096
1097 if (ext4_free_blks_count(sb, gd)) {
1098
1099 if (Group == Vcb->sbi.s_groups_count - 1) {
1100
1101 Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1102
1103 /* s_blocks_count is integer multiple of s_blocks_per_group */
1104 if (Length == 0) {
1105 Length = BLOCKS_PER_GROUP;
1106 }
1107 } else {
1108 Length = BLOCKS_PER_GROUP;
1109 }
1110
1111 /* initialize bitmap buffer */
1112 RtlInitializeBitMap(&BlockBitmap, (PULONG)bh->b_data, Length);
1113
1114 /* try to find a clear bit range */
1115 Index = RtlFindClearBits(&BlockBitmap, *Number, dwHint);
1116
1117 /* We could not get new block in the prefered group */
1118 if (Index == 0xFFFFFFFF) {
1119
1120 /* search clear bits from the hint block */
1121 Count = RtlFindNextForwardRunClear(&BlockBitmap, dwHint, &Index);
1122 if (dwHint != 0 && Count == 0) {
1123 /* search clear bits from the very beginning */
1124 Count = RtlFindNextForwardRunClear(&BlockBitmap, 0, &Index);
1125 }
1126
1127 if (Count == 0) {
1128
1129 RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
1130
1131 /* no blocks found: set bg_free_blocks_count to 0 */
1132 ext4_free_blks_set(sb, gd, 0);
1133 Ext2SaveGroup(IrpContext, Vcb, Group);
1134
1135 /* will try next group */
1136 goto Again;
1137
1138 } else {
1139
1140 /* we got free blocks */
1141 if (Count <= *Number) {
1142 *Number = Count;
1143 }
1144 }
1145 }
1146
1147 } else {
1148
1149 /* try next group */
1150 dwHint = 0;
1151 Group = (Group + 1) % Vcb->sbi.s_groups_count;
1152 if (Group != GroupHint) {
1153 goto Again;
1154 }
1155
1156 Index = 0xFFFFFFFF;
1157 }
1158
1159 if (Index < Length) {
1160
1161 /* mark block bits as allocated */
1162 RtlSetBits(&BlockBitmap, Index, *Number);
1163
1164 /* set block bitmap dirty in cache */
1165 mark_buffer_dirty(bh);
1166
1167 /* update group description */
1168 ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
1169 Ext2SaveGroup(IrpContext, Vcb, Group);
1170
1171 /* update Vcb free blocks */
1172 Ext2UpdateVcbStat(IrpContext, Vcb);
1173
1174 /* validate the new allocated block number */
1175 *Block = Index + EXT2_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP;
1176 if (*Block >= TOTAL_BLOCKS || *Block + *Number > TOTAL_BLOCKS) {
1177 DbgBreak();
1178 dwHint = 0;
1179 goto Again;
1180 }
1181
1182 if (ext4_block_bitmap(sb, gd) == *Block ||
1183 ext4_inode_bitmap(sb, gd) == *Block ||
1184 ext4_inode_table(sb, gd) == *Block ) {
1185 DbgBreak();
1186 dwHint = 0;
1187 goto Again;
1188 }
1189
1190 /* Always remove dirty MCB to prevent Volume's lazy writing.
1191 Metadata blocks will be re-added during modifications.*/
1192 if (Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number)) {
1193 } else {
1194 DbgBreak();
1195 Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number);
1196 }
1197
1198 DEBUG(DL_INF, ("Ext2NewBlock: Block %xh - %x allocated.\n",
1199 *Block, *Block + *Number));
1200 Status = STATUS_SUCCESS;
1201 }
1202
1203 errorout:
1204
1205 ExReleaseResourceLite(&Vcb->MetaBlock);
1206
1207 if (bh)
1208 fini_bh(&bh);
1209
1210 if (gb)
1211 fini_bh(&gb);
1212
1213 return Status;
1214 }
1215
1216 NTSTATUS
Ext2FreeBlock(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG Block,IN ULONG Number)1217 Ext2FreeBlock(
1218 IN PEXT2_IRP_CONTEXT IrpContext,
1219 IN PEXT2_VCB Vcb,
1220 IN ULONG Block,
1221 IN ULONG Number
1222 )
1223 {
1224 struct super_block *sb = &Vcb->sb;
1225 PEXT2_GROUP_DESC gd;
1226 struct buffer_head *gb = NULL;
1227 ext4_fsblk_t bitmap_blk;
1228
1229 RTL_BITMAP BlockBitmap;
1230 LARGE_INTEGER Offset;
1231
1232 PBCB BitmapBcb;
1233 PVOID BitmapCache;
1234
1235 ULONG Group;
1236 ULONG Index;
1237 ULONG Length;
1238 ULONG Count;
1239
1240 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1241
1242 ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
1243
1244 DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n",
1245 Block, Block + Number));
1246
1247 Group = (Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1248 Index = (Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1249
1250 Again:
1251
1252 if (gb)
1253 fini_bh(&gb);
1254
1255 if ( Block < EXT2_FIRST_DATA_BLOCK ||
1256 Block >= TOTAL_BLOCKS ||
1257 Group >= Vcb->sbi.s_groups_count) {
1258
1259 DbgBreak();
1260 Status = STATUS_SUCCESS;
1261
1262 } else {
1263
1264 gd = ext4_get_group_desc(sb, Group, &gb);
1265 if (!gd) {
1266 DbgBreak();
1267 Status = STATUS_INSUFFICIENT_RESOURCES;
1268 goto errorout;
1269 }
1270 bitmap_blk = ext4_block_bitmap(sb, gd);
1271
1272 /* check the block is valid or not */
1273 if (bitmap_blk >= TOTAL_BLOCKS) {
1274 DbgBreak();
1275 Status = STATUS_DISK_CORRUPT_ERROR;
1276 goto errorout;
1277 }
1278
1279 /* get bitmap block offset and length */
1280 Offset.QuadPart = bitmap_blk;
1281 Offset.QuadPart = Offset.QuadPart << BLOCK_BITS;
1282
1283 if (Group == Vcb->sbi.s_groups_count - 1) {
1284
1285 Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1286
1287 /* s_blocks_count is integer multiple of s_blocks_per_group */
1288 if (Length == 0) {
1289 Length = BLOCKS_PER_GROUP;
1290 }
1291
1292 } else {
1293 Length = BLOCKS_PER_GROUP;
1294 }
1295
1296 /* read and initialize bitmap */
1297 if (!CcPinRead( Vcb->Volume,
1298 &Offset,
1299 Vcb->BlockSize,
1300 PIN_WAIT,
1301 &BitmapBcb,
1302 &BitmapCache ) ) {
1303
1304 DEBUG(DL_ERR, ("Ext2FreeBlock: failed to PinLock bitmap block %xh.\n",
1305 bitmap_blk));
1306 Status = STATUS_CANT_WAIT;
1307 DbgBreak();
1308 goto errorout;
1309 }
1310
1311 /* clear usused bits */
1312 RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length);
1313 Count = min(Length - Index, Number);
1314 RtlClearBits(&BlockBitmap, Index, Count);
1315
1316 /* update group description table */
1317 ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
1318
1319 /* indict the cache range is dirty */
1320 CcSetDirtyPinnedData(BitmapBcb, NULL );
1321 Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
1322 CcUnpinData(BitmapBcb);
1323 BitmapBcb = NULL;
1324 BitmapCache = NULL;
1325 Ext2SaveGroup(IrpContext, Vcb, Group);
1326
1327 /* remove dirty MCB to prevent Volume's lazy writing. */
1328 if (Ext2RemoveBlockExtent(Vcb, NULL, Block, Count)) {
1329 } else {
1330 DbgBreak();
1331 Ext2RemoveBlockExtent(Vcb, NULL, Block, Count);
1332 }
1333
1334 /* save super block (used/unused blocks statics) */
1335 Ext2UpdateVcbStat(IrpContext, Vcb);
1336
1337 /* try next group to clear all remaining */
1338 Number -= Count;
1339 if (Number) {
1340 Group += 1;
1341 if (Group < Vcb->sbi.s_groups_count) {
1342 Index = 0;
1343 Block += Count;
1344 goto Again;
1345 } else {
1346 DEBUG(DL_ERR, ("Ext2FreeBlock: block number beyonds max group.\n"));
1347 goto errorout;
1348 }
1349 }
1350 }
1351
1352 Status = STATUS_SUCCESS;
1353
1354 errorout:
1355
1356 if (gb)
1357 fini_bh(&gb);
1358
1359 ExReleaseResourceLite(&Vcb->MetaBlock);
1360
1361 return Status;
1362 }
1363
1364
1365 NTSTATUS
Ext2NewInode(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG GroupHint,IN ULONG Type,OUT PULONG Inode)1366 Ext2NewInode(
1367 IN PEXT2_IRP_CONTEXT IrpContext,
1368 IN PEXT2_VCB Vcb,
1369 IN ULONG GroupHint,
1370 IN ULONG Type,
1371 OUT PULONG Inode
1372 )
1373 {
1374 struct super_block *sb = &Vcb->sb;
1375 PEXT2_GROUP_DESC gd;
1376 struct buffer_head *gb = NULL;
1377 struct buffer_head *bh = NULL;
1378 ext4_fsblk_t bitmap_blk;
1379
1380 RTL_BITMAP InodeBitmap;
1381
1382 ULONG Group, i, j;
1383 ULONG Average, Length;
1384
1385 ULONG dwInode;
1386
1387 NTSTATUS Status = STATUS_DISK_FULL;
1388
1389 *Inode = dwInode = 0XFFFFFFFF;
1390
1391 ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
1392
1393 if (GroupHint >= Vcb->sbi.s_groups_count)
1394 GroupHint = GroupHint % Vcb->sbi.s_groups_count;
1395
1396 repeat:
1397
1398 if (bh)
1399 fini_bh(&bh);
1400
1401 if (gb)
1402 fini_bh(&gb);
1403
1404 Group = i = 0;
1405 gd = NULL;
1406
1407 if (Type == EXT2_FT_DIR) {
1408
1409 Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->sbi.s_groups_count;
1410
1411 for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
1412
1413 i = (j + GroupHint) % (Vcb->sbi.s_groups_count);
1414 gd = ext4_get_group_desc(sb, i, &gb);
1415 if (!gd) {
1416 DbgBreak();
1417 Status = STATUS_INSUFFICIENT_RESOURCES;
1418 goto errorout;
1419 }
1420
1421 if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
1422 (ext4_used_dirs_count(sb, gd) << 8 <
1423 ext4_free_inodes_count(sb, gd)) ) {
1424 Group = i + 1;
1425 break;
1426 }
1427 fini_bh(&gb);
1428 }
1429
1430 if (!Group) {
1431
1432 PEXT2_GROUP_DESC desc = NULL;
1433
1434 gd = NULL;
1435
1436 /* get the group with the biggest vacancy */
1437 for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
1438
1439 struct buffer_head *gt = NULL;
1440 desc = ext4_get_group_desc(sb, j, >);
1441 if (!desc) {
1442 DbgBreak();
1443 Status = STATUS_INSUFFICIENT_RESOURCES;
1444 goto errorout;
1445 }
1446
1447 /* return the group if it's not initialized yet */
1448 if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
1449 Group = j + 1;
1450 gd = desc;
1451
1452 if (gb)
1453 fini_bh(&gb);
1454 gb = gt;
1455 gt = NULL;
1456 break;
1457 }
1458
1459 if (!gd) {
1460 if (ext4_free_inodes_count(sb, desc) > 0) {
1461 Group = j + 1;
1462 gd = desc;
1463 if (gb)
1464 fini_bh(&gb);
1465 gb = gt;
1466 gt = NULL;
1467 }
1468 } else {
1469 if (ext4_free_inodes_count(sb, desc) >
1470 ext4_free_inodes_count(sb, gd)) {
1471 Group = j + 1;
1472 gd = desc;
1473 if (gb)
1474 fini_bh(&gb);
1475 gb = gt;
1476 gt = NULL;
1477 break;
1478 }
1479 }
1480 if (gt)
1481 fini_bh(>);
1482 }
1483 }
1484
1485 } else {
1486
1487 /*
1488 * Try to place the inode in its parent directory (GroupHint)
1489 */
1490
1491 gd = ext4_get_group_desc(sb, GroupHint, &gb);
1492 if (!gb) {
1493 DbgBreak();
1494 Status = STATUS_INSUFFICIENT_RESOURCES;
1495 goto errorout;
1496 }
1497
1498 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
1499 ext4_free_inodes_count(sb, gd)) {
1500
1501 Group = GroupHint + 1;
1502
1503 } else {
1504
1505 /* this group is 100% cocucpied */
1506 fini_bh(&gb);
1507
1508 i = GroupHint;
1509
1510 /*
1511 * Use a quadratic hash to find a group with a free inode
1512 */
1513
1514 for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
1515
1516
1517 i = (i + j) % Vcb->sbi.s_groups_count;
1518 gd = ext4_get_group_desc(sb, i, &gb);
1519 if (!gd) {
1520 DbgBreak();
1521 Status = STATUS_INSUFFICIENT_RESOURCES;
1522 goto errorout;
1523 }
1524
1525 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
1526 ext4_free_inodes_count(sb, gd)) {
1527 Group = i + 1;
1528 break;
1529 }
1530
1531 fini_bh(&gb);
1532 }
1533 }
1534
1535 if (!Group) {
1536 /*
1537 * That failed: try linear search for a free inode
1538 */
1539 i = GroupHint;
1540 for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
1541
1542 i = (i + 1) % Vcb->sbi.s_groups_count;
1543 gd = ext4_get_group_desc(sb, i, &gb);
1544 if (!gd) {
1545 DbgBreak();
1546 Status = STATUS_INSUFFICIENT_RESOURCES;
1547 goto errorout;
1548 }
1549
1550 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
1551 ext4_free_inodes_count(sb, gd)) {
1552 Group = i + 1;
1553 break;
1554 }
1555
1556 fini_bh(&gb);
1557 }
1558 }
1559 }
1560
1561 if (gd == NULL || Group == 0) {
1562 goto errorout;
1563 }
1564
1565 /* finally we got the group, but is it valid ? */
1566 if (Group > Vcb->sbi.s_groups_count) {
1567 DbgBreak();
1568 goto errorout;
1569 }
1570
1571 /* valid group number starts from 1, not 0 */
1572 Group -= 1;
1573
1574 ASSERT(gd);
1575 bitmap_blk = ext4_inode_bitmap(sb, gd);
1576 /* check the block is valid or not */
1577 if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) {
1578 DbgBreak();
1579 Status = STATUS_DISK_CORRUPT_ERROR;
1580 goto errorout;
1581 }
1582
1583 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
1584 bh = sb_getblk_zero(sb, bitmap_blk);
1585 if (!bh) {
1586 DbgBreak();
1587 Status = STATUS_INSUFFICIENT_RESOURCES;
1588 goto errorout;
1589 }
1590 gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
1591 ext4_init_inode_bitmap(sb, bh, Group, gd);
1592 set_buffer_uptodate(bh);
1593 gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
1594 Ext2SaveGroup(IrpContext, Vcb, Group);
1595 } else {
1596 bh = sb_getblk(sb, bitmap_blk);
1597 if (!bh) {
1598 DbgBreak();
1599 Status = STATUS_INSUFFICIENT_RESOURCES;
1600 goto errorout;
1601 }
1602 }
1603
1604 if (!buffer_uptodate(bh)) {
1605 int err = bh_submit_read(bh);
1606 if (err < 0) {
1607 DbgPrint("bh_submit_read error! err: %d\n", err);
1608 Status = Ext2WinntError(err);
1609 goto errorout;
1610 }
1611 }
1612
1613 if (Vcb->sbi.s_groups_count == 1) {
1614 Length = INODES_COUNT;
1615 } else {
1616 if (Group + 1 == Vcb->sbi.s_groups_count) {
1617 Length = INODES_COUNT % INODES_PER_GROUP;
1618 if (!Length) {
1619 /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
1620 Length = INODES_PER_GROUP;
1621 }
1622 } else {
1623 Length = INODES_PER_GROUP;
1624 }
1625 }
1626
1627 RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
1628 dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
1629
1630 if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
1631
1632 RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
1633 if (ext4_free_inodes_count(sb, gd) > 0) {
1634 ext4_free_inodes_set(sb, gd, 0);
1635 Ext2SaveGroup(IrpContext, Vcb, Group);
1636 }
1637 goto repeat;
1638
1639 } else {
1640
1641 __u32 count = 0;
1642
1643 /* update unused inodes count */
1644 count = ext4_free_inodes_count(sb, gd) - 1;
1645 ext4_free_inodes_set(sb, gd, count);
1646
1647 RtlSetBits(&InodeBitmap, dwInode, 1);
1648
1649 /* set block bitmap dirty in cache */
1650 mark_buffer_dirty(bh);
1651
1652 /* If we didn't allocate from within the initialized part of the inode
1653 * table then we need to initialize up to this inode. */
1654 if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
1655
1656 __u32 free;
1657
1658 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
1659 gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
1660 /* When marking the block group with
1661 * ~EXT4_BG_INODE_UNINIT we don't want to depend
1662 * on the value of bg_itable_unused even though
1663 * mke2fs could have initialized the same for us.
1664 * Instead we calculated the value below
1665 */
1666
1667 free = 0;
1668 } else {
1669 free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd);
1670 }
1671
1672 /*
1673 * Check the relative inode number against the last used
1674 * relative inode number in this group. if it is greater
1675 * we need to update the bg_itable_unused count
1676 *
1677 */
1678 if (dwInode + 1 > free) {
1679 ext4_itable_unused_set(sb, gd,
1680 (EXT3_INODES_PER_GROUP(sb) - 1 - dwInode));
1681 }
1682
1683 /* We may have to initialize the block bitmap if it isn't already */
1684 if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
1685
1686 struct buffer_head *block_bitmap_bh = NULL;
1687
1688 /* recheck and clear flag under lock if we still need to */
1689 block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd));
1690 if (block_bitmap_bh) {
1691 gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
1692 free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd);
1693 set_buffer_uptodate(block_bitmap_bh);
1694 brelse(block_bitmap_bh);
1695 gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
1696 ext4_free_blks_set(sb, gd, free);
1697 Ext2SaveGroup(IrpContext, Vcb, Group);
1698 }
1699 }
1700 }
1701
1702 *Inode = dwInode + 1 + Group * INODES_PER_GROUP;
1703
1704 /* update group_desc / super_block */
1705 if (Type == EXT2_FT_DIR) {
1706 ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1);
1707 }
1708 Ext2SaveGroup(IrpContext, Vcb, Group);
1709 Ext2UpdateVcbStat(IrpContext, Vcb);
1710 Status = STATUS_SUCCESS;
1711 }
1712
1713 errorout:
1714
1715 ExReleaseResourceLite(&Vcb->MetaInode);
1716
1717 if (bh)
1718 fini_bh(&bh);
1719
1720 if (gb)
1721 fini_bh(&gb);
1722
1723
1724 return Status;
1725 }
1726
1727 NTSTATUS
Ext2UpdateGroupDirStat(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG group)1728 Ext2UpdateGroupDirStat(
1729 IN PEXT2_IRP_CONTEXT IrpContext,
1730 IN PEXT2_VCB Vcb,
1731 IN ULONG group
1732 )
1733 {
1734 struct super_block *sb = &Vcb->sb;
1735 PEXT2_GROUP_DESC gd;
1736 struct buffer_head *gb = NULL;
1737 NTSTATUS status;
1738
1739 ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
1740
1741 /* get group desc */
1742 gd = ext4_get_group_desc(sb, group, &gb);
1743 if (!gd) {
1744 status = STATUS_INSUFFICIENT_RESOURCES;
1745 goto errorout;
1746 }
1747
1748 /* update group_desc and super_block */
1749 ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1);
1750 Ext2SaveGroup(IrpContext, Vcb, group);
1751 Ext2UpdateVcbStat(IrpContext, Vcb);
1752 status = STATUS_SUCCESS;
1753
1754 errorout:
1755
1756 ExReleaseResourceLite(&Vcb->MetaInode);
1757
1758 if (gb)
1759 fini_bh(&gb);
1760
1761 return status;
1762 }
1763
1764
1765 NTSTATUS
Ext2FreeInode(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN ULONG Inode,IN ULONG Type)1766 Ext2FreeInode(
1767 IN PEXT2_IRP_CONTEXT IrpContext,
1768 IN PEXT2_VCB Vcb,
1769 IN ULONG Inode,
1770 IN ULONG Type
1771 )
1772 {
1773 struct super_block *sb = &Vcb->sb;
1774 PEXT2_GROUP_DESC gd;
1775 struct buffer_head *gb = NULL;
1776 struct buffer_head *bh = NULL;
1777 ext4_fsblk_t bitmap_blk;
1778
1779 RTL_BITMAP InodeBitmap;
1780 ULONG Group;
1781 ULONG Length;
1782 LARGE_INTEGER Offset;
1783
1784 ULONG dwIno;
1785 BOOLEAN bModified = FALSE;
1786
1787 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1788
1789 ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
1790
1791 Group = (Inode - 1) / INODES_PER_GROUP;
1792 dwIno = (Inode - 1) % INODES_PER_GROUP;
1793
1794 DEBUG(DL_INF, ( "Ext2FreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
1795 Inode, Group, dwIno));
1796
1797 if (Group >= Vcb->sbi.s_groups_count) {
1798 DbgBreak();
1799 goto errorout;
1800 }
1801
1802 gd = ext4_get_group_desc(sb, Group, &gb);
1803 if (!gd) {
1804 DbgBreak();
1805 Status = STATUS_INSUFFICIENT_RESOURCES;
1806 goto errorout;
1807 }
1808
1809 bitmap_blk = ext4_inode_bitmap(sb, gd);
1810 bh = sb_getblk(sb, bitmap_blk);
1811 if (!bh) {
1812 DbgBreak();
1813 Status = STATUS_INSUFFICIENT_RESOURCES;
1814 goto errorout;
1815 }
1816 if (!buffer_uptodate(bh)) {
1817 int err = bh_submit_read(bh);
1818 if (err < 0) {
1819 DbgPrint("bh_submit_read error! err: %d\n", err);
1820 Status = Ext2WinntError(err);
1821 goto errorout;
1822 }
1823 }
1824
1825 if (Group == Vcb->sbi.s_groups_count - 1) {
1826
1827 Length = INODES_COUNT % INODES_PER_GROUP;
1828 if (!Length) {
1829 /* s_inodes_count is integer multiple of s_inodes_per_group */
1830 Length = INODES_PER_GROUP;
1831 }
1832 } else {
1833 Length = INODES_PER_GROUP;
1834 }
1835
1836 RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
1837
1838 if (RtlCheckBit(&InodeBitmap, dwIno) == 0) {
1839 DbgBreak();
1840 Status = STATUS_SUCCESS;
1841 } else {
1842 RtlClearBits(&InodeBitmap, dwIno, 1);
1843 bModified = TRUE;
1844 }
1845
1846 if (bModified) {
1847 /* update group free inodes */
1848 ext4_free_inodes_set(sb, gd,
1849 RtlNumberOfClearBits(&InodeBitmap));
1850
1851 /* set inode block dirty and add to vcb dirty range */
1852 mark_buffer_dirty(bh);
1853
1854 /* update group_desc and super_block */
1855 if (Type == EXT2_FT_DIR) {
1856 ext4_used_dirs_set(sb, gd,
1857 ext4_used_dirs_count(sb, gd) - 1);
1858 }
1859 Ext2SaveGroup(IrpContext, Vcb, Group);
1860 Ext2UpdateVcbStat(IrpContext, Vcb);
1861 Status = STATUS_SUCCESS;
1862 }
1863
1864 errorout:
1865
1866 ExReleaseResourceLite(&Vcb->MetaInode);
1867
1868 if (bh)
1869 fini_bh(&bh);
1870
1871 if (gb)
1872 fini_bh(&gb);
1873
1874 return Status;
1875 }
1876
1877
1878 NTSTATUS
Ext2AddEntry(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_FCB Dcb,IN struct inode * Inode,IN PUNICODE_STRING FileName,struct dentry ** Dentry)1879 Ext2AddEntry (
1880 IN PEXT2_IRP_CONTEXT IrpContext,
1881 IN PEXT2_VCB Vcb,
1882 IN PEXT2_FCB Dcb,
1883 IN struct inode *Inode,
1884 IN PUNICODE_STRING FileName,
1885 struct dentry **Dentry
1886 )
1887 {
1888 struct dentry *de = NULL;
1889
1890 NTSTATUS status = STATUS_UNSUCCESSFUL;
1891 OEM_STRING oem;
1892 int rc;
1893
1894 BOOLEAN MainResourceAcquired = FALSE;
1895
1896 if (!IsDirectory(Dcb)) {
1897 DbgBreak();
1898 return STATUS_NOT_A_DIRECTORY;
1899 }
1900
1901 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1902 MainResourceAcquired = TRUE;
1903
1904 _SEH2_TRY {
1905
1906 Ext2ReferXcb(&Dcb->ReferenceCount);
1907 de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName);
1908 if (!de) {
1909 status = STATUS_INSUFFICIENT_RESOURCES;
1910 _SEH2_LEAVE;
1911 }
1912 de->d_inode = Inode;
1913
1914 rc = ext3_add_entry(IrpContext, de, Inode);
1915 status = Ext2WinntError(rc);
1916 if (NT_SUCCESS(status)) {
1917
1918 /* increase dir inode's nlink for .. */
1919 if (S_ISDIR(Inode->i_mode)) {
1920 ext3_inc_count(Dcb->Inode);
1921 ext3_mark_inode_dirty(IrpContext, Dcb->Inode);
1922 }
1923
1924 /* increase inode nlink reference */
1925 ext3_inc_count(Inode);
1926 ext3_mark_inode_dirty(IrpContext, Inode);
1927
1928 if (Dentry) {
1929 *Dentry = de;
1930 de = NULL;
1931 }
1932 }
1933
1934 } _SEH2_FINALLY {
1935
1936 Ext2DerefXcb(&Dcb->ReferenceCount);
1937
1938 if (MainResourceAcquired) {
1939 ExReleaseResourceLite(&Dcb->MainResource);
1940 }
1941
1942 if (de)
1943 Ext2FreeEntry(de);
1944 } _SEH2_END;
1945
1946 return status;
1947 }
1948
1949
1950 NTSTATUS
Ext2SetFileType(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_FCB Dcb,IN PEXT2_MCB Mcb,IN umode_t mode)1951 Ext2SetFileType (
1952 IN PEXT2_IRP_CONTEXT IrpContext,
1953 IN PEXT2_VCB Vcb,
1954 IN PEXT2_FCB Dcb,
1955 IN PEXT2_MCB Mcb,
1956 IN umode_t mode
1957 )
1958 {
1959 struct inode *dir = Dcb->Inode;
1960 struct buffer_head *bh = NULL;
1961 struct ext3_dir_entry_2 *de;
1962 struct inode *inode;
1963 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1964 BOOLEAN MainResourceAcquired = FALSE;
1965
1966 if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
1967 return STATUS_SUCCESS;
1968 }
1969
1970 if (!IsDirectory(Dcb)) {
1971 return STATUS_NOT_A_DIRECTORY;
1972 }
1973
1974 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1975 MainResourceAcquired = TRUE;
1976
1977 _SEH2_TRY {
1978
1979 Ext2ReferXcb(&Dcb->ReferenceCount);
1980
1981 bh = ext3_find_entry(IrpContext, Mcb->de, &de);
1982 if (!bh)
1983 _SEH2_LEAVE;
1984
1985 inode = &Mcb->Inode;
1986 if (le32_to_cpu(de->inode) != inode->i_ino)
1987 _SEH2_LEAVE;
1988
1989 ext3_set_de_type(inode->i_sb, de, mode);
1990 mark_buffer_dirty(bh);
1991
1992 if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) {
1993 } else if (S_ISDIR(inode->i_mode)) {
1994 ext3_dec_count(dir);
1995 } else if (S_ISDIR(mode)) {
1996 ext3_inc_count(dir);
1997 }
1998 dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
1999 ext3_mark_inode_dirty(IrpContext, dir);
2000
2001 inode->i_mode = mode;
2002 ext3_mark_inode_dirty(IrpContext, inode);
2003
2004 Status = STATUS_SUCCESS;
2005
2006 } _SEH2_FINALLY {
2007
2008 Ext2DerefXcb(&Dcb->ReferenceCount);
2009
2010 if (MainResourceAcquired)
2011 ExReleaseResourceLite(&Dcb->MainResource);
2012
2013 if (bh)
2014 brelse(bh);
2015 } _SEH2_END;
2016
2017 return Status;
2018 }
2019
2020 NTSTATUS
Ext2RemoveEntry(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_FCB Dcb,IN PEXT2_MCB Mcb)2021 Ext2RemoveEntry (
2022 IN PEXT2_IRP_CONTEXT IrpContext,
2023 IN PEXT2_VCB Vcb,
2024 IN PEXT2_FCB Dcb,
2025 IN PEXT2_MCB Mcb
2026 )
2027 {
2028 struct inode *dir = Dcb->Inode;
2029 struct buffer_head *bh = NULL;
2030 struct ext3_dir_entry_2 *de;
2031 struct inode *inode;
2032 int rc = -ENOENT;
2033 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2034 BOOLEAN MainResourceAcquired = FALSE;
2035
2036 if (!IsDirectory(Dcb)) {
2037 return STATUS_NOT_A_DIRECTORY;
2038 }
2039
2040 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
2041 MainResourceAcquired = TRUE;
2042
2043 _SEH2_TRY {
2044
2045 Ext2ReferXcb(&Dcb->ReferenceCount);
2046
2047 bh = ext3_find_entry(IrpContext, Mcb->de, &de);
2048 if (!bh)
2049 _SEH2_LEAVE;
2050
2051 inode = &Mcb->Inode;
2052 if (le32_to_cpu(de->inode) != inode->i_ino)
2053 _SEH2_LEAVE;
2054
2055 if (!inode->i_nlink) {
2056 ext3_warning (inode->i_sb, "ext3_unlink",
2057 "Deleting nonexistent file (%lu), %d",
2058 inode->i_ino, inode->i_nlink);
2059 inode->i_nlink = 1;
2060 }
2061 rc = ext3_delete_entry(IrpContext, dir, de, bh);
2062 if (rc) {
2063 Status = Ext2WinntError(rc);
2064 _SEH2_LEAVE;
2065 }
2066 /*
2067 if (!inode->i_nlink)
2068 ext3_orphan_add(handle, inode);
2069 */
2070 inode->i_ctime = dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
2071 ext3_dec_count(inode);
2072 ext3_mark_inode_dirty(IrpContext, inode);
2073
2074 /* decrease dir inode's nlink for .. */
2075 if (S_ISDIR(inode->i_mode)) {
2076 ext3_update_dx_flag(dir);
2077 ext3_dec_count(dir);
2078 ext3_mark_inode_dirty(IrpContext, dir);
2079 }
2080
2081 Status = STATUS_SUCCESS;
2082
2083 } _SEH2_FINALLY {
2084
2085 Ext2DerefXcb(&Dcb->ReferenceCount);
2086
2087 if (MainResourceAcquired)
2088 ExReleaseResourceLite(&Dcb->MainResource);
2089
2090 if (bh)
2091 brelse(bh);
2092 } _SEH2_END;
2093
2094 return Status;
2095 }
2096
2097 NTSTATUS
Ext2SetParentEntry(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_FCB Dcb,IN ULONG OldParent,IN ULONG NewParent)2098 Ext2SetParentEntry (
2099 IN PEXT2_IRP_CONTEXT IrpContext,
2100 IN PEXT2_VCB Vcb,
2101 IN PEXT2_FCB Dcb,
2102 IN ULONG OldParent,
2103 IN ULONG NewParent )
2104 {
2105 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2106
2107 PEXT2_DIR_ENTRY2 pSelf = NULL;
2108 PEXT2_DIR_ENTRY2 pParent = NULL;
2109
2110 ULONG dwBytes = 0;
2111
2112 BOOLEAN MainResourceAcquired = FALSE;
2113
2114 ULONG Offset = 0;
2115
2116 if (!IsDirectory(Dcb)) {
2117 return STATUS_NOT_A_DIRECTORY;
2118 }
2119
2120 if (OldParent == NewParent) {
2121 return STATUS_SUCCESS;
2122 }
2123
2124 MainResourceAcquired =
2125 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
2126
2127 _SEH2_TRY {
2128
2129 Ext2ReferXcb(&Dcb->ReferenceCount);
2130
2131 pSelf = (PEXT2_DIR_ENTRY2)
2132 Ext2AllocatePool(
2133 PagedPool,
2134 EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
2135 EXT2_DENTRY_MAGIC
2136 );
2137 if (!pSelf) {
2138 DEBUG(DL_ERR, ( "Ex2SetParentEntry: failed to allocate pSelf.\n"));
2139 Status = STATUS_INSUFFICIENT_RESOURCES;
2140 _SEH2_LEAVE;
2141 }
2142
2143 dwBytes = 0;
2144
2145 //
2146 // Reading the DCB contents
2147 //
2148
2149 Status = Ext2ReadInode(
2150 IrpContext,
2151 Vcb,
2152 Dcb->Mcb,
2153 (ULONGLONG)Offset,
2154 (PVOID)pSelf,
2155 EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
2156 FALSE,
2157 &dwBytes );
2158
2159 if (!NT_SUCCESS(Status)) {
2160 DEBUG(DL_ERR, ( "Ext2SetParentEntry: failed to read directory.\n"));
2161 _SEH2_LEAVE;
2162 }
2163
2164 ASSERT(dwBytes == EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2));
2165
2166 pParent = (PEXT2_DIR_ENTRY2)((PUCHAR)pSelf + pSelf->rec_len);
2167
2168 if (pSelf->name_len == 1 && pSelf->name[0] == '.' &&
2169 pParent->name_len == 2 && pParent->name[0] == '.' &&
2170 pParent->name[1] == '.') {
2171
2172 if (pParent->inode != OldParent) {
2173 DbgBreak();
2174 }
2175 pParent->inode = NewParent;
2176
2177 Status = Ext2WriteInode(
2178 IrpContext,
2179 Vcb,
2180 Dcb->Mcb,
2181 (ULONGLONG)Offset,
2182 pSelf,
2183 dwBytes,
2184 FALSE,
2185 &dwBytes );
2186 } else {
2187 DbgBreak();
2188 }
2189
2190 } _SEH2_FINALLY {
2191
2192
2193 if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) {
2194 DEBUG(DL_ERR, ( "Ext2SetParentEntry: Dcb reference goes to ZERO.\n"));
2195 }
2196
2197 if (MainResourceAcquired) {
2198 ExReleaseResourceLite(&Dcb->MainResource);
2199 }
2200
2201 if (pSelf) {
2202 Ext2FreePool(pSelf, EXT2_DENTRY_MAGIC);
2203 }
2204 } _SEH2_END;
2205
2206 return Status;
2207 }
2208
ext3_check_dir_entry(const char * function,struct inode * dir,struct ext3_dir_entry_2 * de,struct buffer_head * bh,unsigned long offset)2209 int ext3_check_dir_entry (const char * function, struct inode * dir,
2210 struct ext3_dir_entry_2 * de,
2211 struct buffer_head * bh,
2212 unsigned long offset)
2213 {
2214 const char * error_msg = NULL;
2215 const int rlen = ext3_rec_len_from_disk(de->rec_len);
2216
2217 if (rlen < EXT3_DIR_REC_LEN(1))
2218 error_msg = "rec_len is smaller than minimal";
2219 else if (rlen % 4 != 0)
2220 error_msg = "rec_len % 4 != 0";
2221 else if (rlen < EXT3_DIR_REC_LEN(de->name_len))
2222 error_msg = "rec_len is too small for name_len";
2223 else if ((char *) de + rlen > bh->b_data + dir->i_sb->s_blocksize)
2224 error_msg = "directory entry across blocks";
2225 else if (le32_to_cpu(de->inode) >
2226 le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
2227 error_msg = "inode out of bounds";
2228
2229 if (error_msg != NULL) {
2230 DEBUG(DL_ERR, ("%s: bad entry in directory %u: %s - "
2231 "offset=%u, inode=%u, rec_len=%d, name_len=%d\n",
2232 function, dir->i_ino, error_msg, offset,
2233 (unsigned long) le32_to_cpu(de->inode),
2234 rlen, de->name_len));
2235 }
2236 return error_msg == NULL ? 1 : 0;
2237 }
2238
2239
2240 /*
2241 * p is at least 6 bytes before the end of page
2242 */
2243 struct ext3_dir_entry_2 *
ext3_next_entry(struct ext3_dir_entry_2 * p)2244 ext3_next_entry(struct ext3_dir_entry_2 *p)
2245 {
2246 return (struct ext3_dir_entry_2 *)((char *)p +
2247 ext3_rec_len_from_disk(p->rec_len));
2248 }
2249
2250 #define MAX_LFS_FILESIZE 0x7fffffffffffffff
2251
2252 /*
2253 * Maximal extent format file size.
2254 * Resulting logical blkno at s_maxbytes must fit in our on-disk
2255 * extent format containers, within a sector_t, and within i_blocks
2256 * in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
2257 * so that won't be a limiting factor.
2258 *
2259 * Note, this does *not* consider any metadata overhead for vfs i_blocks.
2260 */
ext4_max_size(int blkbits,int has_huge_files)2261 static loff_t ext4_max_size(int blkbits, int has_huge_files)
2262 {
2263 loff_t res;
2264 loff_t upper_limit = MAX_LFS_FILESIZE;
2265
2266 /* small i_blocks in vfs inode? */
2267 if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
2268 /*
2269 * CONFIG_LBD is not enabled implies the inode
2270 * i_block represent total blocks in 512 bytes
2271 * 32 == size of vfs inode i_blocks * 8
2272 */
2273 upper_limit = (1LL << 32) - 1;
2274
2275 /* total blocks in file system block size */
2276 upper_limit >>= (blkbits - 9);
2277 upper_limit <<= blkbits;
2278 }
2279
2280 /* 32-bit extent-start container, ee_block */
2281 res = 1LL << 32;
2282 res <<= blkbits;
2283 res -= 1;
2284
2285 /* Sanity check against vm- & vfs- imposed limits */
2286 if (res > upper_limit)
2287 res = upper_limit;
2288
2289 return res;
2290 }
2291
2292 /*
2293 * Maximal extent format file size.
2294 * Resulting logical blkno at s_maxbytes must fit in our on-disk
2295 * extent format containers, within a sector_t, and within i_blocks
2296 * in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
2297 * so that won't be a limiting factor.
2298 *
2299 * Note, this does *not* consider any metadata overhead for vfs i_blocks.
2300 */
ext3_max_size(int blkbits,int has_huge_files)2301 loff_t ext3_max_size(int blkbits, int has_huge_files)
2302 {
2303 loff_t res;
2304 loff_t upper_limit = MAX_LFS_FILESIZE;
2305
2306 /* small i_blocks in vfs inode? */
2307 if (!has_huge_files) {
2308 /*
2309 * CONFIG_LBD is not enabled implies the inode
2310 * i_block represent total blocks in 512 bytes
2311 * 32 == size of vfs inode i_blocks * 8
2312 */
2313 upper_limit = ((loff_t)1 << 32) - 1;
2314
2315 /* total blocks in file system block size */
2316 upper_limit >>= (blkbits - 9);
2317 upper_limit <<= blkbits;
2318 }
2319
2320 /* 32-bit extent-start container, ee_block */
2321 res = (loff_t)1 << 32;
2322 res <<= blkbits;
2323 res -= 1;
2324
2325 /* Sanity check against vm- & vfs- imposed limits */
2326 if (res > upper_limit)
2327 res = upper_limit;
2328
2329 return res;
2330 }
2331
2332 /*
2333 * Maximal bitmap file size. There is a direct, and {,double-,triple-}indirect
2334 * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
2335 * We need to be 1 filesystem block less than the 2^48 sector limit.
2336 */
ext3_max_bitmap_size(int bits,int has_huge_files)2337 loff_t ext3_max_bitmap_size(int bits, int has_huge_files)
2338 {
2339 loff_t res = EXT3_NDIR_BLOCKS;
2340 int meta_blocks;
2341 loff_t upper_limit;
2342 /* This is calculated to be the largest file size for a
2343 * dense, bitmapped file such that the total number of
2344 * sectors in the file, including data and all indirect blocks,
2345 * does not exceed 2^48 -1
2346 * __u32 i_blocks_lo and _u16 i_blocks_high representing the
2347 * total number of 512 bytes blocks of the file
2348 */
2349
2350 if (!has_huge_files) {
2351 /*
2352 * !has_huge_files or CONFIG_LBD is not enabled
2353 * implies the inode i_block represent total blocks in
2354 * 512 bytes 32 == size of vfs inode i_blocks * 8
2355 */
2356 upper_limit = ((loff_t)1 << 32) - 1;
2357
2358 /* total blocks in file system block size */
2359 upper_limit >>= (bits - 9);
2360
2361 } else {
2362 /*
2363 * We use 48 bit ext4_inode i_blocks
2364 * With EXT4_HUGE_FILE_FL set the i_blocks
2365 * represent total number of blocks in
2366 * file system block size
2367 */
2368 upper_limit = ((loff_t)1 << 48) - 1;
2369
2370 }
2371
2372 /* indirect blocks */
2373 meta_blocks = 1;
2374 /* double indirect blocks */
2375 meta_blocks += 1 + ((loff_t)1 << (bits-2));
2376 /* tripple indirect blocks */
2377 meta_blocks += 1 + ((loff_t)1 << (bits-2)) + ((loff_t)1 << (2*(bits-2)));
2378
2379 upper_limit -= meta_blocks;
2380 upper_limit <<= bits;
2381
2382 res += (loff_t)1 << (bits-2);
2383 res += (loff_t)1 << (2*(bits-2));
2384 res += (loff_t)1 << (3*(bits-2));
2385 res <<= bits;
2386 if (res > upper_limit)
2387 res = upper_limit;
2388
2389 if (res > MAX_LFS_FILESIZE)
2390 res = MAX_LFS_FILESIZE;
2391
2392 return res;
2393 }
2394
ext3_inode_blocks(struct ext3_inode * raw_inode,struct inode * inode)2395 blkcnt_t ext3_inode_blocks(struct ext3_inode *raw_inode,
2396 struct inode *inode)
2397 {
2398 blkcnt_t i_blocks ;
2399 struct super_block *sb = inode->i_sb;
2400 PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
2401
2402 if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
2403 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
2404 /* we are using combined 48 bit field */
2405 i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
2406 le32_to_cpu(raw_inode->i_blocks);
2407 if (inode->i_flags & EXT4_HUGE_FILE_FL) {
2408 /* i_blocks represent file system block size */
2409 return i_blocks << (BLOCK_BITS - 9);
2410 } else {
2411 return i_blocks;
2412 }
2413 } else {
2414 return le32_to_cpu(raw_inode->i_blocks);
2415 }
2416 }
2417
ext3_inode_blocks_set(struct ext3_inode * raw_inode,struct inode * inode)2418 int ext3_inode_blocks_set(struct ext3_inode *raw_inode,
2419 struct inode * inode)
2420 {
2421 u64 i_blocks = inode->i_blocks;
2422 struct super_block *sb = inode->i_sb;
2423 PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
2424
2425 if (i_blocks < 0x100000000) {
2426 /*
2427 * i_blocks can be represnted in a 32 bit variable
2428 * as multiple of 512 bytes
2429 */
2430 raw_inode->i_blocks = cpu_to_le32(i_blocks);
2431 raw_inode->i_blocks_high = 0;
2432 inode->i_flags &= ~EXT4_HUGE_FILE_FL;
2433 return 0;
2434 }
2435
2436 if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
2437 EXT3_SET_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2438 Ext2SaveSuper(NULL, Vcb);
2439 }
2440
2441 if (i_blocks <= 0xffffffffffff) {
2442 /*
2443 * i_blocks can be represented in a 48 bit variable
2444 * as multiple of 512 bytes
2445 */
2446 raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks);
2447 raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
2448 inode->i_flags &= ~EXT4_HUGE_FILE_FL;
2449 } else {
2450 inode->i_flags |= EXT4_HUGE_FILE_FL;
2451 /* i_block is stored in file system block size */
2452 i_blocks = i_blocks >> (BLOCK_BITS - 9);
2453 raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks);
2454 raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
2455 }
2456 return 0;
2457 }
2458
ext4_block_bitmap(struct super_block * sb,struct ext4_group_desc * bg)2459 ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
2460 struct ext4_group_desc *bg)
2461 {
2462 return le32_to_cpu(bg->bg_block_bitmap) |
2463 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2464 (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
2465 }
2466
ext4_inode_bitmap(struct super_block * sb,struct ext4_group_desc * bg)2467 ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
2468 struct ext4_group_desc *bg)
2469 {
2470 return le32_to_cpu(bg->bg_inode_bitmap) |
2471 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2472 (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
2473 }
2474
ext4_inode_table(struct super_block * sb,struct ext4_group_desc * bg)2475 ext4_fsblk_t ext4_inode_table(struct super_block *sb,
2476 struct ext4_group_desc *bg)
2477 {
2478 return le32_to_cpu(bg->bg_inode_table) |
2479 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2480 (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
2481 }
2482
ext4_free_blks_count(struct super_block * sb,struct ext4_group_desc * bg)2483 __u32 ext4_free_blks_count(struct super_block *sb,
2484 struct ext4_group_desc *bg)
2485 {
2486 return le16_to_cpu(bg->bg_free_blocks_count) |
2487 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2488 (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
2489 }
2490
ext4_free_inodes_count(struct super_block * sb,struct ext4_group_desc * bg)2491 __u32 ext4_free_inodes_count(struct super_block *sb,
2492 struct ext4_group_desc *bg)
2493 {
2494 return le16_to_cpu(bg->bg_free_inodes_count) |
2495 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2496 (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
2497 }
2498
ext4_used_dirs_count(struct super_block * sb,struct ext4_group_desc * bg)2499 __u32 ext4_used_dirs_count(struct super_block *sb,
2500 struct ext4_group_desc *bg)
2501 {
2502 return le16_to_cpu(bg->bg_used_dirs_count) |
2503 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2504 (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
2505 }
2506
ext4_itable_unused_count(struct super_block * sb,struct ext4_group_desc * bg)2507 __u32 ext4_itable_unused_count(struct super_block *sb,
2508 struct ext4_group_desc *bg)
2509 {
2510 return le16_to_cpu(bg->bg_itable_unused) |
2511 (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2512 (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
2513 }
2514
ext4_block_bitmap_set(struct super_block * sb,struct ext4_group_desc * bg,ext4_fsblk_t blk)2515 void ext4_block_bitmap_set(struct super_block *sb,
2516 struct ext4_group_desc *bg, ext4_fsblk_t blk)
2517 {
2518 bg->bg_block_bitmap = cpu_to_le32((u32)blk);
2519 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2520 bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
2521 }
2522
ext4_inode_bitmap_set(struct super_block * sb,struct ext4_group_desc * bg,ext4_fsblk_t blk)2523 void ext4_inode_bitmap_set(struct super_block *sb,
2524 struct ext4_group_desc *bg, ext4_fsblk_t blk)
2525 {
2526 bg->bg_inode_bitmap = cpu_to_le32((u32)blk);
2527 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2528 bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
2529 }
2530
ext4_inode_table_set(struct super_block * sb,struct ext4_group_desc * bg,ext4_fsblk_t blk)2531 void ext4_inode_table_set(struct super_block *sb,
2532 struct ext4_group_desc *bg, ext4_fsblk_t blk)
2533 {
2534 bg->bg_inode_table = cpu_to_le32((u32)blk);
2535 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2536 bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
2537 }
2538
ext4_free_blks_set(struct super_block * sb,struct ext4_group_desc * bg,__u32 count)2539 void ext4_free_blks_set(struct super_block *sb,
2540 struct ext4_group_desc *bg, __u32 count)
2541 {
2542 bg->bg_free_blocks_count = cpu_to_le16((__u16)count);
2543 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2544 bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);
2545 }
2546
ext4_free_inodes_set(struct super_block * sb,struct ext4_group_desc * bg,__u32 count)2547 void ext4_free_inodes_set(struct super_block *sb,
2548 struct ext4_group_desc *bg, __u32 count)
2549 {
2550 bg->bg_free_inodes_count = cpu_to_le16((__u16)count);
2551 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2552 bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16);
2553 }
2554
ext4_used_dirs_set(struct super_block * sb,struct ext4_group_desc * bg,__u32 count)2555 void ext4_used_dirs_set(struct super_block *sb,
2556 struct ext4_group_desc *bg, __u32 count)
2557 {
2558 bg->bg_used_dirs_count = cpu_to_le16((__u16)count);
2559 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2560 bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);
2561 }
2562
ext4_itable_unused_set(struct super_block * sb,struct ext4_group_desc * bg,__u32 count)2563 void ext4_itable_unused_set(struct super_block *sb,
2564 struct ext4_group_desc *bg, __u32 count)
2565 {
2566 bg->bg_itable_unused = cpu_to_le16((__u16)count);
2567 if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2568 bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
2569 }
2570
2571 /** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
2572 __u16 const crc16_table[256] = {
2573 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
2574 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
2575 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
2576 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
2577 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
2578 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
2579 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
2580 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
2581 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
2582 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
2583 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
2584 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
2585 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
2586 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
2587 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
2588 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
2589 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
2590 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
2591 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
2592 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
2593 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
2594 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
2595 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
2596 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
2597 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
2598 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
2599 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
2600 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
2601 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
2602 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
2603 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
2604 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
2605 };
2606
crc16_byte(__u16 crc,const __u8 data)2607 static inline __u16 crc16_byte(__u16 crc, const __u8 data)
2608 {
2609 return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
2610 }
2611
crc16(__u16 crc,__u8 const * buffer,size_t len)2612 __u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
2613 {
2614 while (len--)
2615 crc = crc16_byte(crc, *buffer++);
2616 return crc;
2617 }
2618
ext4_group_desc_csum(struct ext3_sb_info * sbi,__u32 block_group,struct ext4_group_desc * gdp)2619 __le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
2620 struct ext4_group_desc *gdp)
2621 {
2622 int offset;
2623 __u16 crc = 0;
2624 __le32 le_group = cpu_to_le32(block_group);
2625
2626 /* old crc16 code */
2627 if (!(sbi->s_es->s_feature_ro_compat &
2628 cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
2629 return 0;
2630
2631 offset = offsetof(struct ext4_group_desc, bg_checksum);
2632
2633 crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
2634 crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
2635 crc = crc16(crc, (__u8 *)gdp, offset);
2636 offset += sizeof(gdp->bg_checksum); /* skip checksum */
2637 /* for checksum of struct ext4_group_desc do the rest...*/
2638 if ((sbi->s_es->s_feature_incompat &
2639 cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
2640 offset < le16_to_cpu(sbi->s_es->s_desc_size))
2641 crc = crc16(crc, (__u8 *)gdp + offset,
2642 le16_to_cpu(sbi->s_es->s_desc_size) -
2643 offset);
2644
2645 return cpu_to_le16(crc);
2646 }
2647
ext4_group_desc_csum_verify(struct ext3_sb_info * sbi,__u32 block_group,struct ext4_group_desc * gdp)2648 int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
2649 struct ext4_group_desc *gdp)
2650 {
2651 if ((sbi->s_es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
2652 (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
2653 return 0;
2654
2655 return 1;
2656 }
2657
2658
test_root(ext3_group_t a,ext3_group_t b)2659 static inline int test_root(ext3_group_t a, ext3_group_t b)
2660 {
2661 ext3_group_t num = b;
2662
2663 while (a > num)
2664 num *= b;
2665 return num == a;
2666 }
2667
ext3_group_sparse(ext3_group_t group)2668 static int ext3_group_sparse(ext3_group_t group)
2669 {
2670 if (group <= 1)
2671 return 1;
2672 if (!(group & 1))
2673 return 0;
2674 return (test_root(group, 7) || test_root(group, 5) ||
2675 test_root(group, 3));
2676 }
2677
2678 /**
2679 * ext4_bg_has_super - number of blocks used by the superblock in group
2680 * @sb: superblock for filesystem
2681 * @group: group number to check
2682 *
2683 * Return the number of blocks used by the superblock (primary or backup)
2684 * in this group. Currently this will be only 0 or 1.
2685 */
ext3_bg_has_super(struct super_block * sb,ext3_group_t group)2686 int ext3_bg_has_super(struct super_block *sb, ext3_group_t group)
2687 {
2688 if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
2689 EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
2690 !ext3_group_sparse(group))
2691 return 0;
2692 return 1;
2693 }
2694
ext4_bg_num_gdb_meta(struct super_block * sb,ext4_group_t group)2695 static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,
2696 ext4_group_t group)
2697 {
2698 unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
2699 ext4_group_t first = metagroup * EXT4_DESC_PER_BLOCK(sb);
2700 ext4_group_t last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
2701
2702 if (group == first || group == first + 1 || group == last)
2703 return 1;
2704 return 0;
2705 }
2706
ext4_bg_num_gdb_nometa(struct super_block * sb,ext4_group_t group)2707 static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
2708 ext4_group_t group)
2709 {
2710 return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;
2711 }
2712
2713 /**
2714 * ext4_bg_num_gdb - number of blocks used by the group table in group
2715 * @sb: superblock for filesystem
2716 * @group: group number to check
2717 *
2718 * Return the number of blocks used by the group descriptor table
2719 * (primary or backup) in this group. In the future there may be a
2720 * different number of descriptor blocks in each group.
2721 */
ext4_bg_num_gdb(struct super_block * sb,ext4_group_t group)2722 unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
2723 {
2724 unsigned long first_meta_bg =
2725 le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg);
2726 unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
2727
2728 if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
2729 metagroup < first_meta_bg)
2730 return ext4_bg_num_gdb_nometa(sb, group);
2731
2732 return ext4_bg_num_gdb_meta(sb,group);
2733
2734 }
2735
descriptor_loc(struct super_block * sb,ext3_fsblk_t logical_sb_block,unsigned int nr)2736 ext3_fsblk_t descriptor_loc(struct super_block *sb,
2737 ext3_fsblk_t logical_sb_block, unsigned int nr)
2738 {
2739 struct ext3_sb_info *sbi = EXT3_SB(sb);
2740 ext3_group_t bg, first_meta_bg;
2741 int has_super = 0;
2742
2743 first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
2744
2745 if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
2746 nr < first_meta_bg)
2747 return logical_sb_block + nr + 1;
2748 bg = sbi->s_desc_per_block * nr;
2749 if (ext3_bg_has_super(sb, bg))
2750 has_super = 1;
2751 return (has_super + ext3_group_first_block_no(sb, bg));
2752 }
2753
2754 #define ext4_set_bit(n, p) set_bit((int)(n), (unsigned long *)(p))
2755
2756 /*
2757 * The free inodes are managed by bitmaps. A file system contains several
2758 * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
2759 * block for inodes, N blocks for the inode table and data blocks.
2760 *
2761 * The file system contains group descriptors which are located after the
2762 * super block. Each descriptor contains the number of the bitmap block and
2763 * the free blocks count in the block.
2764 */
2765
2766 /*
2767 * To avoid calling the atomic setbit hundreds or thousands of times, we only
2768 * need to use it within a single byte (to ensure we get endianness right).
2769 * We can use memset for the rest of the bitmap as there are no other users.
2770 */
mark_bitmap_end(int start_bit,int end_bit,char * bitmap)2771 void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
2772 {
2773 int i;
2774
2775 if (start_bit >= end_bit)
2776 return;
2777
2778 DEBUG(DL_INF, ("mark end bits +%d through +%d used\n", start_bit, end_bit));
2779 for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
2780 ext4_set_bit(i, bitmap);
2781 if (i < end_bit)
2782 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
2783 }
2784
2785 /* Initializes an uninitialized inode bitmap */
ext4_init_inode_bitmap(struct super_block * sb,struct buffer_head * bh,ext4_group_t block_group,struct ext4_group_desc * gdp)2786 unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
2787 ext4_group_t block_group,
2788 struct ext4_group_desc *gdp)
2789 {
2790 struct ext3_sb_info *sbi = EXT3_SB(sb);
2791
2792 mark_buffer_dirty(bh);
2793
2794 /* If checksum is bad mark all blocks and inodes use to prevent
2795 * allocation, essentially implementing a per-group read-only flag. */
2796 if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
2797 ext4_error(sb, __FUNCTION__, "Checksum bad for group %u",
2798 block_group);
2799 ext4_free_blks_set(sb, gdp, 0);
2800 ext4_free_inodes_set(sb, gdp, 0);
2801 ext4_itable_unused_set(sb, gdp, 0);
2802 memset(bh->b_data, 0xff, sb->s_blocksize);
2803 return 0;
2804 }
2805
2806 memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
2807 mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
2808 bh->b_data);
2809 ext4_itable_unused_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
2810
2811 return EXT4_INODES_PER_GROUP(sb);
2812 }
2813
2814 /*
2815 * Calculate the block group number and offset, given a block number
2816 */
ext4_get_group_no_and_offset(struct super_block * sb,ext4_fsblk_t blocknr,ext4_group_t * blockgrpp,ext4_grpblk_t * offsetp)2817 void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
2818 ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp)
2819 {
2820 struct ext3_super_block *es = EXT3_SB(sb)->s_es;
2821 ext4_grpblk_t offset;
2822
2823 blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
2824 offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
2825 if (offsetp)
2826 *offsetp = offset;
2827 if (blockgrpp)
2828 *blockgrpp = (ext4_grpblk_t)blocknr;
2829
2830 }
2831
ext4_block_in_group(struct super_block * sb,ext4_fsblk_t block,ext4_group_t block_group)2832 static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
2833 ext4_group_t block_group)
2834 {
2835 ext4_group_t actual_group;
2836 ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
2837 if (actual_group == block_group)
2838 return 1;
2839 return 0;
2840 }
2841
ext4_group_used_meta_blocks(struct super_block * sb,ext4_group_t block_group)2842 static int ext4_group_used_meta_blocks(struct super_block *sb,
2843 ext4_group_t block_group)
2844 {
2845 ext4_fsblk_t tmp;
2846 struct ext3_sb_info *sbi = EXT3_SB(sb);
2847 /* block bitmap, inode bitmap, and inode table blocks */
2848 int used_blocks = sbi->s_itb_per_group + 2;
2849
2850 if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
2851 struct ext4_group_desc *gdp;
2852 struct buffer_head *bh = NULL;
2853
2854 gdp = ext4_get_group_desc(sb, block_group, &bh);
2855 if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
2856 block_group))
2857 used_blocks--;
2858
2859 if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp),
2860 block_group))
2861 used_blocks--;
2862
2863 tmp = ext4_inode_table(sb, gdp);
2864 for (; tmp < ext4_inode_table(sb, gdp) +
2865 sbi->s_itb_per_group; tmp++) {
2866 if (!ext4_block_in_group(sb, tmp, block_group))
2867 used_blocks -= 1;
2868 }
2869 if (bh)
2870 fini_bh(&bh);
2871 }
2872 return used_blocks;
2873 }
2874
2875 /* Initializes an uninitialized block bitmap if given, and returns the
2876 * number of blocks free in the group. */
ext4_init_block_bitmap(struct super_block * sb,struct buffer_head * bh,ext4_group_t block_group,struct ext4_group_desc * gdp)2877 unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
2878 ext4_group_t block_group, struct ext4_group_desc *gdp)
2879 {
2880 int bit, bit_max;
2881 unsigned free_blocks, group_blocks;
2882 struct ext3_sb_info *sbi = EXT3_SB(sb);
2883
2884 if (bh) {
2885 mark_buffer_dirty(bh);
2886 /* If checksum is bad mark all blocks used to prevent allocation
2887 * essentially implementing a per-group read-only flag. */
2888 if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
2889 ext4_error(sb, __FUNCTION__,
2890 "Checksum bad for group %u", block_group);
2891 ext4_free_blks_set(sb, gdp, 0);
2892 ext4_free_inodes_set(sb, gdp, 0);
2893 ext4_itable_unused_set(sb, gdp, 0);
2894 memset(bh->b_data, 0xff, sb->s_blocksize);
2895 return 0;
2896 }
2897 memset(bh->b_data, 0, sb->s_blocksize);
2898 }
2899
2900 /* Check for superblock and gdt backups in this group */
2901 bit_max = ext3_bg_has_super(sb, block_group);
2902
2903 if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
2904 block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
2905 sbi->s_desc_per_block) {
2906 if (bit_max) {
2907 bit_max += ext4_bg_num_gdb(sb, block_group);
2908 bit_max +=
2909 le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
2910 }
2911 } else { /* For META_BG_BLOCK_GROUPS */
2912 bit_max += ext4_bg_num_gdb(sb, block_group);
2913 }
2914
2915 if (block_group == sbi->s_groups_count - 1) {
2916 /*
2917 * Even though mke2fs always initialize first and last group
2918 * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
2919 * to make sure we calculate the right free blocks
2920 */
2921 group_blocks = (unsigned int)(ext3_blocks_count(sbi->s_es) -
2922 le32_to_cpu(sbi->s_es->s_first_data_block) -
2923 (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1)));
2924 } else {
2925 group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
2926 }
2927
2928 free_blocks = group_blocks - bit_max;
2929
2930 if (bh) {
2931 ext4_fsblk_t start, tmp;
2932 int flex_bg = 0;
2933
2934 for (bit = 0; bit < bit_max; bit++)
2935 ext4_set_bit(bit, bh->b_data);
2936
2937 start = ext3_group_first_block_no(sb, block_group);
2938
2939 if (EXT3_HAS_INCOMPAT_FEATURE(sb,
2940 EXT4_FEATURE_INCOMPAT_FLEX_BG))
2941 flex_bg = 1;
2942
2943 /* Set bits for block and inode bitmaps, and inode table */
2944 tmp = ext4_block_bitmap(sb, gdp);
2945 if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
2946 ext4_set_bit(tmp - start, bh->b_data);
2947
2948 tmp = ext4_inode_bitmap(sb, gdp);
2949 if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
2950 ext4_set_bit(tmp - start, bh->b_data);
2951
2952 tmp = ext4_inode_table(sb, gdp);
2953 for (; tmp < ext4_inode_table(sb, gdp) +
2954 sbi->s_itb_per_group; tmp++) {
2955 if (!flex_bg ||
2956 ext4_block_in_group(sb, tmp, block_group))
2957 ext4_set_bit(tmp - start, bh->b_data);
2958 }
2959 /*
2960 * Also if the number of blocks within the group is
2961 * less than the blocksize * 8 ( which is the size
2962 * of bitmap ), set rest of the block bitmap to 1
2963 */
2964 mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
2965 }
2966 return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
2967 }
2968
2969 /**
2970 * ext4_get_group_desc() -- load group descriptor from disk
2971 * @sb: super block
2972 * @block_group: given block group
2973 * @bh: pointer to the buffer head to store the block
2974 * group descriptor
2975 */
ext4_get_group_desc(struct super_block * sb,ext4_group_t block_group,struct buffer_head ** bh)2976 struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
2977 ext4_group_t block_group, struct buffer_head **bh)
2978 {
2979 struct ext4_group_desc *desc = NULL;
2980 struct ext3_sb_info *sbi = EXT3_SB(sb);
2981 PEXT2_VCB vcb = sb->s_priv;
2982 ext4_group_t group;
2983 ext4_group_t offset;
2984
2985 if (bh)
2986 *bh = NULL;
2987
2988 if (block_group >= sbi->s_groups_count) {
2989 ext4_error(sb, "ext4_get_group_desc",
2990 "block_group >= groups_count - "
2991 "block_group = %u, groups_count = %u",
2992 block_group, sbi->s_groups_count);
2993
2994 return NULL;
2995 }
2996
2997 _SEH2_TRY {
2998
2999 group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
3000 offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
3001
3002 if (!sbi->s_gd) {
3003 if (!Ext2LoadGroup(vcb)) {
3004 _SEH2_LEAVE;
3005 }
3006 } else if ( !sbi->s_gd[group].block ||
3007 !sbi->s_gd[group].bh) {
3008 if (!Ext2LoadGroupBH(vcb)) {
3009 _SEH2_LEAVE;
3010 }
3011 }
3012
3013 desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
3014 offset * EXT4_DESC_SIZE(sb));
3015 if (bh) {
3016 atomic_inc(&sbi->s_gd[group].bh->b_count);
3017 *bh = sbi->s_gd[group].bh;
3018 }
3019 } _SEH2_FINALLY {
3020 /* do cleanup */
3021 } _SEH2_END;
3022
3023 return desc;
3024 }
3025
3026
3027 /**
3028 * ext4_count_free_blocks() -- count filesystem free blocks
3029 * @sb: superblock
3030 *
3031 * Adds up the number of free blocks from each block group.
3032 */
ext4_count_free_blocks(struct super_block * sb)3033 ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
3034 {
3035 ext4_fsblk_t desc_count;
3036 struct ext4_group_desc *gdp;
3037 struct buffer_head *bh = NULL;
3038 ext4_group_t i;
3039 ext4_group_t ngroups = EXT3_SB(sb)->s_groups_count;
3040
3041 desc_count = 0;
3042 smp_rmb();
3043 for (i = 0; i < ngroups; i++) {
3044 gdp = ext4_get_group_desc(sb, i, &bh);
3045 if (!bh)
3046 continue;
3047 desc_count += ext4_free_blks_count(sb, gdp);
3048 fini_bh(&bh);
3049 }
3050
3051 return desc_count;
3052 }
3053
ext4_count_free_inodes(struct super_block * sb)3054 unsigned long ext4_count_free_inodes(struct super_block *sb)
3055 {
3056 unsigned long desc_count;
3057 struct ext4_group_desc *gdp;
3058 struct buffer_head *bh = NULL;
3059 ext4_group_t i;
3060
3061 desc_count = 0;
3062 for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
3063 gdp = ext4_get_group_desc(sb, i, &bh);
3064 if (!bh)
3065 continue;
3066 desc_count += ext4_free_inodes_count(sb, gdp);
3067 fini_bh(&bh);
3068 }
3069 return desc_count;
3070 }
3071
3072 /* Called at mount-time, super-block is locked */
ext4_count_dirs(struct super_block * sb)3073 unsigned long ext4_count_dirs(struct super_block * sb)
3074 {
3075 struct ext4_group_desc *gdp;
3076 struct buffer_head *bh = NULL;
3077 unsigned long count = 0;
3078 ext4_group_t i;
3079
3080 for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
3081 gdp = ext4_get_group_desc(sb, i, &bh);
3082 if (!bh)
3083 continue;
3084 count += ext4_used_dirs_count(sb, gdp);
3085 fini_bh(&bh);
3086 }
3087 return count;
3088 }
3089
3090 /* Called at mount-time, super-block is locked */
ext4_check_descriptors(struct super_block * sb)3091 int ext4_check_descriptors(struct super_block *sb)
3092 {
3093 PEXT2_VCB Vcb = sb->s_priv;
3094 struct ext3_sb_info *sbi = EXT3_SB(sb);
3095 ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
3096 ext4_fsblk_t last_block;
3097 ext4_fsblk_t block_bitmap;
3098 ext4_fsblk_t inode_bitmap;
3099 ext4_fsblk_t inode_table;
3100 int flexbg_flag = 0;
3101 ext4_group_t i;
3102
3103 if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
3104 flexbg_flag = 1;
3105
3106 DEBUG(DL_INF, ("Checking group descriptors"));
3107
3108 for (i = 0; i < sbi->s_groups_count; i++) {
3109
3110 struct buffer_head *bh = NULL;
3111 struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
3112
3113 if (!bh)
3114 continue;
3115
3116 if (i == sbi->s_groups_count - 1 || flexbg_flag)
3117 last_block = ext3_blocks_count(sbi->s_es) - 1;
3118 else
3119 last_block = first_block +
3120 (EXT3_BLOCKS_PER_GROUP(sb) - 1);
3121
3122 block_bitmap = ext4_block_bitmap(sb, gdp);
3123 if (block_bitmap < first_block || block_bitmap > last_block) {
3124 printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3125 "Block bitmap for group %u not in group "
3126 "(block %llu)!\n", i, block_bitmap);
3127 __brelse(bh);
3128 return 0;
3129 }
3130 inode_bitmap = ext4_inode_bitmap(sb, gdp);
3131 if (inode_bitmap < first_block || inode_bitmap > last_block) {
3132 printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3133 "Inode bitmap for group %u not in group "
3134 "(block %llu)!\n", i, inode_bitmap);
3135 __brelse(bh);
3136 return 0;
3137 }
3138 inode_table = ext4_inode_table(sb, gdp);
3139 if (inode_table < first_block ||
3140 inode_table + sbi->s_itb_per_group - 1 > last_block) {
3141 printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3142 "Inode table for group %u not in group "
3143 "(block %llu)!\n", i, inode_table);
3144 __brelse(bh);
3145 return 0;
3146 }
3147
3148 if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
3149 printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3150 "Checksum for group %u failed (%u!=%u)\n",
3151 i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
3152 gdp)),
3153 le16_to_cpu(gdp->bg_checksum));
3154 if (!IsVcbReadOnly(Vcb)) {
3155 __brelse(bh);
3156 return 0;
3157 }
3158 }
3159
3160 if (!flexbg_flag)
3161 first_block += EXT4_BLOCKS_PER_GROUP(sb);
3162
3163 __brelse(bh);
3164 }
3165
3166 ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
3167 sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
3168 return 1;
3169 }
3170