23#include "fssk-ioctl.h"
28IRX_ID(
"fssk", PFS_MAJOR, PFS_MINOR);
38#define FSSK_MAX_PATH_LEVELS 64
39#define FSSK_MAX_PATH_SEG_LENGTH 256
41static int fsskEventFlagID;
42static int fsskThreadID;
43static char fsskPathBuffer[FSSK_MAX_PATH_LEVELS][FSSK_MAX_PATH_SEG_LENGTH];
44static int fsskVerbosityLevel = 2;
48#define IO_BUFFER_SIZE 256
49#define IO_BUFFER_SIZE_BYTES (IO_BUFFER_SIZE * 512)
52static u8 IOBuffer[IO_BUFFER_SIZE_BYTES];
54static void fsskPrintPWD(
void)
59 for (i = 0, pName = fsskPathBuffer[0]; (u32)i <
fsskRuntimeData.status.PWDLevel; i++, pName += FSSK_MAX_PATH_SEG_LENGTH) {
75 cinode = pfsCacheUsedAdd(clink);
77 for (i = 0; i < clink->u.inode->number_data; i++) {
79 if (pfsFixIndex(i) == 0) {
80 if ((cinode = pfsBlockGetNextSegment(cinode, &result)) == NULL) {
86 if (clink->pfsMount->num_subs -
fsskRuntimeData.status.partsDeleted < cinode->u.inode->data[pfsFixIndex(i)].subpart) {
92 fsskRuntimeData.status.inodeBlockCount += clink->u.inode->number_blocks;
98static int fsskCalculateSpaceToRemove(
pfs_mount_t *mount)
100 u32 PartsToRemove, i, ratio, SizeOfSub, SizeOfSubZones, free, zfree, total_zones;
103 zfree = mount->zfree;
104 total_zones = mount->total_zones;
105 for (i = mount->num_subs; i != 0; i--, PartsToRemove++) {
106 SizeOfSub = mount->blockDev->getSize(mount->fd, i);
107 SizeOfSubZones = SizeOfSub >> mount->sector_scale;
108 total_zones -= SizeOfSubZones;
109 free = SizeOfSubZones - mount->free_zone[i] - pfsGetBitmapSizeBlocks(mount->sector_scale, SizeOfSub) - 1;
110 if (zfree >= mount->free_zone[i]) {
111 zfree -= mount->free_zone[i];
114 ratio = (int)((u64)zfree * 100 / total_zones);
115 PFS_PRINTF(
"free ratio=%ld, freezone=%ld.\n", ratio, zfree);
127 PFS_PRINTF(
"%ld partitions will be removed.\n", PartsToRemove);
129 return PartsToRemove;
134 u32 *zfree, MaxFreeRatio, FreeRatio;
137 for (result = sub = 0, zfree = mount->free_zone, MaxFreeRatio = 0; mount->num_subs - (
fsskRuntimeData.status.partsDeleted - 1) != 0; sub++, zfree++) {
138 FreeRatio = ((u64)*zfree) * 100 / (mount->blockDev->getSize(mount->fd, sub) >> mount->sector_scale);
139 if (MaxFreeRatio < FreeRatio) {
140 MaxFreeRatio = FreeRatio;
152 for (i = 0; i < length; i++) {
155 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, block2->subpart, (block2->number + i) << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ)) < 0 || ((result = mount->blockDev->transfer(mount->fd, IOBuffer, block1->subpart, (block1->number + i) << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_WRITE)) < 0)) {
170 if (!pfsCacheIsFull()) {
171 block.subpart = data->subpart;
172 block.number = data->number + data->count;
173 if ((*result = pfsBitmapSearchFreeZone(clink->pfsMount, &block, clink->u.inode->number_blocks)) >= 0) {
174 clinkfree = pfsCacheGetData(clink->pfsMount, block.subpart, block.number << clink->pfsMount->inode_scale, PFS_CACHE_FLAG_SEGI | PFS_CACHE_FLAG_NOLOAD, result);
176 memset(clinkfree->u.inode, 0,
sizeof(
pfs_inode_t));
177 clinkfree->u.inode->magic = PFS_SEGI_MAGIC;
178 memcpy(&clinkfree->u.inode->inode_block, &clink->u.inode->inode_block,
sizeof(
pfs_blockinfo_t));
179 memcpy(&clinkfree->u.inode->last_segment, &clink2->u.inode->data[0],
sizeof(
pfs_blockinfo_t));
181 clinkfree->flags |= PFS_CACHE_FLAG_DIRTY;
182 clink->u.inode->number_blocks += block.count;
183 clink->u.inode->number_data++;
184 memcpy(&clink->u.inode->last_segment, &block,
sizeof(
pfs_blockinfo_t));
185 clink->u.inode->number_segdesg++;
186 clink->flags |= PFS_CACHE_FLAG_DIRTY;
187 memcpy(&clink2->u.inode->next_segment, &block,
sizeof(
pfs_blockinfo_t));
188 clink2->flags |= PFS_CACHE_FLAG_DIRTY;
189 pfsCacheFree(clink2);
207 num = pfsMount->num_subs - deleted;
208 if (bi->subpart < num) {
211 if (bi->number != 0) {
214 count = (max_count < 33) ? max_count : 32;
219 for (--num; num >= 0; num--) {
220 for (i =
count; i != 0; i /= 2) {
221 if ((pfsMount->free_zone[bi->subpart] >= i) && (pfsBitmapAllocZones(pfsMount, bi, i) != 0)) {
222 pfsMount->free_zone[bi->subpart] -= bi->count;
223 pfsMount->zfree -= bi->count;
230 if (pfsMount->num_subs - deleted == bi->subpart) {
245 printf(
"\t========== Move");
246 if (FIO_S_ISDIR(start->u.inode->mode)) {
247 block.subpart = fsskCalcLastSub(mount);
254 if ((result = fsckBitmapSearchFreeZoneSpecial(mount, &block, start->u.inode->number_blocks,
fsskRuntimeData.status.partsDeleted)) >= 0) {
255 if ((result = fsskCopyBlock(mount, &block, &start->u.inode->inode_block, 1)) >= 0 &&
256 (clink = pfsCacheGetData(mount, block.subpart, block.number << mount->inode_scale, PFS_CACHE_FLAG_SEGD | PFS_CACHE_FLAG_NOLOAD, &result)) != NULL) {
259 memcpy(clink->u.inode, start->u.inode,
sizeof(
pfs_inode_t));
261 memcpy(&clink->u.inode->last_segment, &block,
sizeof(
pfs_blockinfo_t));
263 clink->u.inode->number_segdesg = 1;
264 clink->u.inode->number_data = 1;
265 clink->u.inode->number_blocks = 1;
266 clink2 = pfsCacheUsedAdd(start);
267 clink3 = pfsCacheUsedAdd(clink);
269 for (i = 1; (u32)i < start->u.inode->number_data && result == 0; i++) {
270 if (pfsFixIndex(i) == 0) {
271 if ((clink2 = pfsBlockGetNextSegment(clink2, &result)) == NULL) {
275 memcpy(&block2, &clink2->u.inode->data[pfsFixIndex(i)],
sizeof(
pfs_blockinfo_t));
276 if (pfsFixIndex(clink->u.inode->number_data - 1) != 0) {
278 if ((value = pfsBitmapAllocateAdditionalZones(mount, clink3->u.inode->data, block2.count)) != 0) {
279 block.subpart = clink3->u.inode->data[0].subpart;
280 block.number = clink3->u.inode->data[0].number + clink3->u.inode->data[0].count;
281 clink3->u.inode->data[0].count += value;
283 if ((result = fsskCopyBlock(mount, &block, &block2, value)) < 0) {
287 clink->u.inode->number_blocks += value;
288 block2.number += value;
289 block2.count -= value;
292 while (block2.count != 0) {
293 if (pfsFixIndex(clink->u.inode->number_data) == 0) {
294 if ((clink3 = fsskCreateIndirectSeg(clink, clink3, clink3->u.inode->data, &result)) == NULL) {
299 block.subpart = clink3->u.inode->data[0].subpart;
300 block.count = block2.count;
301 block.number = clink3->u.inode->data[0].number + clink3->u.inode->data[0].count;
303 if ((result = fsckBitmapSearchFreeZoneSpecial(mount, &block, start->u.inode->number_blocks,
fsskRuntimeData.status.partsDeleted)) < 0) {
307 memcpy(&clink3->u.inode->data[pfsFixIndex(start->u.inode->number_data)], &block,
sizeof(
pfs_blockinfo_t));
309 clink->u.inode->number_data++;
310 if ((result = fsskCopyBlock(mount, &block, &block2, block.count)) < 0) {
314 clink->u.inode->number_blocks += block.count;
315 block2.number += block.count;
316 block2.count -= block.count;
323 pfsCacheFree(clink2);
325 dentry->sub = clink->u.inode->inode_block.subpart;
326 dentry->inode = clink->u.inode->inode_block.number;
327 clink3->flags |= PFS_CACHE_FLAG_DIRTY;
328 clink->flags |= PFS_CACHE_FLAG_DIRTY;
329 pfsCacheFree(clink3);
331 pfsBitmapFreeInodeBlocks(start);
333 pfsBitmapFreeInodeBlocks(clink);
334 pfsCacheFree(clink3);
338 pfsBitmapFreeBlockSegment(mount, &block);
346 if ((SelfInodeClink->sub != dentry->sub) || (SelfInodeClink->u.inode->inode_block.number != dentry->inode)) {
347 PFS_PRINTF(
"'.' point not itself.\n");
348 dentry->sub = SelfInodeClink->u.inode->inode_block.subpart;
349 dentry->inode = SelfInodeClink->u.inode->inode_block.number;
350 SelfDEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
356 if ((ParentInodeClink->sub != dentry->sub) || (ParentInodeClink->u.inode->inode_block.number != dentry->inode)) {
357 PFS_PRINTF(
"'..' point not parent.\n");
358 dentry->sub = ParentInodeClink->u.inode->inode_block.subpart;
359 dentry->inode = ParentInodeClink->u.inode->inode_block.number;
360 SelfDEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
371 if ((FileInodeDataClink = pfsInodeGetData(InodeClink->pfsMount, dentry->sub, dentry->inode, &result)) != NULL) {
373 memset(fsskPathBuffer[
fsskRuntimeData.status.PWDLevel], 0, FSSK_MAX_PATH_SEG_LENGTH);
374 strncpy(fsskPathBuffer[
fsskRuntimeData.status.PWDLevel], dentry->path, dentry->pLen);
377 if (fsskVerbosityLevel >= 2) {
379 if (FIO_S_ISDIR(dentry->aLen)) {
384 if ((result = fsskHasSpaceToFree(FileInodeDataClink)) > 0) {
385 if ((result = fsskMoveInode(InodeClink->pfsMount, InodeClink, FileInodeDataClink, dentry)) == 0) {
386 DEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
387 pfsCacheFree(FileInodeDataClink);
388 FileInodeDataClink = pfsInodeGetData(InodeClink->pfsMount, dentry->inode, dentry->sub, &result);
395 if (FIO_S_ISDIR(dentry->aLen)) {
397 result = fsskCheckFiles(InodeClink, FileInodeDataClink);
405 PFS_PRINTF(
"error: exceed max directory depth.\n");
418 u32 inodeOffset, dEntrySize;
421 if (CheckThreadStack() < 128) {
422 PFS_PRINTF(
"error: there is no stack, giving up.\n");
427 BlockPosition.inode = pfsCacheUsedAdd(InodeClink);
428 BlockPosition.block_segment = 1;
429 BlockPosition.block_offset = 0;
430 BlockPosition.byte_offset = 0;
431 if ((DEntryClink = pfsGetDentriesChunk(&BlockPosition, &result)) == NULL) {
432 pfsCacheFree(BlockPosition.inode);
435 pDEntry = DEntryClink->u.dentry;
437 while (inodeOffset < InodeClink->u.inode->size) {
438 if (pDEntry >= (
pfs_dentry_t *)(DEntryClink->u.data + 1024)) {
439 pfsCacheFree(DEntryClink);
440 if ((result = pfsInodeSync(&BlockPosition, 1024, InodeClink->u.inode->number_data)) != 0 || (DEntryClink = pfsGetDentriesChunk(&BlockPosition, &result)) == NULL) {
445 for (pDEntry = DEntryClink->u.dentry, pDEntryEnd = DEntryClink->u.dentry + 1; pDEntry < pDEntryEnd; pDEntry = (
pfs_dentry_t *)((u8 *)pDEntry + dEntrySize), inodeOffset += dEntrySize) {
450 dEntrySize = pDEntry->aLen & 0x0FFF;
452 if (dEntrySize & 3) {
453 PFS_PRINTF(
"error: directory entry is not aligned.\n");
458 if (dEntrySize < (u32)((pDEntry->pLen + 11) & ~3)) {
459 PFS_PRINTF(
"error: directory entry is too small.\n");
464 if (pDEntryEnd < (
pfs_dentry_t *)((u8 *)pDEntry + dEntrySize)) {
465 PFS_PRINTF(
"error: directory entry is too long.\n");
470 if (pDEntry->inode != 0) {
471 if ((pDEntry->pLen == 1) && (pDEntry->path[0] ==
'.')) {
472 fsskCheckSelfEntry(InodeClink, DEntryClink, pDEntry);
473 }
else if ((pDEntry->pLen == 2) && (pDEntry->path[0] ==
'.')) {
474 fsskCheckParentEntry(ParentInodeClink, DEntryClink, pDEntry);
476 if ((result = fsskCheckFile(InodeClink, DEntryClink, pDEntry)) < 0) {
489 pfsCacheFree(DEntryClink);
490 pfsCacheFree(BlockPosition.inode);
501 if ((
fsskRuntimeData.status.partsDeleted = fsskCalculateSpaceToRemove(mount)) != 0) {
502 if ((clink = pfsInodeGetData(mount, mount->root_dir.subpart, mount->root_dir.number, &result)) != NULL) {
503 if ((result = fsskHasSpaceToFree(clink)) > 0) {
504 PFS_PRINTF(
"root directory will be moved.\n");
505 if ((result = fsskMoveInode(mount, clink, clink, &dentry)) == 0) {
507 if ((clink = pfsInodeGetData(mount, dentry.sub, dentry.inode, &result)) != NULL) {
508 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ)) == 0) {
509 mount->root_dir.subpart = dentry.sub;
510 mount->root_dir.number = dentry.inode;
512 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_BACKUP_SECTOR, 1, PFS_IO_MODE_WRITE)) == 0) {
513 result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE);
515 mount->blockDev->flushCache(mount->fd);
523 result = fsskCheckFiles(clink, clink);
525 pfsCacheFlushAllDirty(mount);
528 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ)) == 0) {
531 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_BACKUP_SECTOR, 1, PFS_IO_MODE_WRITE)) == 0) {
532 result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE);
535 mount->blockDev->flushCache(mount->fd);
538 for (i = 0; (u32)i <
fsskRuntimeData.status.partsDeleted && result == 0; i++) {
539 iomanX_ioctl2(mount->fd, HIOCDELSUB, NULL, 0, NULL, 0);
552 PFS_PRINTF(
"error: cannot read root directory.\n");
557 PFS_PRINTF(
"error: there is no space to remove.\n");
562 SetEventFlag(fsskEventFlagID, 1);
573 fsskVerbosityLevel = (mode & 0xF0) >> 4;
575 if (MainPFSMount.fd) {
579 if ((result = iomanX_getstat(name, &StatData)) < 0) {
580 PFS_PRINTF(
"error: could not get status.\n");
584 if (StatData.mode != APA_TYPE_PFS) {
585 PFS_PRINTF(
"error: not PFS.\n");
589 if ((pblockDevData = pfsGetBlockDeviceTable(name)) == NULL)
592 if ((blockfd = iomanX_open(name, O_RDWR)) < 0) {
593 PFS_PRINTF(
"error: cannot open.\n");
597 memset(&MainPFSMount, 0,
sizeof(MainPFSMount));
598 MainPFSMount.fd = blockfd;
599 MainPFSMount.blockDev = pblockDevData;
601 if (pfsMountSuperBlock(&MainPFSMount) >= 0) {
604 fsskRuntimeData.status.zoneUsed = MainPFSMount.total_zones - MainPFSMount.zfree;
606 fd->privdata = &MainPFSMount;
610 PFS_PRINTF(
"error: cannot continue.\n");
629 fsskRuntimeData.status.partsDeleted = fsskCalculateSpaceToRemove(mount);
631 if (mount->num_subs -
fsskRuntimeData.status.partsDeleted < mount->num_subs) {
633 for (i = mount->num_subs; i != 0; i--) {
634 result += mount->blockDev->getSize(mount->fd, i);
641static int fsskGetEstimatedTime(
pfs_mount_t *mount,
int *result)
649 for (i = 0; i < 4; i++) {
650 GetSystemTime(&SysClock1);
651 mount->blockDev->transfer(mount->fd, IOBuffer, 0, 1 << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ);
652 GetSystemTime(&SysClock2);
654 SysClockDiff.lo = SysClock2.lo - SysClock1.lo;
655 SysClockDiff.hi = SysClock2.hi - SysClock1.hi - (SysClock2.lo < SysClock1.lo);
656 SysClock2USec(&SysClockDiff, &sec, &usec);
658 PFS_PRINTF(
"%ld system clocks = %ld.%06ld sec\n", SysClockDiff.lo, sec, usec);
664 if ((*result = ((clock + 400) *
fsskRuntimeData.status.zoneUsed / 1000000)) == 0)
670static int FsskIoctl2(
iomanX_iop_file_t *fd,
int cmd,
void *arg,
unsigned int arglen,
void *buf,
unsigned int buflen)
679 case FSSK_IOCTL2_CMD_GET_ESTIMATE:
680 result = fsskGetEstimatedTime(fd->privdata, buf);
682 case FSSK_IOCTL2_CMD_START:
683 result = StartThread(fsskThreadID, fd->privdata);
685 case FSSK_IOCTL2_CMD_WAIT:
686 result = WaitEventFlag(fsskEventFlagID, 1, WEF_OR | WEF_CLEAR, &FlagBits);
688 case FSSK_IOCTL2_CMD_POLL:
689 result = PollEventFlag(fsskEventFlagID, 1, WEF_OR | WEF_CLEAR, &FlagBits);
690 if (result == KE_EVF_COND) {
694 case FSSK_IOCTL2_CMD_GET_STATUS:
698 case FSSK_IOCTL2_CMD_STOP:
702 case FSSK_IOCTL2_CMD_SET_MINFREE:
703 if (*(
int *)arg >= 4)
707 case FSSK_IOCTL2_CMD_SIM:
708 result = fsskSimGetStat(fd->privdata);
717IOMANX_RETURN_VALUE_IMPL(0);
720 IOMANX_RETURN_VALUE(0),
721 IOMANX_RETURN_VALUE(0),
722 IOMANX_RETURN_VALUE(0),
725 IOMANX_RETURN_VALUE(0),
726 IOMANX_RETURN_VALUE(0),
727 IOMANX_RETURN_VALUE(0),
728 IOMANX_RETURN_VALUE(0),
729 IOMANX_RETURN_VALUE(0),
730 IOMANX_RETURN_VALUE(0),
731 IOMANX_RETURN_VALUE(0),
732 IOMANX_RETURN_VALUE(0),
733 IOMANX_RETURN_VALUE(0),
734 IOMANX_RETURN_VALUE(0),
735 IOMANX_RETURN_VALUE(0),
736 IOMANX_RETURN_VALUE(0),
737 IOMANX_RETURN_VALUE(0),
738 IOMANX_RETURN_VALUE(0),
739 IOMANX_RETURN_VALUE(0),
740 IOMANX_RETURN_VALUE(0),
741 IOMANX_RETURN_VALUE(0),
742 IOMANX_RETURN_VALUE_S64(0),
743 IOMANX_RETURN_VALUE(0),
744 IOMANX_RETURN_VALUE(0),
745 IOMANX_RETURN_VALUE(0),
756static int DisplayUsageHelp(
void)
758 PFS_PRINTF(
"error: Usage: fssk [-n <num>]\n");
759 return MODULE_NO_RESIDENT_END;
762int PFS_ENTRYPOINT(
int argc,
char **argv)
767 for (argc--, argv++; argc > 0 && ((*argv)[0] ==
'-'); argc--, argv++) {
768 if (!strcmp(
"-n", *argv)) {
771 if (strtol(*argv, NULL, 10) < buffers) {
772 buffers = strtol(*argv, NULL, 10);
775 return DisplayUsageHelp();
778 return DisplayUsageHelp();
782 PFS_PRINTF(
"max depth %d, %d buffers.\n", FSSK_MAX_PATH_LEVELS - 1, buffers);
784 if (pfsCacheInit(buffers, 1024) < 0) {
785 PFS_PRINTF(
"error: cache initialization failed.\n");
786 return MODULE_NO_RESIDENT_END;
789 if ((fsskEventFlagID = fsskCreateEventFlag()) < 0) {
790 return MODULE_NO_RESIDENT_END;
793 if ((fsskThreadID = fsskCreateThread((
void *)&FsskThread, 0x2080)) < 0) {
794 return MODULE_NO_RESIDENT_END;
797 iomanX_DelDrv(FsskDevice.name);
798 if (iomanX_AddDrv(&FsskDevice) == 0) {
799 PFS_PRINTF(
"version %04x driver start.\n", IRX_VER(PFS_MAJOR, PFS_MINOR));
800 return MODULE_RESIDENT_END;
803 return MODULE_NO_RESIDENT_END;
u32 count
start sector of fragmented bd/file