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, &gt);
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(&gt);
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