📄 super.c
字号:
if (block > 0) block = sb->BlockMap[block]; // Select a block that has enough free space to insert the data for (I = 0; I != sb->Boot.TotalBlockCount; I++) { if (sb->Blocks[I].LargestSpace < len + FFS_SIZEOF_BLOCKALLOC) continue; if (best == -1) best = I; if (sb->Blocks[I].FreeSpace > sb->Blocks[best].FreeSpace) best = I; } /* If there is no space in the requested block or none was given use the best one. This should possibly try to reclaim the best if that would help */ if (block < 0 || sb->Blocks[block].LargestSpace < len + FFS_SIZEOF_BLOCKALLOC) block = best; // No block found if (block == -1) return -1; // Locate the block we are going to use info = &sb->Blocks[block]; for (writeblock = 0; info->FreeList[writeblock].Stop != 0; writeblock++) if (info->FreeList[writeblock].Stop - info->FreeList[writeblock].Start >= len) break; if (info->FreeList[writeblock].Stop == 0) return -1; // Look for a free allocation entry to use for (cur = 0; ; cur++) { offset = sb->EraseSize - FFS_SIZEOF_BLOCK - (cur + 1)*FFS_SIZEOF_BLOCKALLOC; if (offset <= 100) { printk("ffs2: Allocation list too long"); return -1; } // XX can be advoided if (ffs2_read(r,block,offset,FFS_SIZEOF_BLOCKALLOC) == 0) return -1; alloc = (struct ffs2_blockalloc *)r->p; // It is free.. if (isflagset(alloc->Status,FFS_ALLOC_SMASK,FFS_ALLOC_FREE) != 0) { // Make sure that this was not an abortive write if (alloc->Len == 0xFFFF && alloc->Offset[0] == 0xFF && alloc->Offset[1] == 0xFF && alloc->Offset[2] == 0xFF) break; } // End of the list if (isflagset(alloc->Status,FFS_ALLOC_EMASK,FFS_ALLOC_END) != 0) break; } // End of the list, allocate a new entry past the very end. if (isflagset(alloc->Status,FFS_ALLOC_EMASK,FFS_ALLOC_END) != 0) { __u8 newStatus; // Update the allocation table for (I = 0; info->FreeList[I].Stop != 0; I++) { if (info->FreeList[I].Stop == offset) break; } if (info->FreeList[I].Stop == 0) { printk("ffs2: Corrupted allocation list"); return -1; } // Rewrite the status bit on the last entry newStatus = alloc->Status & (~FFS_ALLOC_END); if (ffs2_write(r,block,offset,&newStatus,sizeof(newStatus)) != 0) return -1; cur++; offset = sb->EraseSize - FFS_SIZEOF_BLOCK - (cur + 1)*FFS_SIZEOF_BLOCKALLOC; info->FreeList[I].Stop = offset; } // Double check if (info->FreeList[writeblock].Stop - info->FreeList[writeblock].Start < len) { printk("ffs2: Logic error allocation new free block\n"); return -1; } if (ffs2_read(r,block,offset,FFS_SIZEOF_BLOCKALLOC) == 0) return -1; alloc = (struct ffs2_blockalloc *)r->p; // The region that is supposed to be FF isnt! if (alloc->Len != 0xFFFF || alloc->Offset[0] != 0xFF || alloc->Offset[1] != 0xFF || alloc->Offset[2] != 0xFF) { printk("ffs2: Block allocations corrupted\n"); return -1; } // Now write the offset and length bytes outalloc->Status = (alloc->Status & (~FFS_ALLOC_SMASK)) | FFS_ALLOC_ALLOCATED; outalloc->Len = len; outalloc->Offset[2] = (__u8)(info->FreeList[writeblock].Start >> 16); outalloc->Offset[1] = (__u8)(info->FreeList[writeblock].Start >> 8); outalloc->Offset[0] = (__u8)(info->FreeList[writeblock].Start); if (ffs2_write(r,block,offset + sizeof(outalloc->Status), outalloc->Offset,FFS_SIZEOF_BLOCKALLOC - sizeof(outalloc->Status)) != 0) return -1; if (ffs2_write(r,block,offset,&outalloc->Status,sizeof(outalloc->Status)) != 0) return -1; // Remove it from the free list offset = info->FreeList[writeblock].Start; info->FreeList[writeblock].Start += len; // Recalculate the available space. info->LargestSpace = 0; info->FreeSpace = 0; for (I = 0; info->FreeList[I].Stop != 0; I++) { if (info->FreeList[I].Stop - info->FreeList[I].Start > info->LargestSpace) info->LargestSpace = info->FreeList[I].Stop - info->FreeList[I].Start; info->FreeSpace += info->FreeList[I].Stop - info->FreeList[I].Start; } r->block = block; r->offset = offset; return (info->VirtualBlock << 16) + cur;} /*}}}*/// update_pointer - Update a pointer in a block /*{{{*/// ---------------------------------------------------------------------/* This does some small writes to update a single pointer to point to a new location. */#define FFS_PTR_SIBLING 2#define FFS_PTR_PRIMARY 6#define FFS_PTR_SECONDARY 10static int update_pointer(struct ffs_read *r,unsigned long from, unsigned long target,unsigned type){ struct ffs2_entry *extent = ffs2_find_entry(r,from); unsigned long block = r->block; unsigned long offset = r->offset; __u16 status; if (extent == 0) return -1; status = extent->Status; // First update the pointer if (ffs2_write(r,block,offset + type,(unsigned char *)&target,4) != 0) return -1; // Then the status if (type == FFS_PTR_PRIMARY) status = status & (~FFS_ENTRY_PRIMARY); if (type == FFS_PTR_SECONDARY) status = status & (~FFS_ENTRY_SECONDARY); if (type == FFS_PTR_SIBLING) status = status & (~FFS_ENTRY_SIBLING); if (ffs2_write(r,block,offset,(unsigned char *)&status,sizeof(status)) != 0) return -1; return 0;} /*}}}*/// ffs2_entry_add - Add a new entry to a directory /*{{{*/// ---------------------------------------------------------------------/* This adds a new entry to a directory. The steps are, 1 - Find allocation space 2 - Mark as allocated, write the data to it 3 - Update the directory pointer to point to the new allocation Flash space will be lost if there is a failure between 2 and 3. */int ffs2_entry_add(struct ffs_read *r,struct ffs2_entry *dir, struct ffs2_entry *new,unsigned long *loc){ unsigned long cur; unsigned long allocloc; int Primary = 0; int res; struct ffs2_blockalloc alloc; // The directory is empty, we need to add the new entry below the head. if (isFNULL(dir->PrimaryPtr) || (dir->Status & FFS_ENTRY_PRIMARY) == FFS_ENTRY_PRIMARY) { cur = r->location; Primary = 1; // XXX Perform block reclimation instead if (isFNULL(dir->PrimaryPtr) == 0) { return -1; } } else { struct ffs2_entry *extent; // Walk the directory and find the end point of the linked list cur = dir->PrimaryPtr; while (1) { extent = ffs2_find_entry(r,cur); if (extent == 0) return -1; // This should not happen. if (isflagset(extent->Status,FFS_ENTRY_TYPEMASK,FFS_ENTRY_TYPEEXTENT)) return -1; // Skip to the next one if (isFNULL(extent->SiblingPtr) == 0 && (extent->Status & FFS_ENTRY_SIBLING) != FFS_ENTRY_SIBLING) cur = extent->SiblingPtr; else break; } // XXX Perform block reclimation instead if (isFNULL(extent->SiblingPtr) == 0) { return -1; } } /* Cur is now the location that we will be linking too. If this is a new primary link then we choose a block at random, otherwise we try to get a new allocation in the same block */ if (Primary == 0) allocloc = find_free_alloc(r,&alloc,FFS_SIZEOF_ENTRY + new->VarStructLen + new->NameLen,cur >> 16); else allocloc = find_free_alloc(r,&alloc,FFS_SIZEOF_ENTRY + new->VarStructLen + new->NameLen,-1); if (allocloc == (unsigned long)-1) return -1; // Write the block (find_free_alloc resets r->block/r->offset) if (ffs2_write(r,r->block,r->offset,(unsigned char *)new,alloc.Len) != 0) return -1; // Update the directory entry if (Primary == 0) res = update_pointer(r,cur,allocloc,FFS_PTR_SIBLING); else res = update_pointer(r,cur,allocloc,FFS_PTR_PRIMARY); *loc = allocloc; return res;} /*}}}*/// ffs2_new_entry - Create an arbitary new entry /*{{{*/// ---------------------------------------------------------------------/* This goes through the process of creating a new sub entry to a directory. Type may either be a file or a directory */static int ffs2_new_entry(struct inode *dir,struct dentry *dentry, struct qstr *name,__u8 type){ struct inode *inode; struct ffs2_entry *entry; struct ffs2_entry *direntry; struct ffs_read r; unsigned char tmp[300]; unsigned long now = CURRENT_TIME; unsigned long cur; memset(&r,0,sizeof(r)); memset(tmp,0xFF,sizeof(tmp)); r.super = dir->i_sb; if (name->len >= sizeof(tmp) - sizeof(*entry)) return -ENAMETOOLONG; // Fill in the entry structure entry = (struct ffs2_entry *)tmp; entry->Status = type | (0xFFFF & (~FFS_ENTRY_TYPEMASK)); entry->Attrib = 0; entry->Time = (__u16)now; entry->Date = (__u16)(now >> 16); entry->VarStructLen = 0; entry->NameLen = name->len; memcpy(entry->Name,name->name,entry->NameLen); // Get the directory inode direntry = ffs2_find_entry(&r,dir->i_ino); if (direntry == 0) { ffs2_relse(&r); return -EIO; } // Append the entry if (ffs2_entry_add(&r,direntry,entry,&cur) != 0) { ffs2_relse(&r); return -EIO; } ffs2_relse(&r); if (dentry == 0) return 0; // Update the dentry cache if ((inode = iget(dir->i_sb,cur))==NULL) return -EACCES; d_instantiate(dentry,inode); return 0;} /*}}}*/// ffs2_new_extent - Create a new extent /*{{{*/// ---------------------------------------------------------------------/* This creates a new, unlinked extent. The caller must link the extent to something. */static int ffs2_new_extent(struct ffs_read *r,unsigned char *buf, unsigned long length,unsigned long *loc){ struct ffs2_fileinfo *entry; struct ffs2_blockalloc alloc; unsigned char tmp[300]; unsigned long now = CURRENT_TIME; unsigned long cur; memset(tmp,0xFF,sizeof(tmp)); // Fill in the entry structure entry = (struct ffs2_fileinfo *)tmp; entry->Status = FFS_ENTRY_TYPEEXTENT | (0xFFFF & (~FFS_ENTRY_TYPEMASK)); entry->Attrib = 0; entry->Time = (__u16)now; entry->Date = (__u16)(now >> 16); entry->VarStructLen = 0; entry->UncompressedExtentLen = length; entry->CompressedExtentLen = length; // Allocate the data block entry->ExtentPtr = find_free_alloc(r,&alloc,length,-1); if (entry->ExtentPtr == (unsigned long)-1 || ffs2_write(r,r->block,r->offset,buf,alloc.Len) != 0) return -1; entry->Status = entry->Status & (~FFS_ENTRY_SIBLING); /* Allocate the entry for the extent info in the same block as the data if possible */ cur = find_free_alloc(r,&alloc,FFS_SIZEOF_FILEINFO + entry->VarStructLen,entry->ExtentPtr >> 16); if (cur == (unsigned long)-1 || ffs2_write(r,r->block,r->offset,(unsigned char *)entry,alloc.Len) != 0) return -1; *loc = cur; return 0;} /*}}}*/// free_alloc - Set an allocation entry to be reclaimable /*{{{*/// ---------------------------------------------------------------------/* */static int free_alloc(struct ffs_read *r,unsigned long location){ struct ffs2_blockalloc *alloc; unsigned long length; __u8 status; unsigned long block = getFFS2_sb(r->super).BlockMap[location >> 16]; signed long offset = getFFS2_sb(r->super).EraseSize - FFS_SIZEOF_BLOCK; offset -= FFS_SIZEOF_BLOCKALLOC*((location & 0xFFFF) + 1); if (offset <= 0) return -1; // Fetch it.. if (ffs2_read(r,block,offset,FFS_SIZEOF_BLOCKALLOC) == 0) return -1; alloc = (struct ffs2_blockalloc *)r->p; // Make sure it is allocated if (isflagset(alloc->Status,FFS_ALLOC_SMASK,FFS_ALLOC_ALLOCATED) == 0) return -1; // Deallocate length = alloc->Len; status = (alloc->Status & (~FFS_ALLOC_SMASK)) | FFS_ALLOC_DEALLOCATED; if (ffs2_write(r,block,offset,&status,sizeof(status)) != 0) return -1; getFFS2_sb(r->super).Blocks[block].ReclaimableSpace += length; return 0;} /*}}}*/// ffs2_erase - Erase an arbitary entry /*{{{*/// ---------------------------------------------------------------------/* This does a very unsafe unlink operation. It goes over the linked list of extents and marks them all as erased. If this routine is interrupted the filesystem will have unreclaimable blocks but will still be consistent */int ffs2_erase(struct ffs_read *r,unsigned long loc,int isdir){ struct ffs2_blockalloc alloc; struct ffs2_entry *entry; unsigned long top; unsigned long oldloc; // Go along the linked list and destroy it. top = loc; while (loc != 0xFFFFFFFF) { unsigned long block; unsigned long offset; oldloc = loc; if (ffs2_find_blockalloc(r,loc,&alloc) != 0) break; entry = (struct ffs2_entry *)r->p; block = r->block; offset = r->offset; if (isFNULL(entry->SecondaryPtr) == 0 && (entry->Status & FFS_ENTRY_SECONDARY) != FFS_ENTRY_SECONDARY) { loc = entry->SecondaryPtr; } else { // Skip cur to the next one if (isdir == 0) { if (isFNULL(entry->PrimaryPtr) == 0 && (entry->Status & FFS_ENTRY_PRIMARY) != FFS_ENTRY_PRIMARY) loc = entry->PrimaryPtr; else loc = 0xFFFFFFFF; } else { if (isFNULL(entry->SiblingPtr) == 0 && (entry->Status & FFS_ENTRY_SIBLING) != FFS_ENTRY_SIBLING) loc = entry->SiblingPtr; else loc = 0xFFFFFFFF; } if (isflagset(entry->Status,FFS_ENTRY_TYPEMASK,FFS_ENTRY_TYPEEXTENT)) { // Purge the datablock if ((entry->Status & FFS_ENTRY_EXISTS) == FFS_ENTRY_EXISTS) free_alloc(r,entry->SiblingPtr); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -