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